Reputation: 63062
Consider the following (working) snippet that defines bidirectional implicit conversions between the DenseVector and Arrays:
import scala.reflect.ClassTag
import org.apache.spark.mllib.linalg.Vectors
import breeze.linalg.{DenseVector => BDV}
implicit def bdvToSeq[T](vect: BDV[T])(implicit ct: ClassTag[T]): Seq[T] = vect.toArray.toSeq
implicit def arrayToVect(darr: Array[Double]): BDV[Double]
= new BDV(darr)
implicit def bdvToArray[T](vect: BDV[T])(implicit ct: ClassTag[T]): Array[T] = vect.toArray
def add(v1: BDV[Double], v2: BDV[Double]) =
v1.zip(v2).map { x => x._1 + x._2}
Let's try it out:
scala> arr.allVisitableIndicesActive // Array to DenseVector implicit conversion
res4: Boolean = true
scala> val d = new BDV(Array(77.7, 88.8, 99.9))
d: breeze.linalg.DenseVector[Double] = DenseVector(77.7, 88.8, 99.9)
Now the other direction:
scala> def myArrMethod(arr: Array[Double]) = println(arr.mkString(","))
myArrMethod: (arr: Array[Double])Unit
scala> myArrMethod(d) // DenseVector to array conversion
77.7,88.8,99.9
The following also works: notice the darr.toSeq
def norm(darr: Array[Double]): Double = {
Math.sqrt(darr.toSeq.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)})
}
However if we omit the .toSeq then we have implicits collision:
scala> def norm(darr: Array[Double]): Double = {
Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)})
}
<console>:34: error: type mismatch;
found : darr.type (with underlying type Array[Double])
required: ?{def foldLeft(x$1: ? >: Double(0.0)): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method doubleArrayOps in object Predef of type (xs: Array[Double])scala.collection.mutable.ArrayOps[Double]
and method arrayToVect of type (darr: Array[Double])breeze.linalg.DenseVector[Double]
are possible conversion functions from darr.type to ?{def foldLeft(x$1: ? >: Double(0.0)): ?}
Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)})
^
<console>:34: error: value foldLeft is not a member of Array[Double]
Math.sqrt(darr.foldLeft(0.0) { case (sum, dval) => sum + Math.pow(dval, 2)})
I would however prefer not to put the ".toSeq" explicitly.
So my question is: how to set the proper precedence so that the Predef.toSeq is the clear winner - always tried before the custom lower priority implicits defined above?
Upvotes: 0
Views: 245
Reputation: 9734
You can extract all your implicit conversions into object, and import them only where needed
trait BDVImplicits {
implicit def bdvToSeq[T](vect: BDV[T])(implicit ct: ClassTag[T]): Seq[T] =
vect.toArray.toSeq
implicit def arrayToVect(darr: Array[Double]): BDV[Double] =
new BDV(darr)
implicit def bdvToArray[T](vect: BDV[T])(implicit ct: ClassTag[T]): Array[T] =
vect.toArray
}
object BDVImplicits extends BDVImplicits
If you'll place your 'norm' method in Utils for example, and don't import implicit you'll be good. You'll just need to import BDVImplicits._ in class where you call your Util methods.
I think it's simplest workaround for this problem.
Upvotes: 1