1include <../std.scad>
  2
  3
  4module test_is_matrix() {
  5    assert(is_matrix([[2,3,4],[5,6,7],[8,9,10]]));
  6    assert(is_matrix([[2,3],[5,6],[8,9]],3,2));
  7    assert(is_matrix([[2,3],[5,6],[8,9]],m=3,n=2));
  8    assert(is_matrix([[2,3,4],[5,6,7]],m=2,n=3));
  9    assert(is_matrix([[2,3,4],[5,6,7]],2,3));
 10    assert(is_matrix([[2,3,4],[5,6,7]],m=2));
 11    assert(is_matrix([[2,3,4],[5,6,7]],2));
 12    assert(is_matrix([[2,3,4],[5,6,7]],n=3));
 13    assert(!is_matrix([[2,3,4],[5,6,7]],m=4));
 14    assert(!is_matrix([[2,3,4],[5,6,7]],n=5));
 15    assert(!is_matrix([[2,3],[5,6],[8,9]],m=2,n=3));
 16    assert(!is_matrix([[2,3,4],[5,6,7]],m=3,n=2));
 17    assert(!is_matrix([ [2,[3,4]],
 18                        [4,[5,6]]]));
 19    assert(!is_matrix([[3,4],[undef,3]]));
 20    assert(!is_matrix([[3,4],[3,"foo"]]));
 21    assert(!is_matrix([[3,4],[3,3,2]]));
 22    assert(!is_matrix([ [3,4],6]));
 23    assert(!is_matrix(undef));
 24    assert(!is_matrix(NAN));
 25    assert(!is_matrix(INF));
 26    assert(!is_matrix(-5));
 27    assert(!is_matrix(0));
 28    assert(!is_matrix(5));
 29    assert(!is_matrix(""));
 30    assert(!is_matrix("foo"));
 31    assert(!is_matrix([3,4,5]));
 32    assert(!is_matrix([]));
 33}
 34test_is_matrix();
 35
 36
 37
 38
 39module test_ident() {
 40    assert(ident(3) == [[1,0,0],[0,1,0],[0,0,1]]);
 41    assert(ident(4) == [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]);
 42}
 43test_ident();
 44
 45
 46
 47
 48
 49module test_qr_factor() {
 50  // Check that R is upper triangular
 51  function is_ut(R) =
 52     let(bad = [for(i=[1:1:len(R)-1], j=[0:min(i-1, len(R[0])-1)]) if (!approx(R[i][j],0)) 1])
 53     bad == [];
 54
 55  // Test the R is upper trianglar, Q is orthogonal and qr=M
 56  function qrok(qr,M) =
 57     is_ut(qr[1]) && approx(qr[0]*transpose(qr[0]), ident(len(qr[0]))) && approx(qr[0]*qr[1],M) && qr[2]==ident(len(qr[2]));
 58
 59  // Test the R is upper trianglar, Q is orthogonal, R diagonal non-increasing and qrp=M
 60  function qrokpiv(qr,M) =
 61       is_ut(qr[1])
 62    && approx(qr[0]*transpose(qr[0]), ident(len(qr[0])))
 63    && approx(qr[0]*qr[1]*transpose(qr[2]),M)
 64    && is_decreasing([for(i=[0:1:min(len(qr[1]),len(qr[1][0]))-1]) abs(qr[1][i][i])]);
 65
 66  
 67  M = [[1,2,9,4,5],
 68       [6,7,8,19,10],
 69       [11,12,13,14,15],
 70       [1,17,18,19,20],
 71       [21,22,10,24,25]];
 72  
 73  assert(qrok(qr_factor(M),M));
 74  assert(qrok(qr_factor(select(M,0,3)),select(M,0,3)));
 75  assert(qrok(qr_factor(transpose(select(M,0,3))),transpose(select(M,0,3))));
 76
 77  A = [[1,2,9,4,5],
 78       [6,7,8,19,10],
 79       [0,0,0,0,0],
 80       [1,17,18,19,20],
 81       [21,22,10,24,25]];
 82  assert(qrok(qr_factor(A),A));
 83
 84  B = [[1,2,0,4,5],
 85       [6,7,0,19,10],
 86       [0,0,0,0,0],
 87       [1,17,0,19,20],
 88       [21,22,0,24,25]];
 89
 90  assert(qrok(qr_factor(B),B));
 91  assert(qrok(qr_factor([[7]]), [[7]]));
 92  assert(qrok(qr_factor([[1,2,3]]), [[1,2,3]]));
 93  assert(qrok(qr_factor([[1],[2],[3]]), [[1],[2],[3]]));
 94
 95
 96  assert(qrokpiv(qr_factor(M,pivot=true),M));
 97  assert(qrokpiv(qr_factor(select(M,0,3),pivot=true),select(M,0,3)));
 98  assert(qrokpiv(qr_factor(transpose(select(M,0,3)),pivot=true),transpose(select(M,0,3))));
 99  assert(qrokpiv(qr_factor(B,pivot=true),B));
100  assert(qrokpiv(qr_factor([[7]],pivot=true), [[7]]));
101  assert(qrokpiv(qr_factor([[1,2,3]],pivot=true), [[1,2,3]]));
102  assert(qrokpiv(qr_factor([[1],[2],[3]],pivot=true), [[1],[2],[3]]));
103}
104test_qr_factor();
105
106
107module test_matrix_inverse() {
108    assert_approx(matrix_inverse(rot([20,30,40])), [[0.663413948169,0.556670399226,-0.5,0],[-0.47302145844,0.829769465589,0.296198132726,0],[0.579769465589,0.0400087565481,0.813797681349,0],[0,0,0,1]]);
109}
110test_matrix_inverse();
111
112
113module test_det2() {
114    assert_equal(det2([[6,-2], [1,8]]), 50);
115    assert_equal(det2([[4,7], [3,2]]), -13);
116    assert_equal(det2([[4,3], [3,4]]), 7);
117}
118test_det2();
119
120
121module test_det3() {
122    M = [ [6,4,-2], [1,-2,8], [1,5,7] ];
123    assert_equal(det3(M), -334);
124}
125test_det3();
126
127
128module test_determinant() {
129    M = [ [6,4,-2,9], [1,-2,8,3], [1,5,7,6], [4,2,5,1] ];
130    assert_equal(determinant(M), 2267);
131}
132test_determinant();
133
134
135module test_matrix_trace() {
136    M = [ [6,4,-2,9], [1,-2,8,3], [1,5,7,6], [4,2,5,1] ];
137    assert_equal(matrix_trace(M), 6-2+7+1);
138}
139test_matrix_trace();
140
141
142
143module test_norm_fro(){
144  assert_approx(norm_fro([[2,3,4],[4,5,6]]), 10.29563014098700);
145
146} test_norm_fro();  
147
148
149module test_linear_solve(){
150  M = [[-2,-5,-1,3],
151       [3,7,6,2],
152       [6,5,-1,-6],
153       [-7,1,2,3]];
154  assert_approx(linear_solve(M, [-3,43,-11,13]), [1,2,3,4]);
155  assert_approx(linear_solve(M, [[-5,8],[18,-61],[4,7],[-1,-12]]), [[1,-2],[1,-3],[1,-4],[1,-5]]);
156  assert_approx(linear_solve([[2]],[4]), [2]);
157  assert_approx(linear_solve([[2]],[[4,8]]), [[2, 4]]);
158  assert_approx(linear_solve(select(M,0,2), [2,4,4]), [   2.254871220604705e+00,
159                                                         -8.378819388897780e-01,
160                                                          2.330507118860985e-01,
161                                                          8.511278195488737e-01]);
162  assert_approx(linear_solve(submatrix(M,idx(M),[0:2]), [2,4,4,4]),
163                 [-2.457142857142859e-01,
164                   5.200000000000000e-01,
165                   7.428571428571396e-02]);
166  assert_approx(linear_solve([[1,2,3,4]], [2]), [0.066666666666666, 0.13333333333, 0.2, 0.266666666666]);
167  assert_approx(linear_solve([[1],[2],[3],[4]], [4,3,2,1]), [2/3]);
168  rd = [[-2,-5,-1,3],
169        [3,7,6,2],
170        [3,7,6,2],
171        [-7,1,2,3]];
172  assert_equal(linear_solve(rd,[1,2,3,4]),[]);
173  assert_equal(linear_solve(select(rd,0,2), [2,4,4]), []);
174  assert_equal(linear_solve(transpose(select(rd,0,2)), [2,4,3,4]), []);
175}
176test_linear_solve();
177
178
179
180module test_null_space(){
181    assert_equal(null_space([[3,2,1],[3,6,3],[3,9,-3]]),[]);
182
183    function nullcheck(A,dim) =
184      let(v=null_space(A))
185        len(v)==dim && all_zero(flatten(A*transpose(v)),eps=1e-12);
186    
187   A = [[-1, 2, -5, 2],[-3,-1,3,-3],[5,0,5,0],[3,-4,11,-4]];
188   assert(nullcheck(A,1));
189
190   B = [
191        [  4,    1,    8,    6,   -2,    3],
192        [ 10,    5,   10,   10,    0,    5],
193        [  8,    1,    8,    8,   -6,    1],
194        [ -8,   -8,    6,   -1,   -8,   -1],
195        [  2,    2,    0,    1,    2,    1],
196        [  2,   -3,   10,    6,   -8,    1],
197       ];
198   assert(nullcheck(B,3));
199}
200test_null_space();
201
202
203
204
205
206module test_back_substitute(){
207   R = [[12,4,3,2],
208        [0,2,-4,2],
209        [0,0,4,5],
210        [0,0,0,15]];
211   assert_approx(back_substitute(R, [1,2,3,3]), [-0.675, 1.8, 0.5, 0.2]);
212   assert_approx(back_substitute(R, [6, 3, 3.5, 37], transpose=true), [0.5, 0.5, 1, 2]);
213   assert_approx(back_substitute(R, [[38,101],[-6,-16], [31, 71], [45, 105]]), [[1, 4],[2,3],[4,9],[3,7]]);
214   assert_approx(back_substitute(R, [[12,48],[8,22],[11,36],[71,164]],transpose=true), [[1, 4],[2,3],[4,9],[3,7]]);
215   assert_approx(back_substitute([[2]], [4]), [2]);
216   sing1 =[[0,4,3,2],
217         [0,3,-4,2],
218         [0,0,4,5],
219         [0,0,0,15]];
220   sing2 =[[12,4,3,2],
221         [0,0,-4,2],
222         [0,0,4,5],
223         [0,0,0,15]];
224   sing3 = [[12,4,3,2],
225        [0,2,-4,2],
226        [0,0,4,5],
227        [0,0,0,0]];
228   assert_approx(back_substitute(sing1, [1,2,3,4]), []);
229   assert_approx(back_substitute(sing2, [1,2,3,4]), []);
230   assert_approx(back_substitute(sing3, [1,2,3,4]), []);
231}
232test_back_substitute();
233
234
235
236
237
238module test_outer_product(){
239  assert_equal(outer_product([1,2,3],[4,5,6]), [[4,5,6],[8,10,12],[12,15,18]]);
240  assert_equal(outer_product([1,2],[4,5,6]), [[4,5,6],[8,10,12]]);
241  assert_equal(outer_product([9],[7]), [[63]]);
242}
243test_outer_product();
244
245
246module test_column() {
247    v = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
248    assert(column(v,2) == [3, 7, 11, 15]);
249    data = [[1,[3,4]], [3, [9,3]], [4, [3,1]]];   // Matrix with non-numeric entries
250    assert_equal(column(data,0), [1,3,4]);
251    assert_equal(column(data,1), [[3,4],[9,3],[3,1]]);
252}
253test_column();
254
255
256// Need decision about behavior for out of bounds ranges, empty ranges
257module test_submatrix(){
258  M = [[1,2,3,4,5],
259       [6,7,8,9,10],
260       [11,12,13,14,15],
261       [16,17,18,19,20],
262       [21,22,23,24,25]];
263  assert_equal(submatrix(M,[1:2], [3:4]), [[9,10],[14,15]]);
264  assert_equal(submatrix(M,[1], [3,4]), [[9,10]]);
265  assert_equal(submatrix(M,1, [3,4]), [[9,10]]);
266  assert_equal(submatrix(M, [3,4],1), [[17],[22]]);
267  assert_equal(submatrix(M, [1,3],[2,4]), [[8,10],[18,20]]);
268  assert_equal(submatrix(M, 1,3), [[9]]);
269  A = [[true,    17, "test"],
270     [[4,2],   91, false],
271     [6,    [3,4], undef]];
272  assert_equal(submatrix(A,[0,2],[1,2]),[[17, "test"], [[3, 4], undef]]);
273}
274test_submatrix();
275
276
277
278module test_hstack() {
279    M = ident(3);
280    v1 = [2,3,4];
281    v2 = [5,6,7];
282    v3 = [8,9,10];
283    a = hstack(v1,v2);   
284    b = hstack(v1,v2,v3);
285    c = hstack([M,v1,M]);
286    d = hstack(column(M,0), submatrix(M,idx(M),[1,2]));
287    assert_equal(a,[[2, 5], [3, 6], [4, 7]]);
288    assert_equal(b,[[2, 5, 8], [3, 6, 9], [4, 7, 10]]);
289    assert_equal(c,[[1, 0, 0, 2, 1, 0, 0], [0, 1, 0, 3, 0, 1, 0], [0, 0, 1, 4, 0, 0, 1]]);
290    assert_equal(d,M);
291    strmat = [["three","four"], ["five","six"]];
292    assert_equal(hstack(strmat,strmat), [["three", "four", "three", "four"], ["five", "six", "five", "six"]]);
293    strvec = ["one","two"];
294    assert_equal(hstack(strvec,strmat),[["o", "n", "e", "three", "four"], ["t", "w", "o", "five", "six"]]);
295}
296test_hstack();
297
298
299module test_block_matrix() {
300    A = [[1,2],[3,4]];
301    B = ident(2);
302    assert_equal(block_matrix([[A,B],[B,A],[A,B]]), [[1,2,1,0],[3,4,0,1],[1,0,1,2],[0,1,3,4],[1,2,1,0],[3,4,0,1]]);
303    assert_equal(block_matrix([[A,B],ident(4)]), [[1,2,1,0],[3,4,0,1],[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]);
304    text = [["aa","bb"],["cc","dd"]];
305    assert_equal(block_matrix([[text,B]]), [["aa","bb",1,0],["cc","dd",0,1]]);
306}
307test_block_matrix();
308
309
310module test_diagonal_matrix() {
311    assert_equal(diagonal_matrix([1,2,3]), [[1,0,0],[0,2,0],[0,0,3]]);
312    assert_equal(diagonal_matrix([1,"c",2]), [[1,0,0],[0,"c",0],[0,0,2]]);
313    assert_equal(diagonal_matrix([1,"c",2],"X"), [[1,"X","X"],["X","c","X"],["X","X",2]]);
314    assert_equal(diagonal_matrix([[1,1],[2,2],[3,3]], [0,0]), [[ [1,1],[0,0],[0,0]], [[0,0],[2,2],[0,0]], [[0,0],[0,0],[3,3]]]);
315}
316test_diagonal_matrix();
317
318module test_submatrix_set() {
319    test = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15], [16,17,18,19,20]];
320    ragged = [[1,2,3,4,5],[6,7,8,9,10],[11,12], [16,17]];
321    assert_equal(submatrix_set(test,[[9,8],[7,6]]), [[9,8,3,4,5],[7,6,8,9,10],[11,12,13,14,15], [16,17,18,19,20]]);
322    assert_equal(submatrix_set(test,[[9,7],[8,6]],1),[[1,2,3,4,5],[9,7,8,9,10],[8,6,13,14,15], [16,17,18,19,20]]);
323    assert_equal(submatrix_set(test,[[9,8],[7,6]],n=1), [[1,9,8,4,5],[6,7,6,9,10],[11,12,13,14,15], [16,17,18,19,20]]);
324    assert_equal(submatrix_set(test,[[9,8],[7,6]],1,2), [[1,2,3,4,5],[6,7,9,8,10],[11,12,7,6,15], [16,17,18,19,20]]);
325    assert_equal(submatrix_set(test,[[9,8],[7,6]],-1,-1), [[6,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15], [16,17,18,19,20]]);
326    assert_equal(submatrix_set(test,[[9,8],[7,6]],n=4), [[1,2,3,4,9],[6,7,8,9,7],[11,12,13,14,15], [16,17,18,19,20]]);
327    assert_equal(submatrix_set(test,[[9,8],[7,6]],7,7), [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15], [16,17,18,19,20]]);
328    assert_equal(submatrix_set(ragged, [["a","b"],["c","d"]], 1, 1), [[1,2,3,4,5],[6,"a","b",9,10],[11,"c"], [16,17]]);
329    assert_equal(submatrix_set(test, [[]]), test);
330}
331test_submatrix_set();
332
333module test_transpose() {
334    assert(transpose([[1,2,3],[4,5,6],[7,8,9]]) == [[1,4,7],[2,5,8],[3,6,9]]);
335    assert(transpose([[1,2,3],[4,5,6]]) == [[1,4],[2,5],[3,6]]);
336    assert(transpose([[1,2,3],[4,5,6]],reverse=true) == [[6,3], [5,2], [4,1]]);
337    assert(transpose([3,4,5]) == [3,4,5]);
338}
339test_transpose();
340
341