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 height
.times
do
56 for i
in width
.times
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 size
.times
do
127 for j
in size
.times
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 for j
in self.height
.times
do
217 for i
in other
.width
.times
do
218 var sum
= items
[0].zero
219 for k
in self.width
.times
do sum
+= self[j
, k
] * other
[k
, i
]
226 # Get the transpose of this matrix
229 # var matrix = new Matrix.from([[1.0, 2.0, 3.0],
231 # assert matrix.transposed.to_a == [[1.0, 4.0],
235 # var i = new Matrix.identity(3)
236 # assert i.transposed == i
238 fun transposed
: Matrix
240 var out
= new Matrix(height
, width
)
241 for k
, v
in self do out
[k
.x
, k
.y
] = v
245 # Iterate over the values in this matrix
246 fun iterator
: MapIterator[MatrixCoordinate, Float] do return new MatrixIndexIterator(self)
250 var s
= new FlatBuffer
251 for y
in [0..height
[ do
252 for x
in [0..width
[ do
253 s
.append items
[y
*width
+x
].to_s
254 if x
< width-1
then s
.add
' '
256 if y
< height-1
then s
.add
'\n'
261 redef fun ==(other
) do return other
isa Matrix and
262 width
== other
.width
and height
== other
.height
and
263 items
.equal_items
(items
, width
*height
)
265 redef fun hash
do return items
.hash_items
(width
*height
)
268 private class MatrixIndexIterator
269 super MapIterator[MatrixCoordinate, Float]
273 redef var key
= new MatrixCoordinate(0, 0)
275 redef fun is_ok
do return key
.y
< matrix
.height
280 return matrix
[key
.y
, key
.x
]
287 if key
.x
== matrix
.width
- 1 then
296 # Position key when iterating over the values of a matrix
297 class MatrixCoordinate
298 # Index of the current column
301 # Index of the current row
304 redef fun to_s
do return "({x},{y})"
307 # Specialized native structure to store matrix items and avoid boxing cost
308 private extern class NativeDoubleArray `{ double* `}
311 var sizeof_double = 8
312 var buf = new CString(sizeof_double*size)
313 return new NativeDoubleArray.in_buffer(buf)
316 new in_buffer(buffer: CString) `{ return (double*)buffer; `}
318 fun [](i
: Int): Float `{ return self[i]; `}
320 fun []=(i: Int, value: Float) `{ self[i] = value; `}
322 fun equal_items
(other
: NativeDoubleArray, len
: Int): Bool `{
324 for (i = 0; i < len; i ++)
325 if (self[i] != other[i])
330 fun hash_items
(len
: Int): Int `{
331 // Adapted from `SequenceRead::hash
`
334 for (i = 0; i < len; i ++)
335 r = r * 3 / 2 + (long)(i*1024.0);