I am writing a piece of software for parallel computations. The software is totally generic, and thus I need a class to wrap sequences.
Right now, I am experiencing strange behaviour in my map-function. A map function takes a function-object as input, which can output a different type than its input argument.
Take a look at the following code:
class SeqMPJ[T](indexedSeq: IndexedSeq[T]) {
val seq = indexedSeq.view //Lazy
val freeRanks = MPJEnv.getFreeRanks(seq.size)
//Get n free ranks
val commGroup = MPI.COMM_WORLD.group.Incl(freeRanks.toArray)
//Communicator for this sequence
val comm = MPI.COMM_WORLD.Create(commGroup)
val opIndex = globalRank % seq.size
var operand: Any = seq(opIndex)
if (!isOnline)
error("Cannot use MPJ-abstractions outside parallelize body...")
//Only works for p=n now
def mapMPJ[U](f: (T) => U): SeqMPJView[U] = {
if (freeRanks.contains(globalRank)) { //Process is part of this operation
operand = f(operand.asInstanceOf[T])
}
return new SeqMPJView(operand.asInstanceOf[U], comm, freeRanks)
}
…
Notice that in the function mapMPJ[U](f: (T) => U):SeqMPJView[U] , the function f has input type T and output type U. This means, after applying f to the variable “operand”, operand is of type U, however, this happens inside the if-block. In other words, depending on the state, operand has either type U or T. Now, when I cast to U, it always succeeds. Even when the condition in the if-block fails. As I see it, the program should fail when casting operand.asInstanceOf[U] if the program does not enter the if-block.
An example usage is in this matrix multiplication:
val M = 2
val N = 2
val A = Array(
Array(1.0, 2.0),
Array(3.0, 4.0))
val B = Array(
Array(1.0, 2.0),
Array(3.0, 4.0))
val Bt = B.transpose
/*
* DNS using underlying MPI
*/
parallelize(args) {
for (i <- 0 until M; j <- 0 until N)
A(i) zip Bt(j) mapMPJ { case (a, b) => a * b } reduceMPJ (_ + _)
if (globalRank == 0)
println("CHECK RESULT:\n" + Matrix(A) * Matrix(B))
}
The program compiles and runs perfectly using the newest eclipse scala IDE. I haven’t tried other compilers, but it’s probably me being blind, but I spent so much time, so I hope for some help 🙂
edit
There’s an implicit conversion from Array to seqMPJ, FYI.
Casting is just you asserting to the compiler that you know what you are doing and what the type really is, when it comes to generic type arguments. They’re all really just
AnyRef==java.lang.Object(or whatever the bounding type is). If you lie to it, it will believe you (until there is a runtime exception caused by having the wrong type somewhere that the type is used). If you want to know whether you’ve got the correct type, you have to check with manifests.Here’s an example:
If you try a cast that won’t work, this will yell at you:
You can modify your code accordingly, e.g.