Skip to content

Commit b621d41

Browse files
committed
add inverse matrix
1 parent 879504e commit b621d41

File tree

2 files changed

+158
-69
lines changed

2 files changed

+158
-69
lines changed

src/main/scala/matrix.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,20 @@ object Matrix:
9898

9999
def appendRowVec(a: Mat, b: Vec): Mat = (a.transpose :+ b).transpose
100100

101-
101+
def inverse(a: Array[Array[Double]]): Array[Array[Double]] =
102+
val n = a.length
103+
val m = a(0).length
104+
val identity = Array.tabulate(n, m)((i, j) => if i == j then 1.0 else 0.0)
105+
for i <- 0 until n do
106+
val pivot = a(i)(i)
107+
for j <- 0 until m do
108+
a(i)(j) /= pivot
109+
identity(i)(j) /= pivot
110+
for k <- 0 until n do
111+
if k != i then
112+
val factor = a(k)(i)
113+
for j <- 0 until m do
114+
a(k)(j) -= factor * a(i)(j)
115+
identity(k)(j) -= factor * identity(i)(j)
116+
identity
102117

src/test/scala/testmatrix.scala

Lines changed: 142 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import munit.Assertions as A
1+
import munit.Assertions as A
22

33
import org.expr.mcdm.Matrix
44

