Array.map返回ArraySeq?

时间:2014-03-10 12:16:09

标签: scala parallel-processing linear-algebra dsl

我正在做一个带有顺序和并行实现的线性代数的小例子。以下是当前代码:

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的原因是我希望将效率与命令式实现进行比较,即我需要有效的随机访问。 有人可以解释这种行为吗?

1 个答案:

答案 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])