Scala array average example

1,450 views
Skip to first unread message

eivindw

unread,
Oct 9, 2009, 7:13:12 AM10/9/09
to NativeLibs4Java
Hello! I'm working on a master-thesis where I will implement some
small image processing examples in Scala. Have been trying to use
ScalaCL, but have a few issues I hope someone can help me out with.

The simplified example I want to do is calculate an average of an
array-element and its neighbors. Example Scala code:

// example array
val arr = Array(30, 60, 32, 99, 5, 63, 71, 8, 92)

// create new array
val newArr = Array.make(9, 0)

// fill new array with average values
for(i <- 0 until arr.size) {
newArr(i) =
if(i == 0) {
(arr(i) + arr(i+1)) / 2
} else if(i == arr.size - 1) {
(arr(i-1) + arr(i)) / 2
} else {
(arr(i-1) + arr(i) + arr(i+1)) / 3
}
}

I have tried to move the example to ScalaCL. I created a small program
like this:

class SimpleAvg(i: Dim) extends Program(i) {
val iarr = IntsVar
var output = IntsVar

content = output(i) := (iarr(i - 1) + iarr(i) + iarr(i + 1)) / 3
}

Obviously this does not work for the first and last elements as the
index for previous and next element will be outside the array.
Typically giving errors like this:

"Inferred weird array usage for array variable 'in' (MinMax
(-1.0,9.0)). Please allocate it explicitely in its constructor."

In my original code you can see me checking for i == 0 and i ==
arr.size - 1. Is there any way I can have these kind of constraints in
the ScalaCL-code? Or do you have suggestions how to achieve the same
result with a different technique?

If I can solve this I believe I can come up with a general algorithm
that can be used for various matrix-operations related to image
processing. Any help or tips is welcome :)

Regards
- Eivind B W

Olivier Chafik

unread,
Oct 10, 2009, 4:02:14 PM10/10/09
to nativel...@googlegroups.com
Hi Eivind,

2009/10/9 eivindw <eiv...@gmail.com>
class SimpleAvg(i: Dim) extends Program(i) {
  val iarr = IntsVar
  var output = IntsVar

  content = output(i) := (iarr(i - 1) + iarr(i) + iarr(i + 1)) / 3
}

Obviously this does not work for the first and last elements as the
index for previous and next element will be outside the array.
Typically giving errors like this:

"Inferred weird array usage for array variable 'in' (MinMax
(-1.0,9.0)). Please allocate it explicitely in its constructor."

This error is easy to fix, you just need to allocate the input array variable size explicitely :

var iarr = IntsVar(i) // allocate to the size of the computation dimension
or
var iarr = IntsVar(1515) // constant size allocation

ScalaCL looked at the indexes given to iarr, and it inferred that they might be as big as 9 and as small as -1 -> concluded there was no unambiguous implicit size for this array.

In my original code you can see me checking for i == 0 and i ==
arr.size - 1. Is there any way I can have these kind of constraints in
the ScalaCL-code?

Not yet, so I've just added an "If" function to ScalaCL (notice the capital 'I', as 'if' cannot be used as a method identifier for DSL construction).

'If' operates on expressions (equivalent of java's test ? thenExpr : elseExpr) and then needs 3 arguments, and on statements (then accepts 2 or three arguments, as the else branch is optional).

You program becomes :

class SimpleAvg(i: Dim) extends Program(i) {
   val input = IntsVar(i)
   var output = IntsVar(i)
   content = output(i) :=
(
input(If(i == 0, i, i - 1)) +
input(i) +
input(If(i == (i.size - 1), i, i + 1))
) / 3
}

Or do you have suggestions how to achieve the same
result with a different technique?

Images will support various different settings for out-of-bounds access (repeat, zero, same as border, mirror...).
ImageVar support in ScalaCL is my next priority :-)

If I can solve this I believe I can come up with a general algorithm
that can be used for various matrix-operations related to image
processing.

I guess there will be other missing parts along the way, please tell me as they come :-)

Best regards
--
Olivier

eivindw

unread,
Oct 12, 2009, 8:17:06 AM10/12/09
to NativeLibs4Java
Thanks for the quick response!

I built a tiny example doing some simple array-operations, like this
one:

class AddProg(i: Dim) extends Program(i) {
val iarr = IntsVar
val iarr2 = IntsVar

var output = IntsVar

content = output := iarr + iarr2
}

Used like this, with a simple Time object:

def plusCL(other: ArrayMatrix) = {
Time("Copy in-data"){
prog.iarr.write(arr)
prog.iarr2.write(other.arr)
}
Time("Run program"){
prog !
}
val newArr = Array.make(arr.size, 0)
Time("Copy out-data"){
for(i <- 0 until arr.size) {
newArr(i) = prog.output.get(i)
}
}
new ArrayMatrix(nCols, newArr)
}

Running on a 1000x1000 matrix (aka 1000000 size array) I got the
following timings:

# Block "Copy in-data" completed, time taken: 146 ms (0.146 s)
# Block "Run program" completed, time taken: 5 ms (0.0050 s)
# Block "Copy out-data" completed, time taken: 204 ms (0.204 s)

Seems like most of the time is used copying data to and from the
program. I noticed that the "write" method on IntsVar is implemented
using a for-comprehension. Could it be that this would be faster with
a regular while loop? Some small tests I've done indicate that while-
loops are much faster than for-comprehensions. There is also a blog-
entry here showing similar results:

http://villane.wordpress.com/2008/02/13/scala-for-avs-while-update/

Just a suggestion. I might be wrong in this.. :)

- eivindw

Olivier Chafik

unread,
Oct 12, 2009, 1:22:04 PM10/12/09
to nativel...@googlegroups.com
Hi Eivind

--
Olivier Chafik
+33 6 34 30 55 70

Olivier Chafik

unread,
Oct 12, 2009, 1:29:57 PM10/12/09
to nativel...@googlegroups.com
Oops, my thumb was too quick on the send button (maybe something to
improve on the iPhone )

So "Hi Eivind", and thanks a lot for your suggestion on using while
loops vs for comprehensions :-)

The Seq/Array read/write methods are actually here for convenience,
not for speed (yet I still need to optimize them, notably with your
suggestion).

You should use the NIO buffer versions of read/write, if possible with
direct buffers (see directInts, directFloats... methods in
SyntaxUtils.scala)

Cheers


--
Olivier Chafik
+33 6 34 30 55 70

Le 12 oct. 2009 à 14:17, eivindw <eiv...@gmail.com> a écrit :

Reply all
Reply to author
Forward
0 new messages