5-
65
class TestMatrix extends munit.FunSuite {
76
test("zeros(10)") {
87
val zeros10 = Matrix.zeros(10)
98
val expected = Array.fill(10)(0.0)
109
A.assert(Matrix.elementwise_equal(zeros10, expected))
1110
}
12-
test("zeros(4,5)"){
11+
test("zeros(4,5)") {
1312
val zeros45 = Matrix.zeros(4, 5)
1413
val expected = Array.fill(4, 5)(0.0)
1514
A.assert(Matrix.elementwise_equal(zeros45, expected, 1e-6))
@@ -19,175 +18,207 @@ class TestMatrix extends munit.FunSuite {
1918
val expected = Array.fill(10)(1.0)
2019
A.assert(Matrix.elementwise_equal(ones10, expected))
2120
}
22-
test("ones(4,5)"){
21+
test("ones(4,5)") {
2322
val ones45 = Matrix.ones(4, 5)
2423
val expected = Array.fill(4, 5)(1.0)
2524
A.assert(Matrix.elementwise_equal(ones45, expected, 1e-6))
2625
}
27-
test("fill(array, 100.0)"){
26+
test("fill(array, 100.0)") {
2827
val myzeros = Matrix.zeros(10)
2928
val filled = Matrix.fill(myzeros, 100.0)
3029
val expected = Array.fill(10)(100.0)
3130
A.assert(Matrix.elementwise_equal(filled, expected))
3231
}
33-
test("fill(array of array, 100.0)"){
32+
test("fill(array of array, 100.0)") {
3433
val myzeros = Matrix.zeros(4, 5)
3534
val filled = Matrix.fill(myzeros, 100.0)
3635
val expected = Array.fill(4, 5)(100.0)
3736
A.assert(Matrix.elementwise_equal(filled, expected, 1e-6))
3837
}
39-
test("idendity(5)"){
38+
test("idendity(5)") {
4039
val id5 = Matrix.identity(5)
4140
val expected = Array.tabulate(5, 5)((i, j) => if i == j then 1.0 else 0.0)
4241
A.assert(Matrix.elementwise_equal(id5, expected, 1e-6))
4342
}
44-
test("colsums"){
45-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
43+
test("colsums") {
44+
val a =
45+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
4646
val colsums = Matrix.colsums(a)
4747
val expected = Array(12.0, 15.0, 18.0)
4848
A.assert(Matrix.elementwise_equal(colsums, expected))
4949
}
50-
test("rowsums"){
51-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
50+
test("rowsums") {
51+
val a =
52+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
5253
val rowsums = Matrix.rowsums(a)
5354
val expected = Array(6.0, 15.0, 24.0)
5455
A.assert(Matrix.elementwise_equal(rowsums, expected))
5556
}
56-
test("getrowat"){
57-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
57+
test("getrowat") {
58+
val a =
59+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
5860
val row = Matrix.getrowat(a, 1)
5961
val expected = Array(4.0, 5.0, 6.0)
6062
A.assert(Matrix.elementwise_equal(row, expected))
6163
}
62-
test("getcolat"){
63-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
64+
test("getcolat") {
65+
val a =
66+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
6467
val col = Matrix.getcolat(a, 1)
6568
val expected = Array(2.0, 5.0, 8.0)
6669
A.assert(Matrix.elementwise_equal(col, expected))
6770
}
68-
test("getelementat"){
69-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
71+
test("getelementat") {
72+
val a =
73+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
7074
val element = Matrix.elementat(a, 1, 1)
7175
val expected = 5.0
7276
A.assertEquals(element, expected)
7377
}
74-
test("setrowat"){
75-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
78+
test("setrowat") {
79+
val a =
80+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
7681
val row = Array(10.0, 11.0, 12.0)
7782
val newa = Matrix.setrowat(a, 1, row)
78-
val expected = Array(Array(1.0, 2.0, 3.0), Array(10.0, 11.0, 12.0), Array(7.0, 8.0, 9.0))
83+
val expected =
84+
Array(Array(1.0, 2.0, 3.0), Array(10.0, 11.0, 12.0), Array(7.0, 8.0, 9.0))
7985
A.assert(Matrix.elementwise_equal(newa, expected, 1e-6))
8086
}
81-
test("setcolat"){
82-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
87+
test("setcolat") {
88+
val a =
89+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
8390
val col = Array(10.0, 11.0, 12.0)
8491
val newa = Matrix.setcolat(a, 1, col)
85-
val expected = Array(Array(1.0, 10.0, 3.0), Array(4.0, 11.0, 6.0), Array(7.0, 12.0, 9.0))
92+
val expected =
93+
Array(Array(1.0, 10.0, 3.0), Array(4.0, 11.0, 6.0), Array(7.0, 12.0, 9.0))
8694
A.assert(Matrix.elementwise_equal(newa, expected, 1e-6))
8795
}
88-
test("appendrow"){
96+
test("appendrow") {
8997
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0))
9098
val row = Array(7.0, 8.0, 9.0)
9199
val newa = Matrix.appendrow(a, row)
92-
val expected = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
100+
val expected =
101+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
93102
A.assert(Matrix.elementwise_equal(newa, expected, 1e-6))
94103
}
95-
test("appendcol"){
104+
test("appendcol") {
96105
val a = Array(Array(1.0, 2.0), Array(4.0, 5.0), Array(7.0, 8.0))
97106
val col = Array(3.0, 6.0, 9.0)
98107
val newa = Matrix.appendcol(a, col)
99-
val expected = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
108+
val expected =
109+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
100110
A.assert(Matrix.elementwise_equal(newa, expected, 1e-6))
101111
}
102-
test("row mins"){
103-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
112+
test("row mins") {
113+
val a =
114+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
104115
val mins = Matrix.rowmins(a)
105116
val expected = Array(1.0, 4.0, 7.0)
106117
A.assert(Matrix.elementwise_equal(mins, expected))
107118
}
108-
test("row maxs"){
109-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
119+
test("row maxs") {
120+
val a =
121+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
110122
val maxs = Matrix.rowmaxs(a)
111123
val expected = Array(3.0, 6.0, 9.0)
112124
A.assert(Matrix.elementwise_equal(maxs, expected))
113125
}
114-
test("col mins"){
115-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
126+
test("col mins") {
127+
val a =
128+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
116129
val mins = Matrix.colmins(a)
117130
val expected = Array(1.0, 2.0, 3.0)
118131
A.assert(Matrix.elementwise_equal(mins, expected))
119132
}
120-
test("col maxs"){
121-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
133+
test("col maxs") {
134+
val a =
135+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
122136
val maxs = Matrix.colmaxs(a)
123137
val expected = Array(7.0, 8.0, 9.0)
124138
A.assert(Matrix.elementwise_equal(maxs, expected))
125139
}
126-
test("which min of vector"){
140+
test("which min of vector") {
127141
val a = Array(1.0, 2.0, 3.0, 4.0, 5.0)
128142
val whichmin = Matrix.whichmin(a)
129143
val expected = 0
130144
A.assertEquals(whichmin, expected)
131145
}
132-
test("which max of vector"){
146+
test("which max of vector") {
133147
val a = Array(1.0, 2.0, 3.0, 4.0, 5.0)
134148
val whichmax = Matrix.whichmax(a)
135149
val expected = 4
136150
A.assertEquals(whichmax, expected)
137151
}
138-
test("which min of matrix"){
139-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
152+
test("which min of matrix") {
153+
val a =
154+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
140155
val whichmin = Matrix.whichmin(a)
141156
val expected = (0, 0)
142157
A.assertEquals(whichmin, expected)
143158
}
144-
test("which max of matrix"){
145-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
159+
test("which max of matrix") {
160+
val a =
161+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
146162
val whichmax = Matrix.whichmax(a)
147163
val expected = (2, 2)
148164
A.assertEquals(whichmax, expected)
149165
}
150-
test("diagonal"){
151-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
166+
test("diagonal") {
167+
val a =
168+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
152169
val diag = Matrix.diagonal(a)
153170
val expected = Array(1.0, 5.0, 9.0)
154171
A.assert(Matrix.elementwise_equal(diag, expected))
155172
}
156-
test("weightize columns"){
157-
val a = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
173+
test("weightize columns") {
174+
val a =
175+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
158176
val weights = Array(0.1, 0.2, 0.3)
159177
val weighted = Matrix.weightizeColumns(a, weights)
160-
val expected = Array(Array(0.1, 0.4, 0.9), Array(0.4, 1.0, 1.8), Array(0.7, 1.6, 2.7))
178+
val expected =
179+
Array(Array(0.1, 0.4, 0.9), Array(0.4, 1.0, 1.8), Array(0.7, 1.6, 2.7))
161180
A.assert(Matrix.elementwise_equal(weighted, expected, 1e-3))
162181
}
163-
test("Vector norm"){
182+
test("Vector norm") {
164183
val a = Array(1.0, 2.0, 3.0)
165184
val norm = Matrix.norm(a)
166185
val expected = math.sqrt(14.0)
167186
A.assertEquals(norm, expected)
168187
}
169-
test("Multiply Row by Scalar"){
170-
val mat = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
188+
test("Multiply Row by Scalar") {
189+
val mat =
190+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
171191
val scalar = 3.0
172192
val newmat = Matrix.multiplyRowByScalar(mat, 1, scalar)
173-
val expected = Array(Array(1.0, 2.0, 3.0), Array(12.0, 15.0, 18.0), Array(7.0, 8.0, 9.0))
193+
val expected =
194+
Array(Array(1.0, 2.0, 3.0), Array(12.0, 15.0, 18.0), Array(7.0, 8.0, 9.0))
174195
A.assert(Matrix.elementwise_equal(newmat, expected, 1e-6))
175196
}
176-
test("Multiply Column By Scalar"){
177-
val mat = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
197+
test("Multiply Column By Scalar") {
198+
val mat =
199+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
178200
val scalar = 10.0
179201
val newmat = Matrix.multiplyColumnByScalar(mat, 1, scalar)
180-
val expected = Array(Array(1.0, 20.0, 3.0), Array(4.0, 50.0, 6.0), Array(7.0, 80.0, 9.0))
202+
val expected =
203+
Array(Array(1.0, 20.0, 3.0), Array(4.0, 50.0, 6.0), Array(7.0, 80.0, 9.0))
181204
A.assert(Matrix.elementwise_equal(newmat, expected, 1e-4))
182205
}
183-
test("Matrix size"){
184-
val mat = Array(Array(1.0, 2.0, 3.0, 4.0), Array(4.0, 5.0, 6.0, 7.0), Array(7.0, 8.0, 9.0, 10.0))
206+
test("Matrix size") {
207+
val mat = Array(
208+
Array(1.0, 2.0, 3.0, 4.0),
209+
Array(4.0, 5.0, 6.0, 7.0),
210+
Array(7.0, 8.0, 9.0, 10.0)
211+
)
185212
val size = Matrix.size(mat)
186213
val expected = (3, 4)
187214
A.assertEquals(size, expected)
188215
}
189-
test("Apply Function to Columns - 1 (norm)"){
190-
val mat = Array(Array(1.0, 2.0, 3.0, 4.0), Array(4.0, 5.0, 6.0, 7.0), Array(7.0, 8.0, 9.0, 10.0))
216+
test("Apply Function to Columns - 1 (norm)") {
217+
val mat = Array(
218+
Array(1.0, 2.0, 3.0, 4.0),
219+
Array(4.0, 5.0, 6.0, 7.0),
220+
Array(7.0, 8.0, 9.0, 10.0)
221+
)
191222
val f = (a: Array[Double]) => math.sqrt(a.map(x => x * x).sum)
192223
val result = Matrix.applyFunctionToColumns(mat, f)
193224
val expected = Array(
@@ -198,8 +229,12 @@ class TestMatrix extends munit.FunSuite {
198229
)
199230
A.assert(Matrix.elementwise_equal(result, expected))
200231
}
201-
test("Apply Function to Columns - 2 (sum)"){
202-
val mat = Array(Array(1.0, 2.0, 3.0, 4.0), Array(4.0, 5.0, 6.0, 7.0), Array(7.0, 8.0, 9.0, 10.0))
232+
test("Apply Function to Columns - 2 (sum)") {
233+
val mat = Array(
234+
Array(1.0, 2.0, 3.0, 4.0),
235+
Array(4.0, 5.0, 6.0, 7.0),
236+
Array(7.0, 8.0, 9.0, 10.0)
237+
)
203238
val f = (a: Array[Double]) => a.sum
204239
val result = Matrix.applyFunctionToColumns(mat, f)
205240
val expected = Array(
@@ -210,26 +245,65 @@ class TestMatrix extends munit.FunSuite {
210245
)
211246
A.assert(Matrix.elementwise_equal(result, expected))
212247
}
213-
test("Apply Function to Rows"){
214-
val mat = Array(Array(1.0, 2.0, 3.0, 4.0), Array(4.0, 5.0, 6.0, 7.0), Array(7.0, 8.0, 9.0, 10.0))
248+
test("Apply Function to Rows") {
249+
val mat = Array(
250+
Array(1.0, 2.0, 3.0, 4.0),
251+
Array(4.0, 5.0, 6.0, 7.0),
252+
Array(7.0, 8.0, 9.0, 10.0)
253+
)
215254
val f = (a: Array[Double]) => a.sum
216255
val result = Matrix.applyFunctionToRows(mat, f)
217-
val expected = Array(1.0 + 2.0 + 3.0 + 4.0, 4.0 + 5.0 + 6.0 + 7.0, 7.0 + 8.0 + 9.0 + 10.0)
256+
val expected = Array(
257+
1.0 + 2.0 + 3.0 + 4.0,
258+
4.0 + 5.0 + 6.0 + 7.0,
259+
7.0 + 8.0 + 9.0 + 10.0
260+
)
218261
A.assert(Matrix.elementwise_equal(result, expected))
219262
}
220-
test("Append a Column Vector to Matrix"){
221-
val mat = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
263+
test("Append a Column Vector to Matrix") {
264+
val mat =
265+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
222266
val col = Array(10.0, 11.0, 12.0)
223267
val newmat = Matrix.appendcol(mat, col)
224-
val expected = Array(Array(1.0, 2.0, 3.0, 10.0), Array(4.0, 5.0, 6.0, 11.0), Array(7.0, 8.0, 9.0, 12.0))
268+
val expected = Array(
269+
Array(1.0, 2.0, 3.0, 10.0),
270+
Array(4.0, 5.0, 6.0, 11.0),
271+
Array(7.0, 8.0, 9.0, 12.0)
272+
)
225273
A.assert(Matrix.elementwise_equal(newmat, expected, 1e-6))
226274
}
227-
test("Append a Row Vector to Matrix"){
275+
test("Append a Row Vector to Matrix") {
228276
val mat = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0))
229277
val row = Array(7.0, 8.0, 9.0)
230278
val newmat = Matrix.appendrow(mat, row)
231-
val expected = Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
279+
val expected =
280+
Array(Array(1.0, 2.0, 3.0), Array(4.0, 5.0, 6.0), Array(7.0, 8.0, 9.0))
232281
A.assert(Matrix.elementwise_equal(newmat, expected, 1e-6))
233282
}
234-
283+
test("Inverse of a matrix") {
284+
val mat =
285+
Array(Array(1.0, 2.0, -7.0), Array(4.0, 15.0, 6.0), Array(7.0, 8.0, 9.0))
286+
val inv = Matrix.inverse(mat)
287+
val expected = Array(
288+
Array(0.142623, -0.121311, 0.191803),
289+
Array(0.00983607, 0.095082, -0.0557377),
290+
Array(-0.119672, 0.00983607, 0.0114754)
291+
)
292+
A.assert(Matrix.elementwise_equal(inv, expected, 1e-6))
293+
}
294+
test("Inverse of a matrix - 2") {
295+
val mat = Array(
296+
Array(1.0, 5.0, 6.0),
297+
Array(-1.0, 10.0, 9.0),
298+
Array(9.0, 17.0, 12.0)
299+
)
300+
val expected = Array(
301+
Array(0.157143, -0.2, 0.0714286),
302+
Array(-0.442857, 0.2, 0.0714286),
303+
Array(0.509524, -0.133333, -0.0714286)
304+
)
305+
val inv = Matrix.inverse(mat)
306+
A.assert(Matrix.elementwise_equal(inv, expected, 1e-6))
307+
}
308+
235309
}

0 commit comments

Comments
 (0)