1 /*
2 Copyright (c) 2013-2021 Timur Gafarov, Martin Cejp
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Square matrices with static memory allocation
31  *
32  * Copyright: Timur Gafarov, Martin Cejp 2013-2021.
33  * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
34  * Authors: Timur Gafarov, Martin Cejp
35  */
36 module dlib.math.matrix;
37 
38 import std.math;
39 import std.range;
40 import std.format;
41 import std.conv;
42 import std..string;
43 
44 import dlib.math.vector;
45 import dlib.math.utils;
46 import dlib.math.decomposition;
47 import dlib.math.linsolve;
48 
49 /***********************************
50  * Square (NxN) matrix.
51  * 
52  * Implementation notes:
53  * 
54  * - The storage order is column-major.
55  *
56  * - Affine vector of 4x4 matrix is in the 4th column (as in OpenGL).
57  *
58  * - Elements are stored in a fixed manner, so it is impossible to change
59  *   matrix size once it's created.
60  *
61  * - Actual data is allocated as a static array, so no references, no GC touching.
62  *   When you pass a Matrix by value, it will be safely copied.
63  *
64  * - This implementation is not perfect (as for now) for dealing with really
65  *   big matrices, but ideal for smaller ones, e.g. those which are meant to be
66  *   manipulated in real-time (in game engines, rendering pipelines etc).
67  */
68 struct Matrix(T, size_t N)
69 {
70     /**
71      * Compare two matrices.
72      *
73      * Params:
74      *     that = The matrix to compare with.
75      *
76      * Returns: $(D_KEYWORD true) if dimensions are equal, $(D_KEYWORD false) otherwise.
77      */
78     bool opEquals(Matrix!(T, N) that) const
79     {
80         return arrayof == that.arrayof;
81     }
82 
83    /**
84     * Return zero matrix
85     */
86     static zero()
87     do
88     {
89         Matrix!(T,N) res;
90         foreach (ref v; res.arrayof)
91             v = 0;
92         return res;
93     }
94 
95    /**
96     * Return identity matrix
97     */
98     static identity()
99     do
100     {
101         Matrix!(T,N) res;
102         res.setIdentity();
103         return res;
104     }
105 
106    /**
107     * Set to identity
108     */
109     void setIdentity()
110     do
111     {
112         foreach(y; 0..N)
113         foreach(x; 0..N)
114         {
115             if (y == x)
116                 arrayof[y * N + x] = 1;
117             else
118                 arrayof[y * N + x] = 0;
119         }
120     }
121 
122    /**
123     * Create matrix from array.
124     * This is a convenient way to deal with arrays of "classic" layout:
125     * the storage order in an array should be row-major
126     */
127     this(F)(F[] arr)
128     in
129     {
130         assert (arr.length == N * N,
131             "Matrix!(T,N): wrong array length in constructor");
132     }
133     do
134     {
135         foreach (i, ref v; arrayof)
136         {
137             auto i2 = i / N + N * (i - N * (i / N));
138             v = arr[i2];
139         }
140     }
141 
142    /**
143     * T = Matrix[i, j]
144     */
145     T opIndex(in size_t i, in size_t j) const
146     do
147     {
148         return arrayof[j * N + i];
149     }
150 
151    /**
152     * Matrix[i, j] = T
153     */
154     T opIndexAssign(in T t, in size_t i, in size_t j)
155     do
156     {
157         return (arrayof[j * N + i] = t);
158     }
159 
160    /**
161     * T = Matrix[index]
162     * Indices start with 0
163     */
164     T opIndex(in size_t index) const
165     in
166     {
167         assert ((0 <= index) && (index < N * N),
168             "Matrix.opIndex(int index): array index out of bounds");
169     }
170     do
171     {
172         return arrayof[index];
173     }
174 
175    /**
176     * Matrix[index] = T
177     * Indices start with 0
178     */
179     T opIndexAssign(in T t, in size_t index)
180     in
181     {
182         assert ((0 <= index) && (index < N * N),
183             "Matrix.opIndexAssign(T t, int index): array index out of bounds");
184     }
185     do
186     {
187         return (arrayof[index] = t);
188     }
189 
190    /**
191     * Matrix4x4!(T)[index1..index2] = T
192     */
193     T[] opSliceAssign(in T t, in size_t index1, in size_t index2)
194     in
195     {
196         assert ((0 <= index1) && (index1 < N * N),
197             "Matrix.opSliceAssign(T t, int index1, int index2): index1 out of bounds");
198         assert ((0 <= index2) && (index2 < N * N),
199             "Matrix.opSliceAssign(T t, int index1, int index2): index2 out of bounds");
200     }
201     do
202     {
203         return (arrayof[index1..index2] = t);
204     }
205 
206    /**
207     * Matrix[] = T
208     */
209     T[] opSliceAssign(in T t)
210     do
211     {
212         return (arrayof[] = t);
213     }
214 
215    /**
216     * Matrix + Matrix
217     */
218     Matrix!(T,N) opBinary(string op)(Matrix!(T,N) mat) const if (op == "+")
219     do
220     {
221         auto res = Matrix!(T,N)();
222         foreach (i; 0..N)
223         foreach (j; 0..N)
224         {
225             res[i, j] = this[i, j] + mat[i, j];
226         }
227         return res;
228     }
229 
230    /**
231     * Matrix - Matrix
232     */
233     Matrix!(T,N) opBinary(string op)(Matrix!(T,N) mat) const if (op == "-")
234     do
235     {
236         auto res = Matrix!(T,N)();
237         foreach (i; 0..N)
238         foreach (j; 0..N)
239         {
240             res[i, j] = this[i, j] - mat[i, j];
241         }
242         return res;
243     }
244 
245    /**
246     * Matrix * Matrix
247     */
248     Matrix!(T,N) opBinary(string op)(Matrix!(T,N) mat) const if (op == "*")
249     do
250     {
251         static if (N == 2)
252         {
253             Matrix!(T,N) res;
254 
255             res.a11 = (a11 * mat.a11) + (a12 * mat.a21);
256             res.a12 = (a11 * mat.a12) + (a12 * mat.a22);
257 
258             res.a21 = (a21 * mat.a11) + (a22 * mat.a21);
259             res.a22 = (a21 * mat.a12) + (a22 * mat.a22);
260 
261             return res;
262         }
263         else static if (N == 3)
264         {
265             Matrix!(T,N) res;
266 
267             res.a11 = (a11 * mat.a11) + (a12 * mat.a21) + (a13 * mat.a31);
268             res.a12 = (a11 * mat.a12) + (a12 * mat.a22) + (a13 * mat.a32);
269             res.a13 = (a11 * mat.a13) + (a12 * mat.a23) + (a13 * mat.a33);
270 
271             res.a21 = (a21 * mat.a11) + (a22 * mat.a21) + (a23 * mat.a31);
272             res.a22 = (a21 * mat.a12) + (a22 * mat.a22) + (a23 * mat.a32);
273             res.a23 = (a21 * mat.a13) + (a22 * mat.a23) + (a23 * mat.a33);
274 
275             res.a31 = (a31 * mat.a11) + (a32 * mat.a21) + (a33 * mat.a31);
276             res.a32 = (a31 * mat.a12) + (a32 * mat.a22) + (a33 * mat.a32);
277             res.a33 = (a31 * mat.a13) + (a32 * mat.a23) + (a33 * mat.a33);
278 
279             return res;
280         }
281         else static if (N == 4)
282         {
283             Matrix!(T,N) res;
284 
285             res.a11 = (a11 * mat.a11) + (a12 * mat.a21) + (a13 * mat.a31) + (a14 * mat.a41);
286             res.a12 = (a11 * mat.a12) + (a12 * mat.a22) + (a13 * mat.a32) + (a14 * mat.a42);
287             res.a13 = (a11 * mat.a13) + (a12 * mat.a23) + (a13 * mat.a33) + (a14 * mat.a43);
288             res.a14 = (a11 * mat.a14) + (a12 * mat.a24) + (a13 * mat.a34) + (a14 * mat.a44);
289 
290             res.a21 = (a21 * mat.a11) + (a22 * mat.a21) + (a23 * mat.a31) + (a24 * mat.a41);
291             res.a22 = (a21 * mat.a12) + (a22 * mat.a22) + (a23 * mat.a32) + (a24 * mat.a42);
292             res.a23 = (a21 * mat.a13) + (a22 * mat.a23) + (a23 * mat.a33) + (a24 * mat.a43);
293             res.a24 = (a21 * mat.a14) + (a22 * mat.a24) + (a23 * mat.a34) + (a24 * mat.a44);
294 
295             res.a31 = (a31 * mat.a11) + (a32 * mat.a21) + (a33 * mat.a31) + (a34 * mat.a41);
296             res.a32 = (a31 * mat.a12) + (a32 * mat.a22) + (a33 * mat.a32) + (a34 * mat.a42);
297             res.a33 = (a31 * mat.a13) + (a32 * mat.a23) + (a33 * mat.a33) + (a34 * mat.a43);
298             res.a34 = (a31 * mat.a14) + (a32 * mat.a24) + (a33 * mat.a34) + (a34 * mat.a44);
299 
300             res.a41 = (a41 * mat.a11) + (a42 * mat.a21) + (a43 * mat.a31) + (a44 * mat.a41);
301             res.a42 = (a41 * mat.a12) + (a42 * mat.a22) + (a43 * mat.a32) + (a44 * mat.a42);
302             res.a43 = (a41 * mat.a13) + (a42 * mat.a23) + (a43 * mat.a33) + (a44 * mat.a43);
303             res.a44 = (a41 * mat.a14) + (a42 * mat.a24) + (a43 * mat.a34) + (a44 * mat.a44);
304 
305             return res;
306         }
307         else
308         {
309             auto res = Matrix!(T,N)();
310 
311             foreach (i; 0..N)
312             foreach (j; 0..N)
313             {
314                 T sumProduct = 0;
315                 foreach (k; 0..N)
316                     sumProduct += this[i, k] * mat[k, j];
317                 res[i, j] = sumProduct;
318             }
319 
320             return res;
321         }
322     }
323 
324    /**
325     * Matrix += Matrix
326     */
327     Matrix!(T,N) opOpAssign(string op)(Matrix!(T,N) mat) if (op == "+")
328     do
329     {
330         this = this + mat;
331         return this;
332     }
333 
334    /**
335     * Matrix -= Matrix
336     */
337     Matrix!(T,N) opOpAssign(string op)(Matrix!(T,N) mat) if (op == "-")
338     do
339     {
340         this = this - mat;
341         return this;
342     }
343 
344    /**
345     * Matrix *= Matrix
346     */
347     Matrix!(T,N) opOpAssign(string op)(Matrix!(T,N) mat) if (op == "*")
348     do
349     {
350         this = this * mat;
351         return this;
352     }
353 
354    /**
355     * Matrix * T
356     */
357     Matrix!(T,N) opBinary(string op)(T k) const if (op == "*")
358     do
359     {
360         auto res = Matrix!(T,N)();
361         foreach(i, v; arrayof)
362             res.arrayof[i] = v * k;
363         return res;
364     }
365 
366    /**
367     * Matrix *= T
368     */
369     Matrix!(T,N) opOpAssign(string op)(T k) if (op == "*")
370     do
371     {
372         foreach(ref v; arrayof)
373             v *= k;
374         return this;
375     }
376 
377    /**
378     * Multiply column vector by the matrix
379     */
380     static if (N == 2)
381     {
382         Vector!(T,2) opBinaryRight(string op) (Vector!(T,2) v) const if (op == "*")
383         do
384         {
385             return Vector!(T,2)
386             (
387                 (v.x * a11) + (v.y * a12),
388                 (v.x * a21) + (v.y * a22)
389             );
390         }
391     }
392     else
393     static if (N == 3)
394     {
395         Vector!(T,3) opBinaryRight(string op) (Vector!(T,3) v) const if (op == "*")
396         do
397         {
398             return Vector!(T,3)
399             (
400                 (v.x * a11) + (v.y * a12) + (v.z * a13),
401                 (v.x * a21) + (v.y * a22) + (v.z * a23),
402                 (v.x * a31) + (v.y * a32) + (v.z * a33)
403             );
404         }
405     }
406     else
407     {
408         Vector!(T,N) opBinaryRight(string op) (Vector!(T,N) v) const if (op == "*")
409         do
410         {
411             Vector!(T,N) res;
412             foreach(x; 0..N)
413             {
414                 T n = 0;
415                 foreach(y; 0..N)
416                     n += v.arrayof[y] * arrayof[y * N + x];
417                 res.arrayof[x] = n;
418             }
419             return res;
420         }
421     }
422 
423    /**
424     * Multiply column 3D vector by the affine 4x4 matrix
425     */
426     static if (N == 4)
427     {
428         Vector!(T,3) opBinaryRight(string op) (Vector!(T,3) v) const if (op == "*")
429         do
430         {
431             return Vector!(T,3)
432             (
433                 (v.x * a11) + (v.y * a12) + (v.z * a13) + a14,
434                 (v.x * a21) + (v.y * a22) + (v.z * a23) + a24,
435                 (v.x * a31) + (v.y * a32) + (v.z * a33) + a34
436             );
437         }
438     }
439 
440     static if (N == 3 || N == 4)
441     {
442        /**
443         * Rotate a vector by the 3x3 upper-left portion of the matrix
444         */
445         Vector!(T,3) rotate(Vector!(T,3) v) const
446         do
447         {
448             return Vector!(T,3)
449             (
450                 (v.x * a11) + (v.y * a12) + (v.z * a13),
451                 (v.x * a21) + (v.y * a22) + (v.z * a23),
452                 (v.x * a31) + (v.y * a32) + (v.z * a33)
453             );
454         }
455 
456        /**
457         * Rotate a vector by the inverse 3x3 upper-left portion of the matrix
458         */
459         Vector!(T,3) invRotate(Vector!(T,3) v) const
460         do
461         {
462             return Vector!(T,3)
463             (
464                 (v.x * a11) + (v.y * a21) + (v.z * a31),
465                 (v.x * a12) + (v.y * a22) + (v.z * a32),
466                 (v.x * a13) + (v.y * a23) + (v.z * a33)
467             );
468         }
469     }
470 
471     static if (N == 4 || N == 3)
472     {
473         T determinant3x3() const
474         do
475         {
476             return a11 * (a33 * a22 - a32 * a23)
477                  - a21 * (a33 * a12 - a32 * a13)
478                  + a31 * (a23 * a12 - a22 * a13);
479         }
480     }
481 
482     static if (N == 1)
483     {
484        /**
485         * Determinant (of upper-left 3x3 portion for 4x4 matrices)
486         */
487         T determinant() const
488         do
489         {
490             return a11;
491         }
492     }
493     else
494     static if (N == 2)
495     {
496         T determinant() const
497         do
498         {
499             return a11 * a22 - a12 * a21;
500         }
501     }
502     else
503     static if (N == 3)
504     {
505         alias determinant = determinant3x3;
506     }
507     else
508     {
509         // Determinant of a given upper-left portion
510         T determinant(size_t n = N) const
511         do
512         {
513             T d = 0;
514 
515             if (n == 1)
516                 d = this[0,0];
517             else if (n == 2)
518                 d = this[0,0] * this[1,1] - this[1,0] * this[0,1];
519             else
520             {
521                 auto submat = Matrix!(T,N)();
522 
523                 for (uint c = 0; c < n; c++)
524                 {
525                     uint subi = 0;
526                     for (uint i = 1; i < n; i++)
527                     {
528                         uint subj = 0;
529                         for (uint j = 0; j < n; j++)
530                         {
531                             if (j == c)
532                                 continue;
533                             submat[subi, subj] = this[i, j];
534                             subj++;
535                         }
536                         subi++;
537                     }
538 
539                     d += pow(-1, c + 2.0) * this[0, c] * submat.determinant(n-1);
540                 }
541             }
542 
543             return d;
544         }
545     }
546 
547     alias det = determinant;
548 
549    /**
550     * Return true if matrix is singular
551     */
552     bool isSingular() @property
553     do
554     {
555         return (determinant == 0);
556     }
557 
558     alias singular = isSingular;
559 
560    /**
561     * Check if matrix represents affine transformation
562     */
563     static if (N == 4)
564     {
565         bool isAffine() @property
566         do
567         {
568             return (a41 == 0.0
569                  && a42 == 0.0
570                  && a43 == 0.0
571                  && a44 == 1.0);
572         }
573 
574         alias affine = isAffine;
575     }
576 
577    /**
578     * Transpose
579     */
580     void transpose()
581     do
582     {
583         this = transposed;
584     }
585 
586    /**
587     * Return the transposed matrix
588     */
589     Matrix!(T,N) transposed() @property
590     do
591     {
592         Matrix!(T,N) res;
593 
594         foreach(y; 0..N)
595         foreach(x; 0..N)
596             res.arrayof[y * N + x] = arrayof[x * N + y];
597 
598         return res;
599     }
600 
601    /**
602     * Invert
603     */
604     void invert()
605     do
606     {
607         this = inverse;
608     }
609 
610    /**
611     * Inverse of a matrix
612     */
613     static if (N == 1)
614     {
615         Matrix!(T,N) inverse() @property
616         do
617         {
618             Matrix!(T,N) res;
619             res.a11 = 1.0 / a11;
620             return res;
621         }
622     }
623     else
624     static if (N == 2)
625     {
626         Matrix!(T,N) inverse() @property
627         do
628         {
629             Matrix!(T,N) res;
630 
631             T invd = 1.0 / (a11 * a22 - a12 * a21);
632 
633             res.a11 =  a22 * invd;
634             res.a12 = -a12 * invd;
635             res.a22 =  a11 * invd;
636             res.a21 = -a21 * invd;
637 
638             return res;
639         }
640     }
641     else
642     static if (N == 3)
643     {
644         Matrix!(T,N) inverse() @property
645         do
646         {
647             T d = determinant;
648 
649             T oneOverDet = 1.0 / d;
650 
651             Matrix!(T,N) res;
652 
653             res.a11 =  (a33 * a22 - a32 * a23) * oneOverDet;
654             res.a12 = -(a33 * a12 - a32 * a13) * oneOverDet;
655             res.a13 =  (a23 * a12 - a22 * a13) * oneOverDet;
656 
657             res.a21 = -(a33 * a21 - a31 * a23) * oneOverDet;
658             res.a22 =  (a33 * a11 - a31 * a13) * oneOverDet;
659             res.a23 = -(a23 * a11 - a21 * a13) * oneOverDet;
660 
661             res.a31 =  (a32 * a21 - a31 * a22) * oneOverDet;
662             res.a32 = -(a32 * a11 - a31 * a12) * oneOverDet;
663             res.a33 =  (a22 * a11 - a21 * a12) * oneOverDet;
664 
665             return res;
666         }
667     }
668     else
669     {
670         Matrix!(T,N) inverse() @property
671         do
672         {
673             Matrix!(T,N) res;
674 
675             // Inversion via LU decomposition
676             enum inv = q{{
677                 Matrix!(T,N) l, u, p;
678                 decomposeLUP(this, l, u, p);
679                 foreach(j; 0..N)
680                 {
681                     Vector!(T,N) b = p.getColumn(j);
682                     Vector!(T,N) x;
683                     solveLU(l, u, x, b);
684                     res.setColumn(j, x);
685                 }
686             }};
687 
688             // Inverse of a 4x4 affine matrix is a special case
689             enum affineInv = q{{
690                 auto m3inv = matrix4x4to3x3(this).inverse;
691                 res = matrix3x3to4x4(m3inv);
692                 Vector!(T,3) t = -(getColumn(3).xyz * m3inv);
693                 res.setColumn(3, Vector!(T,4)(t.x, t.y, t.z, 1.0f));
694             }};
695 
696             static if (N == 4)
697             {
698                 if (affine)
699                     mixin(affineInv);
700                 else
701                     mixin(inv);
702             }
703             else
704                 mixin(inv);
705 
706             return res;
707         }
708     }
709 
710    /**
711     * Adjugate and cofactor matrices
712     */
713     static if (N == 1)
714     {
715         Matrix!(T,N) adjugate() @property
716         do
717         {
718             Matrix!(T,N) res;
719             res.arrayof[0] = 1;
720             return res;
721         }
722 
723         Matrix!(T,N) cofactor() @property
724         {
725             Matrix!(T,N) res;
726             res.arrayof[0] = 1;
727             return res;
728         }
729     }
730     else
731     static if (N == 2)
732     {
733         Matrix!(T,N) adjugate() @property
734         do
735         {
736             Matrix!(T,N) res;
737             res.arrayof[0] =  arrayof[3];
738             res.arrayof[1] = -arrayof[1];
739             res.arrayof[2] = -arrayof[2];
740             res.arrayof[3] =  arrayof[0];
741             return res;
742         }
743 
744         Matrix!(T,N) cofactor() @property
745         {
746             Matrix!(T,N) res;
747             res.arrayof[0] =  arrayof[3];
748             res.arrayof[1] = -arrayof[2];
749             res.arrayof[2] = -arrayof[1];
750             res.arrayof[3] =  arrayof[0];
751             return res;
752         }
753     }
754     else
755     {
756         Matrix!(T,N) adjugate() @property
757         do
758         {
759             return cofactor.transposed;
760         }
761 
762         Matrix!(T,N) cofactor() @property
763         do
764         {
765             Matrix!(T,N) res;
766 
767             foreach(y; 0..N)
768             foreach(x; 0..N)
769             {
770                 auto submat = Matrix!(T,N-1)();
771 
772                 uint suby = 0;
773                 foreach(yy; 0..N)
774                 if (yy != y)
775                 {
776                     uint subx = 0;
777                     foreach(xx; 0..N)
778                     if (xx != x)
779                     {
780                         submat[subx, suby] = this[xx, yy];
781                         subx++;
782                     }
783                     suby++;
784                 }
785 
786                 res[x, y] = submat.determinant * (((x + y) % 2)? -1:1);
787             }
788 
789             return res;
790         }
791     }
792 
793    /**
794     * Negative matrix
795     */
796     Matrix!(T,N) negative() @property
797     do
798     {
799         return this * -1;
800     }
801 
802    /**
803     * Convert to string
804     */
805     string toString() @property
806     do
807     {
808         return matrixToStr(this);
809     }
810 
811    /**
812     * Symbolic element access
813     */
814     private static string elements(string letter) @property
815     do
816     {
817         string res;
818         foreach (x; 0..N)
819         foreach (y; 0..N)
820         {
821             res ~= "T " ~ letter ~ to!string(y+1) ~ to!string(x+1) ~ ";";
822         }
823         return res;
824     }
825 
826    /**
827     * Row/column manipulations
828     */
829     Vector!(T,N) getRow(size_t i)
830     {
831         Vector!(T,N) res;
832         for (size_t j = 0; j < N; j++)
833             res.arrayof[j] = this[i, j];
834         return res;
835     }
836 
837     void setRow(size_t i, Vector!(T,N) v)
838     {
839         for (size_t j = 0; j < N; j++)
840             this[i, j] = v.arrayof[j];
841     }
842 
843     Vector!(T,N) getColumn(size_t j)
844     {
845         Vector!(T,N) res;
846         for (size_t i = 0; i < N; i++)
847             res.arrayof[i] = this[i, j];
848         return res;
849     }
850 
851     void setColumn(size_t j, Vector!(T,N) v)
852     {
853         for (size_t i = 0; i < N; i++)
854             this[i, j] = v.arrayof[i];
855     }
856 
857     void swapRows(size_t r1, size_t r2)
858     {
859         for (size_t j = 0; j < N; j++)
860         {
861             T t = this[r1, j];
862             this[r1, j] = this[r2, j];
863             this[r2, j] = t;
864         }
865     }
866 
867     void swapColumns(size_t c1, size_t c2)
868     {
869         for (size_t i = 0; i < N; i++)
870         {
871             T t = this[i, c1];
872             this[i, c1] = this[i, c2];
873             this[i, c2] = t;
874         }
875     }
876 
877     auto flatten()
878     {
879         return transposed.arrayof;
880     }
881 
882    /**
883     * Matrix elements
884     */
885     union
886     {
887        /**
888         * This auto-generated structure provides symbolic access
889         * to matrix elements, like in standard mathematic notation:
890         * ---
891         *  a11 a12 a13 a14 .. a1N
892         *  a21 a22 a23 a24 .. a2N
893         *  a31 a32 a33 a34 .. a3N
894         *  a41 a42 a43 a44 .. a4N
895         *   :   :   :   :  .
896         *  aN1 aN2 aN3 aN4  ' aNN
897         * ---
898         */
899         struct { mixin(elements("a")); }
900 
901        /**
902         * Linear array representing elements column by column
903         */
904         T[N * N] arrayof;
905     }
906 }
907 
908 ///
909 unittest
910 {
911     auto m1 = matrixf(
912         1, 2, 0, 6,
913         4, 6, 3, 1,
914         2, 7, 8, 2,
915         0, 5, 2, 1
916     );
917     auto m2 = matrixf(
918         0, 3, 7, 1,
919         1, 0, 2, 5,
920         1, 9, 2, 6,
921         5, 2, 0, 0
922     );
923     assert(m1 * m2 == matrixf(
924         32, 15, 11, 11,
925         14, 41, 46, 52,
926         25, 82, 44, 85,
927         12, 20, 14, 37)
928     );
929 
930     auto m3 = Matrix4f.identity;
931     assert(m3 == matrixf(
932         1, 0, 0, 0,
933         0, 1, 0, 0,
934         0, 0, 1, 0,
935         0, 0, 0, 1)
936     );
937 
938     m3[12] = 1;
939     m3.a24 = 2;
940     m3.a34 = 3;
941     m3[1..4] = 0;
942     
943     assert(m3[12] == 1);
944 
945     assert(m1.determinant3x3 == -25);
946     assert(m1.determinant == 567);
947 
948     assert(m1.singular == false);
949 
950     assert(m1.affine == false);
951 
952     assert(m1.transposed == matrixf(
953         1, 4, 2, 0,
954         2, 6, 7, 5,
955         0, 3, 8, 2,
956         6, 1, 2, 1)
957     );
958 
959     auto m4 = matrixf(
960         0, 3, 2,
961         1, 0, 8,
962         0, 1, 0
963     );
964 
965     assert(m4.inverse == matrixf(
966         -4,   1, 12,
967         -0,   0,  1,
968          0.5, 0, -1.5)
969     );
970     
971     assert(m1.adjugate == matrixf(
972         7, 148, -16, -158,
973       -14,  28, -49,  154,
974       -14, -53, 113,  -89,
975        98, -34,  19,  -25)
976     );
977 
978     assert(m1.cofactor == matrixf(
979         7, -14, -14,  98,
980       148,  28, -53, -34,
981       -16, -49, 113,  19,
982      -158, 154, -89, -25)
983     );
984     
985     m1.transpose();
986     assert(m1 == matrixf(
987         1, 4, 2, 0,
988         2, 6, 7, 5,
989         0, 3, 8, 2,
990         6, 1, 2, 1)
991     );
992     
993     Matrix2f m5;
994     m5[] = 1.0f;
995     m5 += matrixf(
996       2, 2,
997       2, 2
998     );
999     m5 *= m5;
1000     assert(m5 == matrixf(
1001       18, 18,
1002       18, 18)
1003     );
1004     
1005     m5 = m5 - m5;
1006     assert(m5 == Matrix2f.zero);
1007     
1008     Matrix2f m6 = matrixf(
1009       2, 2,
1010       2, 2
1011     );
1012     m6 = m6 * m6;
1013     m6 = m6 * 2;
1014     m6 *= 2;
1015     assert(m6 == matrixf(
1016       32, 32,
1017       32, 32)
1018     );
1019     assert(m6.determinant == 0);
1020     
1021     Matrix3f m7 = matrixf(
1022       3, 3, 3,
1023       3, 3, 3,
1024       3, 3, 3
1025     );
1026     m7 = m7 * m7;
1027     assert(m7 == matrixf(
1028       27, 27, 27,
1029       27, 27, 27,
1030       27, 27, 27)
1031     );
1032     
1033     Matrix2f m8 = matrixf(
1034         1, 0,
1035         0, 1
1036     );
1037     m8.invert();
1038     assert(m8 == matrixf(
1039         1, 0,
1040         0, 1)
1041     );
1042     assert(m8.negative == matrixf(
1043        -1,  0,
1044         0, -1)
1045     );
1046     
1047     auto m9 = matrixf(
1048         1, 0, 0, 2,
1049         0, 1, 0, 3,
1050         0, 0, 1, 4,
1051         0, 0, 0, 1
1052     );
1053     assert(m9.affine == true);
1054     assert(m9.inverse == matrixf(
1055         1, 0, 0, -2,
1056         0, 1, 0, -3,
1057         0, 0, 1, -4,
1058         0, 0, 0,  1)
1059     );
1060     
1061     bool isAlmostZero3(Vector3f v)
1062     {
1063         float e = 0.002f;
1064         return abs(v.x) < e &&
1065                abs(v.y) < e &&
1066                abs(v.z) < e;
1067     }
1068     
1069     Vector3f v1 = Vector3f(1, 0, 0);
1070     v1 = v1 * matrixf(
1071         1, 0, 0, 2,
1072         0, 1, 0, 3,
1073         0, 0, 1, 4,
1074         0, 0, 0, 1
1075     );
1076     assert(v1 == Vector3f(3, 3, 4));
1077     
1078     Vector3f v2 = Vector3f(0, 1, 0);
1079     const float a1 = PI * 0.5f;
1080     v2 = matrixf(
1081         1, 0,        0,       0,
1082         0, cos(a1), -sin(a1), 0,
1083         0, sin(a1),  cos(a1), 0,
1084         0, 0,        0,       1
1085     ).rotate(v2);
1086     assert(isAlmostZero3(v2 - Vector3f(0, 0, 1)));
1087     
1088     Vector3f v3 = Vector3f(0, 1, 0);
1089     v3 = matrixf(
1090         1, 0,        0,       0,
1091         0, cos(a1), -sin(a1), 0,
1092         0, sin(a1),  cos(a1), 0,
1093         0, 0,        0,       1
1094     ).invRotate(v3);
1095     assert(isAlmostZero3(v3 - Vector3f(0, 0, -1)));
1096     
1097     auto m10 = matrixf(
1098         1, 2, 3,
1099         3, 2, 1,
1100         2, 3, 1
1101     );
1102     
1103     Vector3f r0 = m10.getRow(0);
1104     assert(isAlmostZero3(r0 - Vector3f(1, 2, 3)));
1105     
1106     Vector3f c0 = m10.getColumn(0);
1107     assert(isAlmostZero3(c0 - Vector3f(1, 3, 2)));
1108     
1109     m10.setRow(2, Vector3f(1, 1, 1));
1110     Vector3f r2 = m10.getRow(2);
1111     assert(isAlmostZero3(r2 - Vector3f(1, 1, 1)));
1112     
1113     m10.setColumn(2, Vector3f(1, 1, 1));
1114     Vector3f c2 = m10.getColumn(2);
1115     assert(isAlmostZero3(c2 - Vector3f(1, 1, 1)));
1116     
1117     m10.swapRows(0, 1);
1118     Vector3f r1 = m10.getRow(1);
1119     assert(isAlmostZero3(r1 - Vector3f(1, 2, 1)));
1120     
1121     m10.swapColumns(1, 2);
1122     Vector3f c1 = m10.getColumn(1);
1123     assert(isAlmostZero3(c1 - Vector3f(1, 1, 1)));
1124     
1125     Matrix2f m11 = matrixf(
1126         2, 1,
1127         2, 1
1128     );
1129     assert(m11.adjugate == matrixf(
1130         1, -1,
1131        -2,  2)
1132     );
1133     assert(m11.cofactor == matrixf(
1134         1, -2,
1135        -1,  2)
1136     );
1137     assert(m11.flatten == [2, 1, 2, 1]);
1138     
1139     assert(m11.elements("a") == "T a11;T a21;T a12;T a22;");
1140     
1141     Matrix!(float, 1) m12 = matrixf(1);
1142     assert(m12.determinant == 1);
1143     assert(m12.inverse == matrixf(1));
1144     assert(m12.adjugate == matrixf(1));
1145     assert(m12.cofactor == matrixf(1));
1146 }
1147 
1148 /*
1149  * Predefined matrix type aliases
1150  */
1151 /// Alias for single precision 2x2 Matrix
1152 alias Matrix!(float, 2) Matrix2x2f, Matrix2f;
1153 /// Alias for single precision 3x3 Matrix
1154 alias Matrix!(float, 3) Matrix3x3f, Matrix3f;
1155 /// Alias for single precision 4x4 Matrix
1156 alias Matrix!(float, 4) Matrix4x4f, Matrix4f;
1157 /// Alias for double precision 2x2 Matrix
1158 alias Matrix!(double, 2) Matrix2x2d, Matrix2d;
1159 /// Alias for double precision 3x3 Matrix
1160 alias Matrix!(double, 3) Matrix3x3d, Matrix3d;
1161 /// Alias for double precision 4x4 Matrix
1162 alias Matrix!(double, 4) Matrix4x4d, Matrix4d;
1163 
1164 /**
1165  * Short aliases
1166  */
1167 alias mat2 = Matrix2x2f;
1168 alias mat3 = Matrix3x3f;
1169 alias mat4 = Matrix4x4f;
1170 
1171 /**
1172  * Matrix factory function
1173  */
1174 auto matrixf(A...)(A arr)
1175 {
1176     static assert(isPerfectSquare(arr.length),
1177         "matrixf(A): input array length is not perfect square integer");
1178     return Matrix!(float, cast(size_t)sqrt(cast(float)arr.length))([arr]);
1179 }
1180 
1181 /**
1182  * Converts 3x3 matrix to 4x4 matrix.
1183  * 4x4 matrix defaults to identity
1184  */
1185 Matrix!(T,4) matrix3x3to4x4(T) (Matrix!(T,3) m)
1186 {
1187     auto res = Matrix!(T,4).identity;
1188     res.a11 = m.a11; res.a12 = m.a12; res.a13 = m.a13;
1189     res.a21 = m.a21; res.a22 = m.a22; res.a23 = m.a23;
1190     res.a31 = m.a31; res.a32 = m.a32; res.a33 = m.a33;
1191     return res;
1192 }
1193 
1194 ///
1195 unittest
1196 {
1197     Matrix3f m1 = matrixf(
1198         1, 0, 0,
1199         0, 1, 0,
1200         0, 0, 1
1201     );
1202     Matrix4f m2 = matrix3x3to4x4(m1);
1203     assert(m2 == matrixf(
1204         1, 0, 0, 0,
1205         0, 1, 0, 0,
1206         0, 0, 1, 0,
1207         0, 0, 0, 1)
1208     );
1209 }
1210 
1211 /**
1212  * Converts 4x4 matrix to 3x3 matrix.
1213  * 3x3 matrix defaults to identity
1214  */
1215 Matrix!(T,3) matrix4x4to3x3(T) (Matrix!(T,4) m)
1216 {
1217     auto res = Matrix!(T,3).identity;
1218     res.a11 = m.a11; res.a12 = m.a12; res.a13 = m.a13;
1219     res.a21 = m.a21; res.a22 = m.a22; res.a23 = m.a23;
1220     res.a31 = m.a31; res.a32 = m.a32; res.a33 = m.a33;
1221     return res;
1222 }
1223 
1224 ///
1225 unittest
1226 {
1227     Matrix4f m1 = matrixf(
1228         1, 0, 0, 0,
1229         0, 1, 0, 0,
1230         0, 0, 1, 0,
1231         0, 0, 0, 1
1232     );
1233     Matrix3f m2 = matrix4x4to3x3(m1);
1234     assert(m2 == matrixf(
1235         1, 0, 0,
1236         0, 1, 0,
1237         0, 0, 1)
1238     );
1239 }
1240 
1241 /**
1242  * Formatted matrix printer
1243  */
1244 string matrixToStr(T, size_t N)(Matrix!(T, N) m)
1245 {
1246     uint width = 8;
1247     string maxnum;
1248     foreach(x; m.arrayof)
1249     {
1250         string num;
1251         real frac, integ;
1252         frac = modf(x, integ);
1253         if (frac == 0.0f)
1254         {
1255             num = format("% s", to!long(integ));
1256             if (num.length > width)
1257                 width = cast(uint)num.length;
1258         }
1259         else
1260         {
1261             num = format("% .4f", x);
1262         }
1263     }
1264 
1265     auto writer = appender!string();
1266     foreach (x; 0..N)
1267     {
1268         foreach (y; 0..N)
1269         {
1270             string s = format("% -*.4f", width, m.arrayof[y * N + x]);
1271             uint n = 0;
1272             foreach(i, c; s)
1273             {
1274                 if (i < width)
1275                 {
1276                     formattedWrite(writer, c.to!string);
1277                     n++;
1278                 }
1279             }
1280 
1281             if (y < N-1)
1282                 formattedWrite(writer, "  ");
1283         }
1284 
1285         if (x < N-1)
1286             formattedWrite(writer, "\n");
1287     }
1288 
1289     return writer.data;
1290 }
1291 
1292 ///
1293 unittest
1294 {
1295     import std..string;
1296     Matrix2f m1 = matrixf(
1297         1, 0,
1298         0, 1
1299     );
1300     string s = m1.toString;
1301     assert(s.startsWith(" 1.0000    0.0000 \n 0.0000    1.0000"));
1302 }