【问题标题】:Generic Breeze Vector method通用微风向量法
【发布时间】:2015-11-02 08:32:03
【问题描述】:

我正在尝试实现一个通用的 Scala 方法,该方法处理类型为 Float 或 Double 的 Breeze 向量(至少,特异性较低)。 下面是 Vector[Double] 的一个简单示例:

def vectorSum(vectors: Seq[Vector[Double]]): Vector[Double] = {
  vectors.reduce { (v1, v2) => v1 :+ v2 }
}

我对 Scala 和 Breeze 有点陌生,所以我将这个通用化的天真方法是:

def vectorSumGeneric[T <: AnyVal](vectors: Seq[Vector[T]]): Vector[T] = {
  vectors.reduce { (v1, v2) => v1 :+ v2 }
}

但是,这会引发以下编译错误:

  • diverging implicit expansion for type breeze.linalg.operators.OpAdd.Impl2[breeze.linalg.Vector[T],breeze.linalg.Vector[T],That] starting with method v_v_Idempotent_OpAdd in trait VectorOps
  • not enough arguments for method :+: (implicit op: breeze.linalg.operators.OpAdd.Impl2[breeze.linalg.Vector[T],breeze.linalg.Vector[T],That])That. Unspecified value parameter op.

我尝试了一些变体,包括T &lt;% AnyValT &lt;% Double,但它们也不起作用(可能正如预期的那样)。 Scala 文档类型边界没有给我关于这样的用例的线索。 解决这个问题的正确方法是什么?

【问题讨论】:

    标签: scala generics vector scala-breeze


    【解决方案1】:

    问题在于类型参数T 可以是任何值,但您必须确保您的类型T 至少支持作为代数运算的加法。如果T 是一个半环,那么您可以添加两个T 类型的元素。您可以通过指定上下文绑定将T 强制为半环:

    def vectorSum[T: Semiring](vectors: Seq[Vector[T]]): Vector[T] = {
      vectors.reduce(_ + _)
    }
    

    这样你就可以强制每个T 的实例化你的范围内还有一个Semiring[T] 来定义加法操作。 Breeze 已经为所有支持加法的原始类型定义了这个结构。

    如果您想支持更多的代数运算,例如除法,那么您应该将您的类型变量约束为具有Field 上下文绑定。

    def vectorDiv[T: Field](vectors: Seq[Vector[T]]): Vector[T] = {
      vectors.reduce(_ / _)
    }
    

    如果您想支持向量上的通用元素二元运算:

    def vectorBinaryOp[T](
        vectors: Seq[Vector[T]], op: (T, T) => T)(
        implicit canZipMapValues: CanZipMapValues[Vector[T], T, T, Vector[T]])
      : Vector[T] = {
      vectors.reduce{
        (left, right) => implicitly[CanZipMapValues[Vector[T], T, T, Vector[T]]].map(left, right, op)
      }
    }
    

    然后你可以在向量上定义任意二元运算:

    val vectors = Seq(DenseVector(1.0,2.0,3.0,4.0), DenseVector(2.0,3.0,4.0,5.0))
    val result = VectorSum.vectorBinaryOp(vectors, (a: Double, b: Double) => (a / b))
    

    【讨论】:

    • 这适用于给定的示例,谢谢!我不知道 Breeze 提供了一个 Semiring 类。但是,我也想用不同的操作实现类似的方法,例如按元素划分。 Semiring 不支持此功能,因此再次失败。有没有更通用的方法来解决这个问题?我想应该为所有向量定义相同的向量操作。
    • 然后你应该限制类型参数有一个Field 上下文绑定。我相应地更新了我的答案。
    • 如果你想在Vectors上有一个通用的二进制操作函数你可以使用CanZipMapValues。我已将其添加到我的答案中。
    • 我实际上希望有一个更直接的解决方案,但感谢您的解决方案!
    • 一开始,Breeze 的架构包含所有这些隐式功能,使用起来似乎很麻烦,但它确实为您提供了很大的灵活性,并允许您使用新操作轻松扩展系统。
    猜你喜欢
    • 1970-01-01
    • 2014-09-15
    • 2013-08-22
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 2013-09-01
    相关资源
    最近更新 更多