Scala неявный ClassManifest[T] является нулевым в Array.fill(..)
Я начал возиться с дженериками в Scala, и это непростое печенье. Моя идея состоит в том, чтобы выучить его, написав общий матричный класс для использования в моем проекте параллельных вычислений.
Однако у меня возникают проблемы с использованием Array.fill() при создании новой матрицы. Вот мой код для Матрицы:
(остерегайтесь кирпичной стены)
package dm8xx.matrix.immutable
import scala.util.Random
/*
* Bring your sunglasses...
*/
object Matrix {
def apply[T](m: Int, n: Int, v: T )(implicit nn:Numeric[T],mm:ClassManifest[T]): Matrix[T] = {
println("making new mat")
println(mm)
new Matrix[T](Array.fill(m,n)(v))
}
def apply[T: Numeric](m: Int, n: Int): Matrix[T] = Matrix(m, n)
def apply(m: Int, n: Int, r: Random): Matrix[Double] =
new Matrix(Array.fill[Double](m, n) { Math.floor(r.nextDouble() * 100) })
}
class Matrix[T: Numeric](val data: Array[Array[T]]) {
val num = implicitly[Numeric[T]]
implicit val cm: ClassManifest[T] = implicitly
val m = data.size
val n = data(0).size
def apply(i: Int, j: Int) = data(i)(j)
def map(f:T=>T)= new Matrix(data.map(_.map(f)))
def pieceWise(f: (T, T) => T, that: Matrix[T]): Matrix[T] = {
val temp: Array[Array[T]] = Array.ofDim[T](m, n)
for (i <- 0 until m; j <- 0 until n) temp(i)(j) = f(data(i)(j), that.data(i)(j))
return new Matrix(temp)
}
def +(that: Matrix[T]) = pieceWise(num.plus(_, _), that)
def -(that: Matrix[T]) = pieceWise(num.minus(_, _), that)
def *(that: Matrix[T]) = {
val temp = Matrix[T](m,that.n,num.one)
for (i <- 0 until m; j <- 0 until n; k <- 0 until that.n)
temp.data(i)(k) = num.plus(temp.data(i)(k) , num.times( data(i)(j) , that.data(j)(k)))
temp
}
override def toString() = (for (i <- 0 until m) yield "\n" + (for (j <- 0 until n) yield data(i)(j))).toString
}
Все компилируется, и я даже могу запустить свой тест, но в определенный момент он не проходит. Тест, который я запускаю, выглядит следующим образом:
val M = 100
val N = 100
val threads = false
def main(args: Array[String]) {
val r = new Random(2)
val a: Matrix[Double] = Matrix(M, N, r)
val b: Matrix[Double] = Matrix(N, M, r)
println(a)
println(b)
var m12 = a * b
}
Это терпит неудачу со следующим исключением:
Exception in thread "main" scala.MatchError: null
at scala.reflect.ClassManifest$.arrayType(ClassManifest.scala:206)
at scala.Array$.fill(Array.scala:254)
at dm8xx.matrix.immutable.Matrix$.apply(Matrix.scala:12)
at dm8xx.matrix.immutable.Matrix.$times(Matrix.scala:37)
at dm8xx.matrix.MatrixTest$.main(MatrixTest.scala:19)
at dm8xx.matrix.MatrixTest.main(MatrixTest.scala)
Может кто-нибудь сказать мне, почему манифест класса является нулевым в этой точке? Извините за добавление такого большого количества кода, но я не могу сказать, в какой момент моя ошибка лежит, поэтому я должен сообщить обо всем. (Может быть, я смогу удалить ненужные части, когда получу хороший ответ).
Хорошо, теперь код работает, но, конечно, он по крайней мере в 10 раз медленнее, чем прямая реализация, например, с Double... вот как выглядит финальная матрица (если кому-то интересно):
package dm8xx.matrix.immutable
import scala.util.Random
/*
* Bring your sunglasses...
*/
object Matrix {
def apply[T](m: Int, n: Int, v: T)(implicit nn: Numeric[T], mm: ClassManifest[T]): Matrix[T] = {
new Matrix[T](Array.fill(m, n)(v))
}
def apply[T](m: Int, n: Int)(implicit num: Numeric[T], cm: ClassManifest[T]): Matrix[T] = Matrix[T](m, n, num.zero)
def apply(m: Int, n: Int, r: Random): Matrix[Double] =
new Matrix(Array.fill[Double](m, n) { Math.floor(r.nextDouble() * 100) })
}
class Matrix[T: Numeric: ClassManifest](val data: Array[Array[T]]) {
val num = implicitly[Numeric[T]]
val cm: ClassManifest[T] = implicitly
val m = data.size
val n = data(0).size
def apply(i: Int, j: Int) = data(i)(j)
def map(f: T => T) = new Matrix(data.map(_.map(f)))
def pieceWise(f: (T, T) => T, that: Matrix[T]): Matrix[T] = {
val temp: Array[Array[T]] = Array.ofDim[T](m, n)
for (i <- 0 until m; j <- 0 until n) temp(i)(j) = f(data(i)(j), that.data(i)(j))
return new Matrix(temp)
}
def +(that: Matrix[T]) = pieceWise(num.plus(_, _), that)
def -(that: Matrix[T]) = pieceWise(num.minus(_, _), that)
def *(that: Matrix[T]) = {
val temp = Matrix[T](m, that.n, num.zero)
for (i <- 0 until m; j <- 0 until n; k <- 0 until that.n)
temp.data(i)(k) = num.plus(temp.data(i)(k), num.times(data(i)(j), that.data(j)(k)))
temp
}
override def toString() = (for (i <- 0 until m) yield "\n" + (for (j <- 0 until n) yield data(i)(j))).toString
}
2 ответа
Это похоже на работу:
class Matrix[T: Numeric: ClassManifest](val data: Array[Array[T]]) {
val num = implicitly[Numeric[T]]
val cm: ClassManifest[T] = implicitly
...
Попробуйте использовать Manifest
вместо ClassManifest
Массивы нуждаются в дополнительной обработке, когда содержат примитивы, потому что они reified, но ClassManifest
предназначен для работы с классами (название - раздача)