1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Services for matrices of `Float` values
18 # A rectangular array of `Float`
20 # Require: `width > 0 and height > 0`
30 # Items of this matrix, rows by rows
31 private var items
= new NativeDoubleArray(width
*height
) is lazy
33 # Create a matrix from nested sequences
35 # Require: all rows are of the same length
38 # var matrix = new Matrix.from([[1.0, 2.0],
40 # assert matrix.to_s == """
44 init from
(items
: SequenceRead[SequenceRead[Float]])
46 if items
.is_empty
then
51 init(items
.first
.length
, items
.length
)
53 for j
in height
.times
do assert items
[j
].length
== width
55 for j
in [0..height
[ do
56 for i
in [0..width
[ do
57 self[j
, i
] = items
[j
][i
]
62 # Get each row of this matrix in nested arrays
65 # var items = [[1.0, 2.0],
67 # var matrix = new Matrix.from(items)
68 # assert matrix.to_a == items
70 fun to_a
: Array[Array[Float]]
72 var a
= new Array[Array[Float]]
73 for j
in height
.times
do
74 var row
= new Array[Float]
75 for i
in width
.times
do
83 # Create a matrix from an `Array[Float]` composed of rows after rows
85 # Require: `width > 0 and height > 0`
86 # Require: `array.length >= width*height`
89 # var matrix = new Matrix.from_array(2, 2, [1.0, 2.0,
91 # assert matrix.to_s == """
95 init from_array
(width
, height
: Int, array
: SequenceRead[Float])
99 assert array
.length
>= width
*height
103 for i
in height
.times
do
104 for j
in width
.times
do
105 self[j
, i
] = array
[i
+ j
*width
]
110 # Create an identity matrix
112 # Require: `size >= 0`
115 # var i = new Matrix.identity(3)
116 # assert i.to_s == """
121 new identity
(size
: Int)
125 var matrix
= new Matrix(size
, size
)
126 for i
in [0..size
[ do
127 for j
in [0..size
[ do
128 matrix
[j
, i
] = if i
== j
then 1.0 else 0.0
134 # Create a new clone of this matrix
137 var c
= new Matrix(width
, height
)
138 for i
in [0..width
*height
[ do c
.items
[i
] = items
[i
]
142 # Get the value at column `y` and row `x`
144 # Require: `x >= 0 and x <= width and y >= 0 and y <= height`
147 # var matrix = new Matrix.from([[0.0, 0.1],
150 # assert matrix[0, 0] == 0.0
151 # assert matrix[0, 1] == 0.1
152 # assert matrix[1, 0] == 1.0
153 # assert matrix[1, 1] == 1.1
155 fun [](y
, x
: Int): Float
157 assert x
>= 0 and x
< width
158 assert y
>= 0 and y
< height
160 return items
[x
+ y
*width
]
163 # Set the `value` at row `y` and column `x`
165 # Require: `x >= 0 and x <= width and y >= 0 and y <= height`
168 # var matrix = new Matrix.identity(2)
175 # assert matrix.to_s == """
179 fun []=(y
, x
: Int, value
: Float)
181 assert x
>= 0 and x
< width
182 assert y
>= 0 and y
< height
184 items
[x
+ y
*width
] = value
189 # Require: `self.width == other.height`
192 # var m = new Matrix.from([[3.0, 4.0],
194 # var i = new Matrix.identity(2)
197 # assert (m * m).to_s == """
201 # var a = new Matrix.from([[1.0, 2.0, 3.0],
203 # var b = new Matrix.from([[1.0],
207 # assert c.to_s == """
211 fun *(other
: Matrix): Matrix
213 assert self.width
== other
.height
215 var out
= new Matrix(other
.width
, self.height
)
216 out
.items
.mul
(items
, other
.items
, self.width
, self.height
, other
.width
)
220 # Get the transpose of this matrix
223 # var matrix = new Matrix.from([[1.0, 2.0, 3.0],
225 # assert matrix.transposed.to_a == [[1.0, 4.0],
229 # var i = new Matrix.identity(3)
230 # assert i.transposed == i
232 fun transposed
: Matrix
234 var out
= new Matrix(height
, width
)
235 for k
, v
in self do out
[k
.x
, k
.y
] = v
239 # Iterate over the values in this matrix
240 fun iterator
: MapIterator[MatrixCoordinate, Float] do return new MatrixIndexIterator(self)
244 var s
= new FlatBuffer
245 for y
in [0..height
[ do
246 for x
in [0..width
[ do
247 s
.append items
[y
*width
+x
].to_s
248 if x
< width-1
then s
.add
' '
250 if y
< height-1
then s
.add
'\n'
255 redef fun ==(other
) do return other
isa Matrix and
256 width
== other
.width
and height
== other
.height
and
257 items
.equal_items
(items
, width
*height
)
259 redef fun hash
do return items
.hash_items
(width
*height
)
262 private class MatrixIndexIterator
263 super MapIterator[MatrixCoordinate, Float]
267 redef var key
= new MatrixCoordinate(0, 0)
269 redef fun is_ok
do return key
.y
< matrix
.height
274 return matrix
[key
.y
, key
.x
]
281 if key
.x
== matrix
.width
- 1 then
290 # Position key when iterating over the values of a matrix
291 class MatrixCoordinate
292 # Index of the current column
295 # Index of the current row
298 redef fun to_s
do return "({x},{y})"
301 # Specialized native structure to store matrix items and avoid boxing cost
302 private extern class NativeDoubleArray `{ double* `}
305 var sizeof_double = 8
306 var buf = new CString(sizeof_double*size)
307 return new NativeDoubleArray.in_buffer(buf)
310 new in_buffer(buffer: CString) `{ return (double*)buffer; `}
312 fun [](i
: Int): Float `{ return self[i]; `}
314 fun []=(i: Int, value: Float) `{ self[i] = value; `}
316 fun equal_items
(other
: NativeDoubleArray, len
: Int): Bool `{
318 for (i = 0; i < len; i ++)
319 if (self[i] != other[i])
324 fun hash_items
(len
: Int): Int `{
325 // Adapted from `SequenceRead::hash
`
328 for (i = 0; i < len; i ++)
329 r = r * 3 / 2 + (long)(i*1024.0);
333 fun mul
(a
, b
: NativeDoubleArray, a_width
, a_height
, b_width
: Int) `{
335 for (j = 0; j < a_height; j ++)
336 for (i = 0; i < b_width; i ++) {
338 for (k = 0; k < a_width; k ++) sum += a[j*a_width + k] * b[k*b_width + i];
339 self[j*b_width + i] = sum;