score:2

Accepted answer

The problem is that the type parameter T can be anything, but you have to make sure that your type T supports at least addition as an algebraic operation. If T is a semiring, then you can add two elements of type T. You can enforce T to be a semiring by specifying a context bound:

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

That way you enforce that for every instantiation of T you also have a Semiring[T] in your scope which defines the addition operation. Breeze already defines this structure for all primitive types which support addition.

If you want to support more algebraic operations such as division, then you should constrain your type variable to have a Field context bound.

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

If you want to support general purpose element-wise binary operations on vectors:

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)
  }
}

Then you can define arbitrary binary operations on vectors:

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))

Related Query

More Query from same tag