var height: Int
# Items of this matrix, rows by rows
- private var items: Array[Float] is lazy do
- return new Array[Float].filled_with(0.0, width*height)
- end
+ private var items = new NativeDoubleArray(width*height) is lazy
# Create a matrix from nested sequences
#
for j in height.times do assert items[j].length == width
+ for j in [0..height[ do
+ for i in [0..width[ do
+ self[j, i] = items[j][i]
+ end
+ end
+ end
+
+ # Get each row of this matrix in nested arrays
+ #
+ # ~~~
+ # var items = [[1.0, 2.0],
+ # [3.0, 4.0]]
+ # var matrix = new Matrix.from(items)
+ # assert matrix.to_a == items
+ # ~~~
+ fun to_a: Array[Array[Float]]
+ do
+ var a = new Array[Array[Float]]
for j in height.times do
+ var row = new Array[Float]
for i in width.times do
- self[j, i] = items[j][i]
+ row.add self[j, i]
end
+ a.add row
end
+ return a
end
# Create a matrix from an `Array[Float]` composed of rows after rows
assert size >= 0
var matrix = new Matrix(size, size)
- for i in size.times do
- for j in size.times do
+ for i in [0..size[ do
+ for j in [0..size[ do
matrix[j, i] = if i == j then 1.0 else 0.0
end
end
end
# Create a new clone of this matrix
- redef fun clone do return new Matrix.from_array(width, height, items.clone)
+ redef fun clone
+ do
+ var c = new Matrix(width, height)
+ for i in [0..width*height[ do c.items[i] = items[i]
+ return c
+ end
# Get the value at column `y` and row `x`
#
assert self.width == other.height
var out = new Matrix(other.width, self.height)
- for j in self.height.times do
- for i in other.width.times do
- var sum = items.first.zero
- for k in self.width.times do sum += self[j, k] * other[k, i]
- out[j, i] = sum
- end
- end
+ out.items.mul(items, other.items, self.width, self.height, other.width)
+ return out
+ end
+
+ # Get the transpose of this matrix
+ #
+ # ~~~
+ # var matrix = new Matrix.from([[1.0, 2.0, 3.0],
+ # [4.0, 5.0, 6.0]])
+ # assert matrix.transposed.to_a == [[1.0, 4.0],
+ # [2.0, 5.0],
+ # [3.0, 6.0]]
+ #
+ # var i = new Matrix.identity(3)
+ # assert i.transposed == i
+ # ~~~
+ fun transposed: Matrix
+ do
+ var out = new Matrix(height, width)
+ for k, v in self do out[k.x, k.y] = v
return out
end
redef fun to_s
do
- var lines = new Array[String]
- for y in height.times do
- lines.add items.subarray(y*width, width).join(" ")
+ var s = new FlatBuffer
+ for y in [0..height[ do
+ for x in [0..width[ do
+ s.append items[y*width+x].to_s
+ if x < width-1 then s.add ' '
+ end
+ if y < height-1 then s.add '\n'
end
- return lines.join("\n")
+ return s.to_s
end
- redef fun ==(other) do return other isa Matrix and other.items == self.items
- redef fun hash do return items.hash
+ redef fun ==(other) do return other isa Matrix and
+ width == other.width and height == other.height and
+ items.equal_items(items, width*height)
+
+ redef fun hash do return items.hash_items(width*height)
end
private class MatrixIndexIterator
redef fun to_s do return "({x},{y})"
end
+
+# Specialized native structure to store matrix items and avoid boxing cost
+private extern class NativeDoubleArray `{ double* `}
+
+ new(size: Int) do
+ var sizeof_double = 8
+ var buf = new CString(sizeof_double*size)
+ return new NativeDoubleArray.in_buffer(buf)
+ end
+
+ new in_buffer(buffer: CString) `{ return (double*)buffer; `}
+
+ fun [](i: Int): Float `{ return self[i]; `}
+
+ fun []=(i: Int, value: Float) `{ self[i] = value; `}
+
+ fun equal_items(other: NativeDoubleArray, len: Int): Bool `{
+ int i;
+ for (i = 0; i < len; i ++)
+ if (self[i] != other[i])
+ return 0;
+ return 1;
+ `}
+
+ fun hash_items(len: Int): Int `{
+ // Adapted from `SequenceRead::hash`
+ long r = 17+len;
+ int i;
+ for (i = 0; i < len; i ++)
+ r = r * 3 / 2 + (long)(i*1024.0);
+ return r;
+ `}
+
+ fun mul(a, b: NativeDoubleArray, a_width, a_height, b_width: Int) `{
+ int i, j, k;
+ for (j = 0; j < a_height; j ++)
+ for (i = 0; i < b_width; i ++) {
+ float sum = 0.0;
+ for (k = 0; k < a_width; k ++) sum += a[j*a_width + k] * b[k*b_width + i];
+ self[j*b_width + i] = sum;
+ }
+ `}
+end