我正在做一个带有顺序和并行实现的线性代数的小例子。以下是当前代码:
import util.Random
import System.currentTimeMillis
import actors.Futures._
import Numeric.Implicits._
object Parallel extends App{
val rnd = new Random(1337)//Seeded RNG
//Create 2 matrices with dimension NxN
val N = 550
val A:Array[Array[Double]] = Array.fill(N,N){ rnd.nextDouble }
val B:Array[Array[Double]] = Array.fill(N,N){ rnd.nextDouble }
//Time a call-by-name block and return milli-seconds
def time(b: => Unit):Long = {
val start = currentTimeMillis
b
currentTimeMillis-start
}
val sequentialProgram = new LinearAlgebra with SequentialLinearAlgebra {
println("Sequential time: "+time { A * B } )
}
val parColProgram = new LinearAlgebra with ParColLinearAlgebra {
println("ParCol time: "+time { A * B } )
}
val futureProgram = new LinearAlgebra with FutureLinearAlgebra {
println("Future time: "+time { A * B } )
}
}
//Interface, knows nothing about implementation
trait LinearAlgebra{
type Vector[T] = Array[T]
type Matrix[T] = Vector[Vector[T]]
implicit class VectorOps[T:Numeric](v:Vector[T]){
def dot(that:Vector[T]):T = innerProd(v,that)
}
implicit class MatrixOps[T:Numeric](m:Matrix[T]){
def *(that:Matrix[T]):Matrix[T] = matMul(m,that)
}
//Functionality is deferred to implementing traits
def innerProd[T:Numeric](a:Vector[T],b:Vector[T]):T
def matMul[T:Numeric](A:Matrix[T],B:Matrix[T]):Matrix[T]
}
//Implements LinearAlgebra interface in a sequential fashion
trait SequentialLinearAlgebra extends LinearAlgebra {
def innerProd[T:Numeric](a:Vector[T],b:Vector[T]) =
((a,b).zipped map (_*_)).sum
def matMul[T:Numeric](A:Matrix[T],B:Matrix[T]) = {
val Bt = B.transpose
A.map(row => Bt.map(col => row dot col))
}
}
//Implements LinearAlgebra interface using parallel collections
trait ParColLinearAlgebra extends LinearAlgebra {
def innerProd[T:Numeric](a:Vector[T],b:Vector[T]) =
((a,b).zipped map (_*_)).sum
def matMul[T:Numeric](A:Matrix[T],B:Matrix[T]) = {
val Bt = B.transpose
(A.par map (row => Bt map (col => row dot col))).toArray
}
}
//Implements LinearAlgebra interface using futures, i.e. explicit workload distribution
trait FutureLinearAlgebra extends LinearAlgebra {
def innerProd[T:Numeric](a:Vector[T],b:Vector[T]) =
((a,b).zipped map (_*_)).sum
def matMul[T:Numeric](A:Matrix[T],B:Matrix[T]) = {
val Bt = B.transpose
val res = A map ( row => future {Bt map (col => row dot col)})
res.map(_.apply)
}
}
代码对我来说似乎是正确的,但我收到以下错误:
fsc Parallel.scala
/home/felix/Documents/teaching/2014/dm509/scala/Parallel.scala:61: error: type mismatch;
found : Array[scala.collection.mutable.ArraySeq[T]]
required: SequentialLinearAlgebra.this.Matrix[T]
(which expands to) Array[Array[T]]
A.map(row => Bt.map(col => row dot col))
^
/home/felix/Documents/teaching/2014/dm509/scala/Parallel.scala:71: error: type mismatch;
found : Array[scala.collection.mutable.ArraySeq[T]]
required: ParColLinearAlgebra.this.Matrix[T]
(which expands to) Array[Array[T]]
(A.par map (row => Bt map (col => row dot col))).toArray
^
/home/felix/Documents/teaching/2014/dm509/scala/Parallel.scala:82: error: type mismatch;
found : Array[scala.collection.mutable.ArraySeq[T]]
required: FutureLinearAlgebra.this.Matrix[T]
(which expands to) Array[Array[T]]
res.map(_.apply)
^
three errors found
问题似乎是Array.map
有时会返回ArraySeq
,与预期的Array
相反。如果我使用Array和List进行搜索替换,程序将按预期工作。迁移到Array的原因是我希望将效率与命令式实现进行比较,即我需要有效的随机访问。
有人可以解释这种行为吗?
答案 0 :(得分:3)
上下文界限有所不同:
scala> val as = Array.tabulate(10,10)((x,y)=>y)
as: Array[Array[Int]] = Array(Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
scala> as map (x => x.sum)
res0: Array[Int] = Array(45, 45, 45, 45, 45, 45, 45, 45, 45, 45)
scala> def f[A: Numeric](as: Array[Array[A]]) = as map (x => x.sum)
f: [A](as: Array[Array[A]])(implicit evidence$1: Numeric[A])scala.collection.mutable.ArraySeq[A]
scala> def f[A](as: Array[Array[A]]) = as map (x => 42)
f: [A](as: Array[Array[A]])Array[Int]
据推测,它会使用产生CanBuildFrom
的后备Seq
。
修改:要修复它,请提供reflect.ClassTag[T]
,以便它可以创建您想要的Array[T]
。
你需要它:
def matMul[T:Numeric](A:Matrix[T],B:Matrix[T])(implicit ev1: ClassTag[T])
和
implicit class MatrixOps[T:Numeric](m:Matrix[T])(implicit ev1: ClassTag[T])