1 // Written in the D programming language.
2 /*
3 NYSL Version 0.9982
4 
5 A. This software is "Everyone'sWare". It means:
6   Anybody who has this software can use it as if he/she is
7   the author.
8 
9   A-1. Freeware. No fee is required.
10   A-2. You can freely redistribute this software.
11   A-3. You can freely modify this software. And the source
12       may be used in any software with no limitation.
13   A-4. When you release a modified version to public, you
14       must publish it with your name.
15 
16 B. The author is not responsible for any kind of damages or loss
17   while using or misusing this software, which is distributed
18   "AS IS". No warranty of any kind is expressed or implied.
19   You use AT YOUR OWN RISK.
20 
21 C. Copyrighted to Kazuki KOMATSU
22 
23 D. Above three clauses are applied both to source and binary
24   form of this software.
25 */
26 
27 /**
28 このモジュールは、式テンプレートベースの試験的な行列演算モジュールです。
29 */
30 module carbon.linear;
31 
32 import std.algorithm,
33        std.array,
34        std.ascii,
35        std.complex,
36        std.conv,
37        std.exception,
38        std.format,
39        std.functional,
40        std.math,
41        std.range,
42        std.traits,
43        std.typecons,
44        std..string,
45        std.typetuple;
46 
47 version(unittest) import std.stdio;
48 
49 
50 /**
51 行列の格納方式
52 */
53 enum Major
54 {
55     row,
56     column,
57 }
58 
59 /**
60 デフォルトでの行列の格納方式は「行優先」です。
61 */
62 enum defaultMajor = Major.row;
63 
64 alias Msize_t = ptrdiff_t;
65 
66 enum Msize_t wild = -2,
67              dynamic = -1;
68 
69 
70 /**
71 行列型かどうかを判定します
72 */
73 enum isMatrix(T) =
74     is(typeof((const T m)
75     {
76         size_t rsize = m.rows;
77         size_t csize = m.cols;
78 
79         size_t i = 0;
80 
81         auto e = m.at(i, i);
82     }));
83 
84 
85 ///
86 enum isNarrowMatrix(T) = 
87     is(typeof((const T m)
88     {
89         size_t rsize = m.rows;
90         size_t csize = m.cols;
91 
92         auto e1 = m[0, 0];
93         auto e2 = m.at(0, 0);
94 
95         static assert(is(typeof(e2) : typeof(e1)));
96         static assert(is(typeof(e1) : typeof(e2)));
97     }));
98 
99 
100 
101 ///
102 unittest{
103     static struct S(size_t R, size_t C)
104     {
105         enum rows = R;
106         enum cols = C;
107 
108         auto opIndex(size_t i, size_t j) const
109         {
110             return i + j;
111         }
112 
113         alias at = opIndex;
114     }
115 
116     static assert(isNarrowMatrix!(S!(0, 0)));
117     static assert(isMatrix!(S!(1, 1)));
118 }
119 
120 
121 /**
122 大きさが推論される行列かどうか判定します
123 */
124 enum bool isAbstractMatrix(T) = !isMatrix!T &&
125     is(typeof((T t)
126     {
127         auto e = t[0, 0];
128         auto f = t.at(0, 0);
129         static assert(!is(CommonType!(typeof(e), typeof(f)) == void));
130 
131 
132         enum InferredResult result = T.inferSize(wild, wild);
133 
134         static if(result.isValid)
135         {
136             enum inferredRows = result.rows;
137             enum inferredCols = result.cols;
138         }
139 
140         enum someValue = 4; //非負の整数
141         static assert(!T.inferSize(wild, wild).isValid);
142         static assert(T.inferSize(wild, someValue).isValid);
143         static assert(T.inferSize(wild, someValue).isValid);
144     }));
145 
146 
147 /**
148 ベクトル型かどうか判定します
149 */
150 enum bool isVector(T) =
151     is(typeof((const T v)
152     {
153         size_t size = v.length;
154 
155       static if(isMatrix!T)
156       {
157         assert(min(v.rows, v.cols) == 1);
158         assert(max(v.rows, v.cols) == size);
159       }
160 
161         auto e = v.at(size-1);
162 
163       static if(isMatrix!T)
164       {
165         static assert(is(typeof(e) : typeof(v.at(size-1))));
166         static assert(is(typeof(v.at(size-1)) : typeof(e)));
167       }
168     }));
169 
170 
171 /**
172 ベクトル型かどうか判定します
173 */
174 enum isNarrowVector(V) = isMatrix!V && isVector!V && !isAbstractMatrix!V &&
175     is(typeof((const V v)
176     {
177         static if(hasStaticRows!V && hasStaticCols!V)
178             static assert(staticRows!V == 1 || staticCols!V == 1);
179         else static if(hasStaticRows!V)
180             static assert(staticRows!V == 1);
181         else static if(hasStaticCols!V)
182             static assert(staticCols!V == 1);
183         else
184             static assert(0);
185 
186         auto e = v[0];
187         static assert(is(typeof(e) : typeof(v.at(0, 0))));
188         static assert(is(typeof(v.at(0, 0)) : typeof(e)));
189     }));
190 
191 
192 unittest{
193     static struct V
194     {
195         enum rows = 1;
196         enum cols = 3;
197         enum length = 3;
198 
199         auto opIndex(size_t i, size_t j) const { return j; }
200         auto opIndex(size_t j) const { return j; }
201 
202         alias at = opIndex;
203     }
204 
205     static assert(isMatrix!V);
206     static assert(isNarrowMatrix!V);
207     static assert(isVector!V);
208     static assert(!isAbstractMatrix!V);
209     static assert(isNarrowVector!V);
210 
211     static assert(isVector!(int[]));
212     static assert(isVector!(int[][]));
213     static assert(isVector!(int[][1]));
214     static assert(isVector!(int[1][]));
215 }
216 
217 
218 ///
219 unittest{
220     import std.bigint, std.typetuple;
221     alias TT = TypeTuple!(ubyte, ushort, uint, ulong,
222                            byte,  short,  int,  long,
223                           float, double, real,
224                           creal, cfloat, cdouble/*,*/
225                           /*BigInt*/);
226 
227     static struct M(T, size_t r, size_t c)
228     {
229         enum rows = r;
230         enum cols = c;
231 
232         auto opIndex(size_t i, size_t j) const { return T.init; }
233         alias at = opIndex;
234     }
235 
236     foreach(T; TT)
237     {
238         static assert(isNarrowMatrix!(M!(T, 3, 3)));
239         static assert(isNarrowMatrix!(M!(const(T), 3, 3)));
240         static assert(isNarrowMatrix!(M!(immutable(T), 3, 3)));
241         static assert(isMatrix!(M!(T, 3, 3)));
242         static assert(isMatrix!(M!(const(T), 3, 3)));
243         static assert(isMatrix!(M!(immutable(T), 3, 3)));
244     }
245 }
246 
247 
248 /**
249 行列型でも、ベクトル型でもないような型
250 */
251 enum bool isNotVectorOrMatrix(T) =
252     !(  isMatrix!T
253      || isAbstractMatrix!T
254      || isVector!T
255     );
256 
257 ///
258 unittest{
259     import std.bigint, std.numeric, std.typetuple;
260 
261     alias TT = TypeTuple!(ubyte, ushort, uint, ulong,
262                            byte,  short,  int,  long,
263                           float, double, real,
264                           creal, cfloat, cdouble);
265 
266     foreach(T; TT)
267     {
268         static assert(isNotVectorOrMatrix!(T));
269         static assert(isNotVectorOrMatrix!(const(T)));
270         static assert(isNotVectorOrMatrix!(immutable(T)));
271     }
272 
273     static assert(isNotVectorOrMatrix!BigInt);
274     // static assert(isNotVectorOrMatrix!(CustomFloat!16)); In dmd2.064, isNotVectorOrMatrix!(CustomFloat!16) is true.
275 }
276 
277 
278 /**
279 行列やベクトルのビューを取得します。
280 */
281 enum bool hasView(T) = is(typeof((T m){
282         auto v = m.view;
283 
284         static if(isMatrix!T)
285             static assert(isMatrix!(typeof(v)));
286         else static if(isAbstractMatrix!T)
287             static assert(isAbstractMatrix!(typeof(v)));
288         else static if(isVector!T)
289             static assert(isVector!T);
290     }));
291 
292 
293 
294 auto ref at(R)(auto ref R r, size_t i, size_t j)
295 if(!isNarrowMatrix!R && is(typeof(r[i][j])))
296 {
297   static if(defaultMajor == Major.row)
298     return r[i][j];
299   else
300     return r[j][i];
301 }
302 
303 
304 void assignAt(R, E)(auto ref R r, size_t i, size_t j, auto ref E e)
305 if(!isNarrowMatrix!R && is(typeof({ r[i][j] = forward!e; })))
306 {
307   static if(defaultMajor == Major.row)
308     r[i][j] = forward!e;
309   else
310     r[j][i] = forward!e;
311 }
312 
313 
314 auto ref at(R)(auto ref R r, size_t i, size_t j)
315 if(!isNarrowMatrix!R && is(typeof(r[i])) && !is(typeof(r[i][j])))
316 in{
317   static if(defaultMajor == Major.row)
318     assert(j == 0);
319   else
320     assert(i == 0);
321 }
322 body{
323     return r[i+j];
324 }
325 
326 
327 void assignAt(R, E)(auto ref R r, size_t i, size_t j, auto ref E e)
328 if(!isNarrowMatrix!R && is(typeof({ r[i] = forward!e; })) && !is(typeof(r[i][j])))
329 in{
330   static if(defaultMajor == Major.row)
331     assert(j == 0);
332   else
333     assert(i == 0);
334 }
335 body{
336     r[i+j] = e;
337 }
338 
339 
340 auto ref at(M)(auto ref M m, size_t i)
341 if(isMatrix!M && is(typeof(m.length)))
342 {
343     static if(hasStaticRows!M)
344         static if(staticRows!M == 1)
345         {
346             enum ReturnA = true;
347             return m.at(0, i);
348         }
349 
350   static if(!is(typeof({static assert(ReturnA);})))
351   {
352     static if(hasStaticCols!M)
353         static if(staticCols!M == 1)
354         {
355             enum ReturnB = true;
356             return m.at(i, 0);
357         }
358 
359     static if(!is(typeof({static assert(ReturnB);})))
360     {
361       if(m.rows == 1)
362           return m.at(0, i);
363       else if(m.cols == 1)
364           return m.at(i, 0);
365 
366       assert(0);
367     }
368   }
369 }
370 
371 
372 void assignAt(M, E)(auto ref M m, size_t i, auto ref E e)
373 if(isMatrix!M && is(typeof(m.length)) && is(typeof(m.assignAt(0, 0, forward!e))))
374 {
375     static if(hasStaticRows!M)
376         static if(staticRows!M == 1)
377             return m.assignAt(0, i, forward!e);
378 
379     static if(hasStaticCols!M)
380         static if(staticCols!M == 1)
381             return m.assignAt(i, 0, forward!e);
382 
383     if(m.rows == 1)
384         return m.assignAt(0, i, forward!e);
385     else if(m.cols == 1)
386         return m.assignAt(i, 0, forward!e);
387 
388     assert(0);
389 }
390 
391 
392 size_t rows(R)(auto ref R r) @property
393 if(!isNarrowMatrix!R && is(typeof(r[0][0])) && hasLength!R && hasLength!(typeof(r[0])))
394 {
395   static if(defaultMajor == Major.row)
396     return r.length;
397   else
398   {
399     if(r.length)
400         return r[0].length;
401     else
402         return 0;
403   }
404 }
405 
406 
407 size_t rows(R)(auto ref R r) @property
408 if(!isNarrowMatrix!R && is(typeof(r[0])) && !is(typeof(r[0][0])) && hasLength!R)
409 {
410   static if(defaultMajor == Major.row)
411     return r.length;
412   else
413     return 1;
414 }
415 
416 
417 size_t cols(R)(auto ref R r) @property
418 if(is(typeof(r[0][0])) && hasLength!R && hasLength!(typeof(r[0])))
419 {
420   static if(defaultMajor == Major.column)
421     return r.length;
422   else
423   {
424     if(r.length)
425         return r[0].length;
426     else
427         return 0;
428   }
429 }
430 
431 
432 size_t cols(R)(auto ref R r) @property
433 if(is(typeof(r[0])) && !is(typeof(r[0][0])) && hasLength!R)
434 {
435   static if(defaultMajor == Major.row)
436     return 1;
437   else
438     return r.length;
439 }
440 
441 
442 size_t staticRows(T)() @property
443 if(isNarrowMatrix!T)
444 {
445   static if(is(typeof(T.staticRows)))
446     return T.staticRows;
447   else static if(is(typeof({ enum srows = T.rows; })))
448     return T.rows;
449   else
450     static assert(0);
451 }
452 
453 
454 size_t staticRows(R)() @property
455 if(!isNarrowMatrix!R && is(typeof(R.init[0][0])) && hasLength!R && hasLength!(std.range.ElementType!R))
456 {
457   static if((defaultMajor == Major.row) && is(typeof({ enum srows = R.length; })))
458     return R.length;
459   else static if((defaultMajor == Major.column) && is(typeof({ enum srows = std.range.ElementType!R.length; })))
460     return std.range.ElementType!R.length;
461   else
462     static assert(0);
463 }
464 
465 
466 size_t staticRows(R)() @property
467 if(!isNarrowMatrix!R && is(typeof(R.init[0])) && !is(typeof(R.init[0][0])) && hasLength!R)
468 {
469   static if((defaultMajor == Major.row) && is(typeof({ enum srows = R.length; })))
470     return R.length;
471   else static if(defaultMajor == Major.column)
472     return 1;
473   else
474     static assert(0);
475 }
476 
477 
478 size_t staticCols(T)() @property
479 if(isNarrowMatrix!T)
480 {
481   static if(is(typeof(T.staticCols)))
482     return T.staticCols;
483   else static if(is(typeof({ enum srows = T.cols; })))
484     return T.cols;
485   else
486     static assert(0);
487 }
488 
489 
490 size_t staticCols(R)() @property
491 if(!isNarrowMatrix!R && is(typeof(R.init[0][0])) && hasLength!R && hasLength!(std.range.ElementType!R))
492 {
493   static if((defaultMajor == Major.column) && is(typeof({ enum scols = R.length; })))
494     return R.length;
495   else static if((defaultMajor == Major.row) && is(typeof({ enum scols = std.range.ElementType!R.length; })))
496     return std.range.ElementType!R.length;
497   else
498     static assert(0);
499 }
500 
501 
502 size_t staticCols(R)() @property
503 if(!isNarrowMatrix!R && is(typeof(R.init[0])) && !is(typeof(R.init[0][0])) && hasLength!R)
504 {
505   static if((defaultMajor == Major.column) && is(typeof({ enum scols = R.length; })))
506     return R.length;
507   else static if(defaultMajor == Major.row)
508     return 1;
509   else
510     static assert(0);
511 }
512 
513 
514 unittest{
515     int[][] arr2d = [
516         [ 1,  2,  3],
517         [ 4,  5,  6],
518         [ 7,  8,  9],
519         [10, 11, 12]
520     ];
521 
522     assert(arr2d.rows == 4);
523     assert(arr2d.cols == 3);
524 
525     foreach(i; 0 .. arr2d.rows)
526         foreach(j; 0 .. arr2d.cols)
527             assert(arr2d.at(i, j) == arr2d[i][j]);
528 
529     static assert(isMatrix!(int[][]));
530 
531 
532     int[] arr1d = [1, 2, 3, 4]; // 列ベクトル
533 
534     assert(arr1d.rows == 4);
535     assert(arr1d.cols == 1);
536     static assert(staticCols!(int[])() == 1);
537 
538     foreach(i; 0 .. arr1d.rows)
539         foreach(j; 0 .. arr1d.cols)
540             assert(arr1d.at(i, j) == arr1d[i] && arr1d.at(i) == arr1d[i]);
541 
542     arr2d = [arr1d];            // 行ベクトル
543     assert(arr2d.rows == 1);
544     assert(arr2d.cols == 4);
545 
546     foreach(i; 0 .. arr2d.rows)
547         foreach(j; 0 .. arr2d.cols)
548             assert(arr2d.at(i, j) == arr2d[i][j] && arr2d.at(j) == arr2d[i][j]);
549 
550     static assert(staticRows!(int[4][3]) == 3);
551     static assert(staticCols!(int[4][3]) == 4);
552     static assert(staticRows!(int[][4]) == 4);
553     static assert(staticCols!(int[4][]) == 4);
554     static assert(staticRows!(int[4]) == 4);
555 
556     static struct M(T, size_t r, size_t c)
557     {
558         enum rows = r;
559         enum cols = c;
560 
561         auto opIndex(size_t i, size_t j) const {return T.init;}
562         alias at = opIndex;
563     }
564 
565 
566     static assert(staticRows!(M!(int, 4, 3)) == 4);
567     static assert(staticCols!(M!(int, 4, 3)) == 3);
568 }
569 
570 
571 unittest{
572     static assert(isMatrix!(int[]));
573     static assert(!isNarrowMatrix!(int[]));
574     static assert(isVector!(int[]));
575     static assert(isNarrowVector!(int[]));
576 
577     static assert(isMatrix!(int[][]));
578     static assert(!isNarrowMatrix!(int[][]));
579     static assert(isVector!(int[][]));
580     static assert(!isNarrowVector!(int[][]));
581 
582     static assert(isMatrix!(int[][][]));
583     static assert(!isNarrowMatrix!(int[][][]));
584     static assert(isVector!(int[][][]));
585     static assert(!isNarrowVector!(int[][][]));
586 
587 
588     static struct M0
589     {
590         enum rows = 3;
591         //enum cols = 3;
592 
593         auto at(size_t i, size_t j) const
594         {
595             return i;
596         }
597     }
598 
599     static assert(!isMatrix!(M0));
600     static assert(!isNarrowMatrix!(M0));
601     static assert(!isVector!(M0));
602     static assert(!isNarrowVector!(M0));
603 
604 
605     static struct M1
606     {
607         enum rows = 3;
608         enum cols = 3;
609 
610         auto at(size_t i, size_t j) const
611         {
612             return i;
613         }
614     }
615 
616     static assert(isMatrix!(M1));
617     static assert(!isNarrowMatrix!(M1));
618     static assert(!isVector!(M1));
619     static assert(!isNarrowVector!(M1));
620 
621 
622     static struct M2
623     {
624         enum rows = 1;
625         enum cols = 3;
626         enum length = rows;
627 
628         auto at(size_t i, size_t j) const
629         {
630             return i;
631         }
632 
633         auto at(size_t j) const
634         {
635             return at(0, j);
636         }
637     }
638 
639     static assert(isMatrix!(M2));
640     static assert(!isNarrowMatrix!(M2));
641     static assert(isVector!(M2));
642     static assert(!isNarrowVector!(M2));
643 }
644 
645 
646 /**
647 行の大きさが静的な行列型かどうか判定します
648 */
649 enum hasStaticRows(T) = is(typeof(staticRows!T()));
650 
651 unittest{
652     int[4] arr4;
653     static assert(hasStaticRows!(int[4]));
654 }
655 
656 
657 /**
658 列の大きさが静的な行列型かどうか判定します
659 */
660 enum hasStaticCols(T) = is(typeof(staticCols!T()));
661 
662 unittest{
663     int[4][] arr4x;
664     static assert(hasStaticCols!(typeof(arr4x)));
665 }
666 
667 
668 /**
669 大きさが静的なベクトル型かどうか判定します
670 */
671 enum hasStaticLength(T) = is(typeof({ enum len = T.length; }));
672 
673 unittest{
674     static assert(hasStaticLength!(int[4]));
675 }
676 
677 
678 /**
679 行の大きさが動的な行列型かどうか判定します
680 */
681 enum hasDynamicRows(T) = !hasStaticRows!T && is(typeof({ size_t rs = T.init.rows; }));
682 
683 
684 /**
685 列の大きさが動的な行列型かどうか判定します
686 */
687 enum hasDynamicColumns(T) = !hasStaticCols!T && is(typeof({ size_t cs = T.init.cols; }));
688 
689 
690 /**
691 大きさが動的なベクトル型かどうか判定します
692 */
693 enum hasDynamicLength(T) = !hasStaticLength!T && is(typeof({ size_t len = T.init.length; }));
694 
695 
696 /**
697 大きさが推論される行列が、推論結果を返す際の結果の型です。
698 */
699 struct InferredResult
700 {
701     bool isValid;
702     size_t rows;
703     size_t cols;
704 }
705 
706 /+
707 version(none):
708 
709 
710 /**
711 Matrix -> NarrowMatrix
712 */
713 auto toNarrowMatrix(Major major = defaultMajor, M)(M m)
714 if(isMatrix!M && !isNarrowMatrix!M)
715 {
716     static struct Result()
717     {
718       static if(isVector!M)
719       {
720         auto ref opIndex(size_t i) inout
721         {
722             return _m.at(i);
723         }
724 
725 
726         auto ref length() inout
727         {
728             return _m.length;
729         }
730       }
731 
732         auto ref opIndex(size_t i, size_t j) inout
733         {
734             return _m.at(i, j);
735         }
736 
737 
738         alias at = opIndex;
739 
740 
741       static if(hasStaticRows!M)
742       {
743         enum rows = staticRows!M;
744       }
745       else
746       {
747         auto ref rows() const @property
748         {
749             return _m.rows;
750         }
751       }
752 
753 
754       static if(hasStaticCols!M)
755       {
756         enum cols = staticCols!M;
757       }
758       else
759       {
760         auto ref cols() const @property
761         {
762             return _m.cols;
763         }
764       }
765 
766 
767       private:
768         M _m;
769     }
770 
771     return Result!()(m);
772 }
773 
774 unittest {
775     auto nm = [1, 2, 3, 4].toNarrowMatrix();
776     static assert(isNarrowMatrix!(typeof(nm)));
777     static assert(isNarrowVector!(typeof(nm)));
778 }
779 
780 
781 
782 version(none):
783 
784 /**
785 ベクトルを、行列ベクトル型へ変換します
786 */
787 auto toNarrowVector(Major major = defaultMajor, V)(V v)
788 if(isVector!V && !isNarrowVector!V)
789 {
790     static struct Result()
791     {
792       static if(major == Major.row)
793       {
794         enum rows = 1;
795 
796         static if(hasStaticLength!V)
797             enum cols = V.length;
798         else
799             @property size_t cols() const { return _v.length; }
800       }
801       else
802       {
803         enum cols = 1;
804 
805         static if(hasStaticLength!V)
806             enum rows = V.length;
807         else
808             @property size_t rows() const { return _v.length; }
809       }
810 
811         @property auto ref length() const { return _v.length; }
812         alias opDollar = length;
813 
814         auto ref opIndex(size_t i) inout
815         in{
816             assert(i < length);
817         }
818         body{
819             return _v[i];
820         }
821 
822 
823         auto ref opIndex(size_t i, size_t j) inout
824         in{
825             assert(i < rows);
826             assert(j < cols);
827         }
828         body{
829             return _v[i+j];
830         }
831 
832 
833         mixin(defaultExprOps!(true));
834 
835       private:
836         V _v;
837     }
838 
839 
840     return Result!()(v);
841 }
842 +/
843 
844 /**
845 行列型の要素の型を取得します
846 */
847 template ElementType(A)
848 if(isMatrix!A || isAbstractMatrix!A)
849 {
850     alias typeof(A.init.at(0, 0)) ElementType;
851 }
852 
853 ///
854 unittest{
855     static struct S
856     {
857         enum rows = 1;
858         enum cols = 1;
859 
860         int opIndex(size_t, size_t) const
861         {
862             return 1;
863         }
864 
865         alias at = opIndex;
866     }
867 
868     static assert(is(ElementType!S == int));
869 }
870 
871 
872 /**
873 その行列の要素がstd.algorithm.swapを呼べるかどうかをチェックします
874 */
875 template hasLvalueElements(A)
876 if(isMatrix!A || isAbstractMatrix!A)
877 {
878     enum hasLvalueElements = is(typeof((A a){
879             import std.algorithm : swap;
880 
881             swap(a.at(0, 0), a.at(0, 0));
882         }));
883 }
884 
885 ///
886 unittest{
887     static struct M
888     {
889         enum rows = 1;
890         enum cols = 1;
891 
892         ref int opIndex(size_t i, size_t j) inout
893         {
894             static int a;
895             return a;
896         }
897 
898         alias at = opIndex;
899     }
900 
901     static assert(hasLvalueElements!(M));
902 }
903 
904 
905 //version(none):
906 
907 
908 /**
909 A型の行列の要素にElementType!A型の値が代入可能かどうかをチェックします。
910 */
911 template hasAssignableElements(A)
912 if(isMatrix!A || isAbstractMatrix!A)
913 {
914     enum hasAssignableElements = is(typeof((A a){
915             ElementType!A e;
916             a.assignAt(0, 0, e);
917         }));
918 }
919 unittest{
920     static struct M
921     {
922         enum rows = 1;
923         enum cols = 1;
924 
925         auto opIndex(size_t i, size_t j) const
926         {
927             return i;
928         }
929 
930         void opIndexAssign(typeof(this[0, 0]) a, size_t i, size_t j){}
931 
932         auto at(size_t i, size_t j) const
933         {
934             return this[i, j];
935         }
936 
937         void assignAt(size_t i, size_t j, typeof(this[0, 0]) e){}
938     }
939 
940     static assert(hasAssignableElements!(M));
941 }
942 
943 
944 /**
945 aとbが等しいか、もしくはどちらかが0であるとtrueとなります。
946 2つの行列が演算可能かどうかを判定するのに使います。
947 */
948 private bool isEqOrEitherEqX(alias pred = "a == b", T, X = T)(T a, T b, X x = 0)
949 {
950     return binaryFun!pred(a, b) || a == x || b == x;
951 }
952 
953 ///
954 unittest{
955     static assert(isEqOrEitherEqX(0, 0));
956     static assert(isEqOrEitherEqX(1, 1));
957     static assert(isEqOrEitherEqX(0, 1));
958     static assert(isEqOrEitherEqX(1, 0));
959 }
960 
961 
962 /**
963 ポインタを管理します
964 */
965 struct PMatrix(M)
966 if(isMatrix!M)
967 {
968     this(ref M m)
969     {
970         ptr = &m;
971     }
972 
973 
974     this(M* m)
975     {
976         ptr = m;
977     }
978 
979 
980     auto ref opIndex(size_t r, size_t c) inout
981     {
982         return (*ptr)[r, c];
983     }
984 
985 
986   static if(is(typeof({ enum r = M.rows; })))
987     enum rows = M.rows;
988   else
989   {
990     auto ref rows() inout @property { return ptr.rows; }
991 
992     static if(is(typeof({ ptr.rows = ptr.rows; })))
993     void rows(typeof(ptr.rows) r) { ptr.rows = r; }
994   }
995 
996 
997   static if(is(typeof({ enum r = M.cols; })))
998     enum cols = M.cols;
999   else
1000   {
1001     auto ref cols() inout @property { return ptr.cols; }
1002 
1003     static if(is(typeof({ ptr.cols = ptr.cols; })))
1004     void cols(typeof(ptr.cols) r) { ptr.cols = r; }
1005   }
1006 
1007 
1008     M* ptr;
1009     ref inout(typeof(this)) pref() inout pure nothrow @safe @nogc { return this; }
1010 
1011 
1012     void opAssign(X)(auto ref X m)
1013     if(is(typeof(*ptr = m)))
1014     {
1015         *ptr = m;
1016     }
1017 
1018 
1019     mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.opAssign, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
1020 }
1021 
1022 
1023 auto pref(NMatrix)(ref NMatrix nm) @property @trusted
1024 if(isMatrix!NMatrix || isAbstractMatrix!NMatrix)
1025 {
1026     return PMatrix!NMatrix(nm);
1027 }
1028 
1029 unittest
1030 {
1031     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
1032     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
1033 
1034 
1035     SMatrix!(int, 2, 2) m;
1036     m = [[0, 1],
1037          [2, 3]];
1038 
1039     auto t = m.pref;
1040     assert(t[0, 0] == 0);
1041     assert(t[0, 1] == 1);
1042     assert(t[1, 0] == 2);
1043     assert(t[1, 1] == 3);
1044 }
1045 
1046 
1047 
1048 /**
1049 正しい演算かどうか判定します
1050 
1051 Example:
1052 ----
1053 static struct S(T, size_t r, size_t c){enum rows = r; enum cols = c; T opIndex(size_t i, size_t j) const {return T.init;}}
1054 alias Static1x1 = S!(int, 1, 1);
1055 alias Static1x2 = S!(int, 1, 2);
1056 alias Static2x1 = S!(int, 2, 1);
1057 alias Static2x2 = S!(int, 2, 2);
1058 
1059 static struct D(T){size_t rows = 1, cols = 1; T opIndex(size_t i, size_t j) const {return T.init;}}
1060 alias Dynamic = D!(int);
1061 
1062 static struct I(T){
1063     enum rows = 0, cols = 0;
1064     T opIndex(size_t i, size_t j) const { return T.init; }
1065     static InferredResult inferSize(size_t rs, size_t cs){
1066         if(rs == 0 && cs == 0)
1067             return InferredResult(false, 0, 0);
1068         else if(rs == 0 || cs == 0)
1069             return InferredResult(true, max(rs, cs), max(rs, cs));
1070         else
1071             return InferredResult(true, rs, cs);
1072     }
1073 }
1074 alias Inferable = I!int;
1075 static assert(Inferable.inferSize(1, 0).isValid);
1076 
1077 alias T = Inferable;
1078 static assert(T.rows == wild);
1079 static assert(T.cols == wild);
1080 
1081 
1082 static assert( isValidOperator!(Static1x1, "+", Static1x1));
1083 static assert(!isValidOperator!(Static1x1, "+", Static1x2));
1084 static assert( isValidOperator!(Static1x2, "+", Static1x2));
1085 static assert(!isValidOperator!(Static1x2, "+", Static1x1));
1086 
1087 static assert( isValidOperator!(Static1x1, "+", Dynamic));
1088 static assert( isValidOperator!(Static1x2, "+", Dynamic));
1089 static assert( isValidOperator!(Dynamic, "+", Static1x1));
1090 static assert( isValidOperator!(Dynamic, "+", Static1x2));
1091 
1092 static assert( isValidOperator!(Static1x1, "+", Inferable));
1093 static assert( isValidOperator!(Static1x2, "+", Inferable));
1094 static assert( isValidOperator!(Inferable, "+", Static1x1));
1095 static assert( isValidOperator!(Inferable, "+", Static1x2));
1096 
1097 static assert( isValidOperator!(Static1x1, "*", Static1x1));
1098 static assert( isValidOperator!(Static1x1, "*", Static1x2));
1099 static assert(!isValidOperator!(Static1x2, "*", Static1x2));
1100 static assert(!isValidOperator!(Static1x2, "*", Static1x1));
1101 
1102 static assert( isValidOperator!(Static1x1, "*", Dynamic));
1103 static assert( isValidOperator!(Static1x2, "*", Dynamic));
1104 static assert( isValidOperator!(Dynamic, "*", Static1x1));
1105 static assert( isValidOperator!(Dynamic, "*", Static1x2));
1106 
1107 static assert( isValidOperator!(Static1x1, "*", Inferable));
1108 static assert( isValidOperator!(Static1x2, "*", Inferable));
1109 static assert( isValidOperator!(Inferable, "*", Static1x1));
1110 static assert( isValidOperator!(Inferable, "*", Static1x2));
1111 ----
1112 */
1113 template isValidOperator(L, string op, R)
1114 {
1115   static if(op != "=")
1116   {
1117     static if((isMatrix!L || isAbstractMatrix!L) && (isMatrix!R || isAbstractMatrix!R))
1118         enum isValidOperator = is(typeof(mixin("typeof(L.init.at(0, 0)).init " ~ op ~ " typeof(R.init.at(0, 0)).init"))) && isValidOperatorImpl!(L, op, R);
1119     else static if(isMatrix!L || isAbstractMatrix!L)
1120         enum isValidOperator = is(typeof(mixin("typeof(L.init.at(0, 0)).init " ~ op ~ " R.init"))) && isValidOperatorImpl!(L, op, R);
1121     else static if(isMatrix!R || isAbstractMatrix!R)
1122         enum isValidOperator = is(typeof(mixin("L.init " ~ op ~ " typeof(R.init.at(0, 0)).init"))) && isValidOperatorImpl!(L, op, R);
1123     else
1124         static assert(0);
1125   }
1126   else
1127   {
1128     static if((isMatrix!L || isAbstractMatrix!L) && (isMatrix!R || isAbstractMatrix!R)){
1129         enum isValidOperator = isAssignable!(typeof(L.init.at(0, 0)), typeof(R.init.at(0, 0))) && isValidOperatorImpl!(L, "+", R);
1130     }else static if(isMatrix!L || isAbstractMatrix!L)
1131         enum isValidOperator = isAssignable!(typeof(L.init.at(0,0)), R) && isValidOperatorImpl!(L, "+", R);
1132     else static if(isMatrix!R || isAbstractMatrix!R)
1133         enum isValidOperator = isAssignable!(L, typeof(R.init.at(0, 0))) && isValidOperatorImpl!(L, "+", R);
1134     else
1135         static assert(0);
1136   }
1137 }
1138 
1139 
1140 template isValidOperatorImpl(L, string op, R)
1141 if((isMatrix!L || isAbstractMatrix!L) && (isMatrix!R || isAbstractMatrix!R) && op != "*")
1142 {
1143     struct Inferred(M, size_t r, size_t c)
1144     {
1145         enum size_t rows = M.inferSize(r, c).rows;
1146         enum size_t cols = M.inferSize(r, c).cols;
1147 
1148         auto opIndex(size_t i, size_t j) const { return ElementType!M.init; }
1149     }
1150 
1151     static if(op != "+" && op != "-")
1152         enum isValidOperatorImpl = false;
1153     else static if(isAbstractMatrix!L && isAbstractMatrix!R)
1154         enum isValidOperatorImpl = true;
1155     else static if(isAbstractMatrix!L)
1156     {
1157         static if(hasStaticRows!R && hasStaticCols!R)
1158             enum isValidOperatorImpl = L.inferSize(staticRows!R, staticCols!R).isValid && isValidOperatorImpl!(Inferred!(L, staticRows!R, staticCols!R), op, R);
1159         else static if(hasStaticRows!R)
1160             enum isValidOperatorImpl = L.inferSize(staticRows!R, wild).isValid && isValidOperatorImpl!(Inferred!(L, staticRows!R, wild), op, R);
1161         else static if(hasStaticCols!R)
1162             enum isValidOperatorImpl = L.inferSize(wild, staticCols!R).isValid && isValidOperatorImpl!(Inferred!(L, wild, staticCols!R), op, R);
1163         else
1164             enum isValidOperatorImpl = true;
1165     }
1166     else static if(isAbstractMatrix!R)
1167         enum isValidOperatorImpl = isValidOperatorImpl!(R, op, L);
1168     else
1169     {
1170         static if(hasStaticRows!L)
1171         {
1172             static if(hasStaticRows!R)
1173                 enum _isValidR = staticRows!L == staticRows!R;
1174             else
1175                 enum _isValidR = true;
1176         }
1177         else
1178             enum _isValidR = true;
1179 
1180         static if(hasStaticCols!L)
1181         {
1182             static if(hasStaticCols!R)
1183                 enum _isValidC = staticCols!L == staticCols!R;
1184             else
1185                 enum _isValidC = true;
1186         }
1187         else
1188             enum _isValidC = true;
1189 
1190         enum isValidOperatorImpl = _isValidR && _isValidC;
1191     }
1192 }
1193 
1194 
1195 template isValidOperatorImpl(L, string op, R)
1196 if((isMatrix!L || isAbstractMatrix!L) && (isMatrix!R || isAbstractMatrix!R) && op == "*")
1197 {
1198     struct Inferred(M, size_t r, size_t c)
1199     if(r == wild || c == wild)
1200     {
1201         enum size_t rows = M.inferSize(r, c).rows;
1202         enum size_t cols = M.inferSize(r, c).cols;
1203 
1204         auto opIndex(size_t i, size_t j) const { return M.init[i, j]; }
1205     }
1206 
1207 
1208     static if(isAbstractMatrix!L && isAbstractMatrix!R)
1209         enum isValidOperatorImpl = false;
1210     else static if(isAbstractMatrix!L)
1211     {
1212         static if(hasStaticRows!R)
1213             enum isValidOperatorImpl = isValidOperatorImpl!(Inferred!(L, wild, staticRows!R), op, R);
1214         else
1215             enum isValidOperatorImpl = true;
1216     }
1217     else static if(isAbstractMatrix!R)
1218     {
1219         static if(hasStaticCols!L)
1220             enum isValidOperatorImpl = isValidOperatorImpl!(L, op, Inferred!(R, staticCols!L, wild));
1221         else
1222             enum isValidOperatorImpl = true;
1223     }
1224     else
1225     {
1226         static if(hasStaticCols!L && hasStaticRows!R)
1227             enum isValidOperatorImpl = staticCols!L == staticRows!R;
1228         else
1229             enum isValidOperatorImpl = true;
1230     }
1231 }
1232 
1233 
1234 template isValidOperatorImpl(L, string op, R)
1235 if(((isMatrix!L || isAbstractMatrix!L) && isNotVectorOrMatrix!R) || ((isMatrix!R || isAbstractMatrix!R) && isNotVectorOrMatrix!L))
1236 {
1237     static if(op != "+" && op != "-" && op != "*" && op != "/")
1238         enum isValidOperatorImpl = false;
1239     else
1240         enum isValidOperatorImpl = true;
1241 }
1242 
1243 
1244 unittest{
1245     static struct S(T, size_t r, size_t c)
1246     {
1247         enum rows = r;
1248         enum cols = c;
1249         T at(size_t i, size_t j) const { return T.init; }
1250         alias opIndex = at;
1251 
1252         static assert(isNarrowMatrix!(typeof(this)));
1253         static assert(isMatrix!(typeof(this)));
1254         static assert(hasStaticRows!(typeof(this)));
1255         static assert(hasStaticCols!(typeof(this)));
1256     }
1257     alias Static1x1 = S!(int, 1, 1);
1258     alias Static1x2 = S!(int, 1, 2);
1259     alias Static2x1 = S!(int, 2, 1);
1260     alias Static2x2 = S!(int, 2, 2);
1261 
1262     static struct D(T)
1263     {
1264         size_t rows = 1, cols = 1;
1265         T at(size_t i, size_t j) const { return T.init; }
1266         alias opIndex = at;
1267 
1268         static assert(isNarrowMatrix!(typeof(this)));
1269         static assert(isMatrix!(typeof(this)));
1270         static assert(!hasStaticRows!(typeof(this)));
1271         static assert(!hasStaticCols!(typeof(this)));
1272     }
1273     alias Dynamic = D!(int);
1274 
1275     static struct I(T)
1276     {
1277         T at(size_t i, size_t j) const { return T.init; }
1278         alias opIndex = at;
1279 
1280         static InferredResult inferSize(Msize_t rs, Msize_t cs)
1281         {
1282             if(rs == wild && cs == wild)
1283                 return InferredResult(false, 0, 0);
1284             else if(rs == wild || cs == wild)
1285                 return InferredResult(true, max(rs, cs), max(rs, cs));
1286             else
1287                 return InferredResult(true, rs, cs);
1288         }
1289     }
1290     alias Inferable = I!int;
1291     static assert(Inferable.inferSize(1, wild).isValid);
1292 
1293     alias T = Inferable;
1294     static assert(isAbstractMatrix!(I!int));
1295 
1296 
1297     static assert( isValidOperator!(Static1x1, "+", Static1x1));
1298     static assert(!isValidOperator!(Static1x1, "+", Static1x2));
1299     static assert( isValidOperator!(Static1x2, "+", Static1x2));
1300     static assert(!isValidOperator!(Static1x2, "+", Static1x1));
1301 
1302     static assert( isValidOperator!(Static1x1, "+", Dynamic));
1303     static assert( isValidOperator!(Static1x2, "+", Dynamic));
1304     static assert( isValidOperator!(Dynamic, "+", Static1x1));
1305     static assert( isValidOperator!(Dynamic, "+", Static1x2));
1306 
1307     static assert( isValidOperator!(Static1x1, "+", Inferable));
1308     static assert( isValidOperator!(Static1x2, "+", Inferable));
1309     static assert( isValidOperator!(Inferable, "+", Static1x1));
1310     static assert( isValidOperator!(Inferable, "+", Static1x2));
1311 
1312     static assert( isValidOperator!(Static1x1, "*", Static1x1));
1313     static assert( isValidOperator!(Static1x1, "*", Static1x2));
1314     static assert(!isValidOperator!(Static1x2, "*", Static1x2));
1315     static assert(!isValidOperator!(Static1x2, "*", Static1x1));
1316 
1317     static assert( isValidOperator!(Static1x1, "*", Dynamic));
1318     static assert( isValidOperator!(Static1x2, "*", Dynamic));
1319     static assert( isValidOperator!(Dynamic, "*", Static1x1));
1320     static assert( isValidOperator!(Dynamic, "*", Static1x2));
1321 
1322     static assert( isValidOperator!(Static1x1, "*", Inferable));
1323     static assert( isValidOperator!(Static1x2, "*", Inferable));
1324     static assert( isValidOperator!(Inferable, "*", Static1x1));
1325     static assert( isValidOperator!(Inferable, "*", Static1x2));
1326 
1327     foreach(i, E1; TypeTuple!(byte, short, int, long))
1328     {
1329         foreach(E2; TypeTuple!(byte, short, int, long)[0 .. i+1])
1330         {
1331             static assert( isValidOperator!(S!(E1, 1, 1), "=", S!(E2, 1, 1)));
1332             static assert(!isValidOperator!(S!(E1, 1, 1), "=", S!(E2, 1, 2)));
1333             static assert( isValidOperator!(S!(E1, 1, 2), "=", S!(E2, 1, 2)));
1334             static assert(!isValidOperator!(S!(E1, 1, 2), "=", S!(E2, 1, 1)));
1335 
1336             static assert( isValidOperator!(S!(E1, 1, 1), "=", D!(E2)));
1337             static assert( isValidOperator!(S!(E1, 1, 2), "=", D!(E2)));
1338             static assert( isValidOperator!(D!(E1), "=", S!(E2, 1, 1)));
1339             static assert( isValidOperator!(D!(E1), "=", S!(E2, 1, 2)));
1340 
1341             static assert( isValidOperator!(S!(E1, 1, 1), "=", I!(E2)));
1342             static assert( isValidOperator!(S!(E1, 1, 2), "=", I!(E2)));
1343             static assert( isValidOperator!(I!(E1), "=", S!(E2, 1, 1)));
1344             static assert( isValidOperator!(I!(E1), "=", S!(E2, 1, 2)));
1345 
1346             static assert( isValidOperator!(S!(E1, 1, 1), "=", E2));
1347             static assert( isValidOperator!(D!(E1), "=", E2));
1348             static assert( isValidOperator!(I!(E1), "=", E2));
1349         }
1350 
1351         foreach(E2; TypeTuple!(byte, short, int, long)[i+1 .. $])
1352         {
1353             static assert(!isValidOperator!(S!(E1, 1, 1), "=", S!(E2, 1, 1)));
1354             static assert(!isValidOperator!(S!(E1, 1, 1), "=", S!(E2, 1, 2)));
1355             static assert(!isValidOperator!(S!(E1, 1, 2), "=", S!(E2, 1, 2)));
1356             static assert(!isValidOperator!(S!(E1, 1, 2), "=", S!(E2, 1, 1)));
1357 
1358             static assert(!isValidOperator!(S!(E1, 1, 1), "=", D!(E2)));
1359             static assert(!isValidOperator!(S!(E1, 1, 2), "=", D!(E2)));
1360             static assert(!isValidOperator!(D!(E1), "=", S!(E2, 1, 1)));
1361             static assert(!isValidOperator!(D!(E1), "=", S!(E2, 1, 2)));
1362 
1363             static assert(!isValidOperator!(S!(E1, 1, 1), "=", I!(E2)));
1364             static assert(!isValidOperator!(S!(E1, 1, 2), "=", I!(E2)));
1365             static assert(!isValidOperator!(I!(E1), "=", S!(E2, 1, 1)));
1366             static assert(!isValidOperator!(I!(E1), "=", S!(E2, 1, 2)));
1367 
1368             static assert(!isValidOperator!(S!(E1, 1, 1), "=", E2));
1369             static assert(!isValidOperator!(D!(E1), "=", E2));
1370             static assert(!isValidOperator!(I!(E1), "=", E2));
1371         }
1372     }
1373 }
1374 
1375 
1376 /**
1377 式テンプレート演算子の種類
1378 */
1379 enum ETOSpec : uint
1380 {
1381     none = 0,
1382     matrixAddMatrix = (1 << 0),
1383     matrixSubMatrix = (1 << 1),
1384     matrixMulMatrix = (1 << 2),
1385     matrixAddScalar = (1 << 3),
1386     scalarAddMatrix = (1 << 4),
1387     matrixSubScalar = (1 << 5),
1388     scalarSubMatrix = (1 << 6),
1389     matrixMulScalar = (1 << 7),
1390     scalarMulMatrix = (1 << 8),
1391     matrixDivScalar = (1 << 9),
1392     scalarDivMatrix = (1 << 10),
1393     addScalar = (1 << 11),
1394     subScalar = (1 << 12),
1395     mulScalar = (1 << 13),
1396     divScalar = (1 << 14),
1397     opEquals = (1 << 15),
1398     toString = (1 << 16),
1399     opAssign = (1 << 17),
1400     swizzle = (1 << 18),
1401     modifiedOperator = addScalar | subScalar | mulScalar | divScalar | opAssign,
1402     all = (1 << 19) -1,
1403 }
1404 
1405 
1406 /**
1407 式テンプレートでの演算子の種類を返します
1408 */
1409 template ETOperatorSpec(A, string op, B)
1410 if(isValidOperator!(A, op, B))
1411 {
1412     static if((isMatrix!A || isAbstractMatrix!A) && (isMatrix!B || isAbstractMatrix!B))
1413         enum ETOSpec ETOperatorSpec = op == "+" ? ETOSpec.matrixAddMatrix
1414                                                 : (op == "-" ? ETOSpec.matrixSubMatrix
1415                                                              : ETOSpec.matrixMulMatrix);
1416     else static if(isNotVectorOrMatrix!A)
1417         enum ETOSpec ETOperatorSpec = op == "+" ? ETOSpec.scalarAddMatrix
1418                                                 : (op == "-" ? ETOSpec.scalarSubMatrix
1419                                                              : (op == "*" ? ETOSpec.scalarMulMatrix
1420                                                                           : ETOSpec.scalarDivMatrix));
1421     else
1422         enum ETOSpec ETOperatorSpec = op == "+" ? ETOSpec.matrixAddScalar
1423                                                 : (op == "-" ? ETOSpec.matrixSubScalar
1424                                                              : (op == "*" ? ETOSpec.matrixMulScalar
1425                                                                           : ETOSpec.matrixDivScalar));
1426 }
1427 
1428 ///
1429 unittest{
1430     static struct S(T, size_t r, size_t c)
1431     {
1432         enum rows = r;
1433         enum cols = c;
1434         T opIndex(size_t i, size_t j) const {return T.init;}
1435         alias at = opIndex;
1436     }
1437     alias Matrix2i = S!(int, 2, 2);
1438 
1439     static assert(ETOperatorSpec!(Matrix2i, "+", Matrix2i) == ETOSpec.matrixAddMatrix);
1440     static assert(ETOperatorSpec!(Matrix2i, "-", Matrix2i) == ETOSpec.matrixSubMatrix);
1441     static assert(ETOperatorSpec!(Matrix2i, "*", Matrix2i) == ETOSpec.matrixMulMatrix);
1442     static assert(ETOperatorSpec!(Matrix2i, "*", int) == ETOSpec.matrixMulScalar);
1443     static assert(ETOperatorSpec!(int, "*", Matrix2i) == ETOSpec.scalarMulMatrix);
1444 }
1445 
1446 
1447 /**
1448 式テンプレートでの、式を表します
1449 */
1450 struct MatrixExpression(Lhs, string s, Rhs)
1451 if(isValidOperator!(Lhs, s, Rhs)
1452   && (isAbstractMatrix!Lhs || isAbstractMatrix!Rhs)
1453   && !(isMatrix!Lhs || isMatrix!Rhs))
1454 {
1455     enum etoSpec = ETOperatorSpec!(Lhs, s, Rhs);
1456 
1457 
1458     static InferredResult inferSize(Msize_t r, Msize_t c)
1459     {
1460         static if(isAbstractMatrix!Lhs && isAbstractMatrix!Rhs)
1461         {
1462             static assert(s != "*");
1463             auto rLhs = Lhs.inferSize(r, c);
1464             auto rRhs = Rhs.inferSize(r, c);
1465 
1466             bool b = rLhs.isValid && rRhs.isValid && rLhs.rows == rRhs.rows && rLhs.cols == rRhs.cols;
1467             return InferredResult(b, rLhs.rows, rLhs.cols);
1468         }
1469         else static if(isAbstractMatrix!Lhs)
1470             return Lhs.inferSize(r, c);
1471         else
1472             return Rhs.inferSize(r, c);
1473     }
1474 
1475 
1476     auto opIndex(size_t i, size_t j) const
1477     {
1478       static if(etoSpec == ETOSpec.matrixAddMatrix)
1479         return this.lhs[i, j] + this.rhs[i, j];
1480       else static if(etoSpec == ETOSpec.matrixSubMatrix)
1481         return this.lhs[i, j] - this.rhs[i, j];
1482       else static if(etoSpec == ETOSpec.matrixMulMatrix)
1483       {
1484         static assert(0);
1485         return typeof(this.lhs.at(0, 0) + this.rhs.at(0, 0)).init;
1486       }
1487       else
1488       {
1489         static if(isMatrix!Lhs || isAbstractMatrix!Lhs)
1490             return mixin("this.lhs.at(i, j) " ~ s ~ " this.rhs");
1491         else
1492             return mixin("this.lhs " ~ s ~ " this.rhs.at(i, j)");
1493       }
1494     }
1495 
1496 
1497     mixin(defaultExprOps!(true));
1498 
1499   private:
1500     Lhs lhs;
1501     Rhs rhs;
1502 }
1503 
1504 
1505 /// ditto
1506 struct MatrixExpression(Lhs, string s, Rhs)
1507 if(isValidOperator!(Lhs, s, Rhs)
1508   && !((isAbstractMatrix!Lhs || isAbstractMatrix!Rhs)
1509     && !(isMatrix!Lhs || isMatrix!Rhs)))
1510 {
1511     enum etoSpec = ETOperatorSpec!(Lhs, s, Rhs);
1512 
1513 
1514     static if((isMatrix!Lhs || isAbstractMatrix!Lhs) && (isMatrix!Rhs || isAbstractMatrix!Rhs))
1515     {
1516         static if(s == "*")
1517         {
1518             static if(hasStaticRows!Lhs)
1519             {
1520                 enum rows = Lhs.rows;
1521                 private enum staticrows = rows;
1522             }
1523             else static if(isAbstractMatrix!Lhs && hasStaticRows!Rhs)
1524             {
1525                 enum rows = Lhs.inferSize(wild, Rhs.rows).rows;
1526                 private enum staticrows = rows;
1527             }
1528             else static if(hasDynamicRows!Lhs)
1529             {
1530                 @property size_t rows() const { return this.lhs.rows; }
1531                 private enum staticrows = wild;
1532             }
1533             else static if(isAbstractMatrix!Lhs && hasDynamicRows!Rhs)
1534             {
1535                 @property size_t rows() const { return this.lhs.inferSize(wild, rhs.rows).rows; }
1536                 private enum staticrows = wild;
1537             }
1538             else
1539                 static assert(0);
1540 
1541 
1542             static if(hasStaticCols!Rhs)
1543             {
1544                 enum cols = Rhs.cols;
1545                 private enum staticcols = cols;
1546             }
1547             else static if(isAbstractMatrix!Rhs && hasStaticCols!Lhs)
1548             {
1549                 enum cols = Rhs.inferSize(Lhs.cols, wild).cols;
1550                 private enum staticcols = cols;
1551             }
1552             else static if(hasDynamicRows!Rhs)
1553             {
1554                 @property size_t cols() const { return this.rhs.cols; }
1555                 private enum staticcols = wild;
1556             }
1557             else static if(isAbstractMatrix!Rhs && hasDynamicColumns!Lhs)
1558             {
1559                 @property size_t cols() const { return this.rhs.inferSize(lhs.cols, wild).cols; }
1560                 private enum staticcols = wild;
1561             }
1562             else
1563                 static assert(0);
1564         }
1565         else
1566         {
1567             static if(hasStaticRows!Lhs)
1568             {
1569                 enum rows = Lhs.rows;
1570                 private enum staticrows = rows;
1571             }
1572             else static if(hasStaticRows!Rhs)
1573             {
1574                 enum rows = Rhs.rows;
1575                 private enum staticrows = rows;
1576             }
1577             else static if(hasDynamicRows!Lhs)
1578             {
1579                 @property size_t rows() const { return this.lhs.rows; }
1580                 private enum staticrows = wild;
1581             }
1582             else
1583             {
1584                 @property size_t rows() const { return this.rhs.rows; }
1585                 private enum staticrows = wild;
1586             }
1587 
1588             static if(hasStaticCols!Lhs)
1589             {
1590                 enum cols = Lhs.cols;
1591                 private enum staticcols = cols;
1592             }
1593             else static if(hasStaticCols!Rhs)
1594             {
1595                 enum cols = Rhs.cols;
1596                 private enum staticcols = cols;
1597             }
1598             else static if(hasDynamicColumns!Lhs)
1599             {
1600                 @property size_t cols() const { return this.lhs.cols; }
1601                 private enum staticcols = wild;
1602             }
1603             else
1604             {
1605                 @property size_t cols() const { return this.rhs.cols; }
1606                 private enum staticcols = wild;
1607             }
1608         }
1609     }
1610     else static if(isMatrix!Lhs || isAbstractMatrix!Lhs)
1611     {
1612         static assert(!isAbstractMatrix!Lhs);
1613 
1614         static if(hasStaticRows!Lhs)
1615         {
1616             enum rows = Lhs.rows;
1617             private enum staticrows = rows;
1618         }
1619         else
1620         {
1621             @property size_t rows() const { return this.lhs.rows; }
1622             private enum staticrows = wild;
1623         }
1624 
1625         static if(hasStaticCols!Lhs)
1626         {
1627             enum cols = Lhs.cols;
1628             private enum staticcols = cols;
1629         }
1630         else
1631         {
1632             @property size_t cols() const { return this.lhs.cols; }
1633             private enum staticcols = wild;
1634         }
1635     }
1636     else
1637     {
1638         static assert(!isAbstractMatrix!Rhs);
1639 
1640         static if(hasStaticRows!Rhs)
1641         {
1642             enum rows = Rhs.rows;
1643             private enum staticrsght = rows;
1644         }
1645         else
1646         {
1647             @property size_t rows() const { return this.rhs.rows; }
1648             private enum staticrsght = wild;
1649         }
1650 
1651         static if(hasStaticCols!Rhs)
1652         {
1653             enum cols = Rhs.cols;
1654             private enum staticcsght = cols;
1655         }
1656         else
1657         {
1658             @property size_t cols() const { return this.rhs.cols; }
1659             private enum staticcsght = wild;
1660         }
1661     }
1662 
1663 
1664     auto opIndex(size_t i, size_t j) const
1665     in{
1666         assert(i < this.rows);
1667         assert(j < this.cols);
1668     }
1669     body{
1670       static if(etoSpec == ETOSpec.matrixAddMatrix)
1671         return this.lhs.at(i, j) + this.rhs.at(i, j);
1672       else static if(etoSpec == ETOSpec.matrixSubMatrix)
1673         return this.lhs.at(i, j) - this.rhs.at(i, j);
1674       else static if(etoSpec == ETOSpec.matrixMulMatrix)
1675       {
1676         auto sum = cast(Unqual!(typeof(this.lhs.at(0, 0) * this.rhs.at(0, 0))))0;
1677 
1678         static if(hasStaticCols!Lhs)
1679             immutable cnt = Lhs.cols;
1680         else static if(hasStaticRows!Rhs)
1681             immutable cnt = Rhs.rows;
1682         else static if(hasDynamicColumns!Lhs)
1683             immutable cnt = this.lhs.cols;
1684         else
1685             immutable cnt = this.rhs.rows;
1686 
1687         foreach(k; 0 .. cnt)
1688             sum += this.lhs.at(i, k) * this.rhs.at(k, j);
1689         return sum;
1690       }
1691       else
1692       {
1693         static if(isMatrix!Lhs || isAbstractMatrix!Lhs)
1694             return mixin("this.lhs.at(i, j) " ~ s ~ " this.rhs");
1695         else
1696             return mixin("this.lhs " ~ s ~ " this.rhs.at(i, j)");
1697       }
1698     }
1699 
1700     mixin(defaultExprOps!(false));
1701 
1702   private:
1703     Lhs lhs;
1704     Rhs rhs;
1705 }
1706 
1707 
1708 /// ditto
1709 auto matrixExpression(string s, A, B)(auto ref A a, auto ref B b)
1710 if(isValidOperator!(A, s, B))
1711 {
1712     return MatrixExpression!(A, s, B)(a, b);
1713     static assert(isNarrowMatrix!(MatrixExpression!(A, s, B))
1714                || isAbstractMatrix!(MatrixExpression!(A, s, B)));
1715 }
1716 
1717 
1718 /**
1719 specに示された演算子をオーバーロードします。specはETOSpecで指定する必要があります。
1720 */
1721 template ExpressionOperators(size_t spec, size_t rs, size_t cs)
1722 {
1723     enum stringMixin = 
1724     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1725     q{
1726         static if(is(typeof({enum _unused_ = this.rows;}))) static assert(rows != 0);
1727         static if(is(typeof({enum _unused_ = this.cols;}))) static assert(cols != 0);
1728 
1729         alias at = opIndex;
1730     } ~
1731 
1732 
1733     ( rs == 1 ?
1734     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1735     q{
1736         alias cols length;
1737         alias length opDollar;
1738 
1739 
1740         auto ref opIndex(size_t i) inout
1741         in{
1742             assert(i < this.cols);
1743         }
1744         body{
1745             return this[0, i];
1746         }
1747 
1748       static if(is(typeof({this[0, 0] = this[0, 0];})))
1749       {
1750         auto ref opIndexAssign(S)(S value, size_t i)
1751         if(is(typeof(this[0, i] = value)))
1752         in{
1753             assert(i < this.cols);
1754         }
1755         body{
1756             return this[0, i] = value;
1757         }
1758 
1759 
1760         auto ref opIndexOpAssign(string op, S)(S value, size_t i)
1761         if(is(typeof(mixin("this[0, i] " ~ op ~ "= value"))))
1762         in{
1763             assert(i < this.cols);
1764         }
1765         body{
1766             return mixin("this[0, i] " ~ op ~ "= value");
1767         }
1768       }
1769     } : ( cs == 1 ?
1770     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1771     q{
1772         alias rows length;
1773         alias length opDollar;
1774 
1775 
1776         auto ref opIndex(size_t i) inout
1777         in{
1778             assert(i < this.rows);
1779         }
1780         body{
1781             return this[i, 0];
1782         }
1783 
1784       static if(is(typeof({this[0, 0] = this[0, 0];})))
1785       {
1786         auto ref opIndexAssign(S)(S value, size_t i)
1787         if(is(typeof(this[i, 0] = value)))
1788         in{
1789             assert(i < this.rows);
1790         }
1791         body{
1792             return this[0, i] = value;
1793         }
1794 
1795 
1796         auto ref opIndexOpAssign(string op, S)(S value, size_t i)
1797         if(is(typeof(mixin("this[i, 0] " ~ op ~ "= value"))))
1798         in{
1799             assert(i < this.rows);
1800         }
1801         body{
1802             return mixin("this[i, 0] " ~ op ~ "= value");
1803         }
1804       }
1805     } : ""
1806     )) ~
1807 
1808 
1809     /*
1810     ((rs == 1 || cs == 1) && (spec & ETOSpec.opAssign) ?
1811     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1812     q{
1813         void opAssign(Array)(Array arr)
1814         if(!isNarrowMatrix!Array && is(typeof(arr[size_t.init])) && isAssignable!(typeof(this[size_t.init]), typeof(arr[size_t.init])))
1815         {
1816             foreach(i; 0 .. this.length)
1817                 this[i] = arr[i];
1818         }
1819     } : ""
1820     ) ~
1821     */
1822 
1823 
1824     (rs == 1 && cs == 1 ?
1825     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1826     q{
1827         auto det() const @property
1828         {
1829             return this[0, 0];
1830         }
1831 
1832         alias det this;
1833 
1834 
1835         auto ref opAssign(S)(S value)
1836         if(is(typeof(this[0, 0] = value)))
1837         {
1838             return this[0, 0] = value;
1839         }
1840 
1841 
1842         auto ref opOpAssign(S)(S value)
1843         if(is(typeof(mixin("this[0, 0] " ~ op ~ "= value"))))
1844         {
1845             return mixin("this[0, 0] " ~ op ~ "= value");
1846         }
1847     } : ""
1848     ) ~
1849 
1850 
1851     (spec & ETOSpec.opEquals ?
1852     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1853     q{
1854         bool opEquals(Rhs)(auto ref const Rhs mat) const
1855         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
1856         {
1857             static assert(isValidOperator!(Unqual!(typeof(this)), "+", Rhs));
1858 
1859             static if(isAbstractMatrix!Rhs)
1860             {
1861                 auto result = Rhs.inferSize(this.rows, this.cols);
1862                 if(!result.isValid)
1863                     return false;
1864             }
1865             else
1866             {
1867                 if(this.rows != mat.rows)
1868                     return false;
1869 
1870                 if(this.cols != mat.cols)
1871                     return false;
1872             }
1873 
1874             foreach(i; 0 .. this.rows)
1875                 foreach(j; 0 .. this.cols)
1876                     if(this[i, j] != mat.at(i, j))
1877                         return false;
1878             return true;
1879         }
1880     } : ""
1881     ) ~
1882 
1883 
1884     (spec & ETOSpec.toString ?
1885     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1886     q{
1887         @property
1888         void toString(scope void delegate(const(char)[]) sink, string formatString) const @system
1889         {
1890             sink.formattedWrite(formatString, this.toRange);
1891         }
1892     } : ""
1893     ) ~
1894 
1895 
1896     (spec & ETOSpec.opAssign ?
1897     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1898     q{
1899         void opAssign(M)(M m)
1900         if((isMatrix!M || isAbstractMatrix!M) && is(typeof(this[0, 0] = m.at(0, 0))))
1901         in{
1902             static if(isAbstractMatrix!M)
1903                 assert(m.inferSize(this.rows, this.cols).isValid);
1904             else
1905             {
1906                 assert(m.rows == this.rows);
1907                 assert(m.cols == this.cols);
1908             }
1909         }
1910         body{
1911             static assert(isValidOperator!(typeof(this), "=", M));
1912 
1913             foreach(i; 0 .. this.rows)
1914                 foreach(j; 0 .. this.cols)
1915                     this[i, j] = m.at(i, j);
1916         }
1917     } : ""
1918     ) ~
1919 
1920 
1921     (spec & ETOSpec.matrixAddMatrix ?
1922     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1923     q{
1924         auto opBinary(string op : "+", Rhs)(auto ref Rhs mat) const
1925         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
1926         in{
1927             static if(isAbstractMatrix!Rhs)
1928                 assert(mat.inferSize(this.rows, this.cols).isValid);
1929             else
1930             {
1931                 assert(mat.rows == this.rows);
1932                 assert(mat.cols == this.cols);
1933             }
1934         }
1935         body{
1936             static assert(isValidOperator!(typeof(this), op, Rhs));
1937             return matrixExpression!"+"(this, mat);
1938         }
1939     } : ""
1940     ) ~
1941 
1942 
1943     (spec & ETOSpec.matrixSubMatrix ?
1944     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1945     q{
1946         auto opBinary(string op : "-", Rhs)(auto ref Rhs mat) const
1947         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
1948         in{
1949             static if(isAbstractMatrix!Rhs)
1950                 assert(mat.inferSize(this.rows, this.cols).isValid);
1951             else
1952             {
1953                 assert(mat.rows == this.rows);
1954                 assert(mat.cols == this.cols);
1955             }
1956         }
1957         body{
1958             static assert(isValidOperator!(typeof(this), op, Rhs));
1959             return matrixExpression!"-"(this, mat);
1960         }
1961     } : ""
1962     ) ~
1963 
1964 
1965     (spec & ETOSpec.matrixMulMatrix ?
1966     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1967     q{
1968         auto opBinary(string op : "*", Rhs)(auto ref Rhs mat) const
1969         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
1970         in{
1971             static if(isAbstractMatrix!Rhs)
1972                 assert(mat.inferSize(this.cols, wild).isValid);
1973             else
1974                 assert(mat.rows == this.cols);
1975         }
1976         body{
1977             static assert(isValidOperator!(typeof(this), op, Rhs));
1978             return matrixExpression!"*"(this, mat);
1979         }
1980     } : ""
1981     ) ~
1982 
1983 
1984     (spec & ETOSpec.matrixAddScalar ?
1985     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1986     q{
1987         auto opBinary(string op : "+", S)(S s) const
1988         if(isNotVectorOrMatrix!S)
1989         {
1990             static assert(isValidOperator!(typeof(this), op, S));
1991             return matrixExpression!"+"(this, s);
1992         }
1993     } : ""
1994     ) ~
1995 
1996 
1997     (spec & ETOSpec.scalarAddMatrix ?
1998     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
1999     q{
2000         auto opBinaryRight(string op : "+", S)(S s) const
2001         if(isNotVectorOrMatrix!S)
2002         {
2003             static assert(isValidOperator!(S, op, typeof(this)));
2004             return matrixExpression!"+"(s, this);
2005         }
2006     } : ""
2007     ) ~
2008 
2009 
2010     (spec & ETOSpec.matrixSubScalar ?
2011     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2012     q{
2013         auto opBinary(string op : "-", S)(S s) const
2014         if(isNotVectorOrMatrix!S)
2015         {
2016             static assert(isValidOperator!(typeof(this), op, S));
2017             return matrixExpression!"-"(this, s);
2018         }
2019     } : ""
2020     ) ~
2021 
2022 
2023     (spec & ETOSpec.scalarSubMatrix ?
2024     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2025     q{
2026         auto opBinaryRight(string op : "-", S)(S s) const
2027         if(isNotVectorOrMatrix!S)
2028         {
2029             static assert(isValidOperator!(S, op, typeof(this)));
2030             return matrixExpression!"-"(s, this);
2031         }
2032     } : ""
2033     ) ~
2034 
2035 
2036     (spec & ETOSpec.matrixMulScalar ?
2037     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2038     q{
2039         auto opBinary(string op : "*", S)(S s) const
2040         if(isNotVectorOrMatrix!S)
2041         {
2042             static assert(isValidOperator!(typeof(this), op, S));
2043             return matrixExpression!"*"(this, s);
2044         }
2045     } : ""
2046     ) ~
2047 
2048 
2049     (spec & ETOSpec.scalarMulMatrix ?
2050     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2051     q{
2052         auto opBinaryRight(string op : "*", S)(S s) const
2053         if(isNotVectorOrMatrix!S)
2054         {
2055             static assert(isValidOperator!(S, op, typeof(this)));
2056             return matrixExpression!"*"(s, this);
2057         }
2058     } : ""
2059     ) ~
2060 
2061 
2062     (spec & ETOSpec.matrixDivScalar ?
2063     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2064     q{
2065         auto opBinary(string op : "/", S)(S s) const
2066         if(isNotVectorOrMatrix!S)
2067         {
2068             static assert(isValidOperator!(typeof(this), op, S));
2069             return matrixExpression!"/"(this, s);
2070         }
2071     } : ""
2072     ) ~
2073 
2074 
2075     (spec & ETOSpec.scalarDivMatrix ?
2076     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2077     q{
2078         auto opBinaryRight(string op : "/", S)(S s) const
2079         if(isNotVectorOrMatrix!S)
2080         {
2081             static assert(isValidOperator!(S, op, typeof(this)));
2082             return matrixExpression!"/"(s, this);
2083         }
2084     } : ""
2085     ) ~ 
2086 
2087 
2088     (spec & ETOSpec.addScalar ?
2089     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2090     q{
2091         void opOpAssign(string op : "+", S)(S scalar)
2092         if(is(typeof(this[0, 0] += scalar)))
2093         {
2094             foreach(r; 0 .. rows)
2095                 foreach(c; 0 .. cols)
2096                     this[r, c] +=  scalar;
2097         }
2098     } : ""
2099     ) ~
2100 
2101 
2102     (spec & ETOSpec.subScalar ?
2103     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2104     q{
2105         void opOpAssign(string op : "-", S)(S scalar)
2106         if(is(typeof(this[0, 0] -= scalar)))
2107         {
2108             foreach(r; 0 .. rows)
2109                 foreach(c; 0 .. cols)
2110                     this[r, c] -=  scalar;
2111         }
2112     } : ""
2113     ) ~
2114 
2115 
2116     (spec & ETOSpec.mulScalar ?
2117     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2118     q{
2119         void opOpAssign(string op : "*", S)(S scalar)
2120         if(is(typeof(this[0, 0] *= scalar)))
2121         {
2122             foreach(r; 0 .. rows)
2123                 foreach(c; 0 .. cols)
2124                     this[r, c] *=  scalar;
2125         }
2126     } : ""
2127     ) ~
2128 
2129 
2130     (spec & ETOSpec.divScalar ?
2131     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2132     q{
2133         void opOpAssign(string op : "/", S)(S scalar)
2134         if(is(typeof(this[0, 0] /= scalar)))
2135         {
2136             foreach(r; 0 .. rows)
2137                 foreach(c; 0 .. cols)
2138                     this[r, c] /=  scalar;
2139         }
2140     } : ""
2141     ) ~
2142 
2143 
2144     ((spec & ETOSpec.swizzle) && (rs == 1 || cs == 1) ? 
2145         (rs*cs >= 1 ?
2146         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2147         q{
2148             auto ref a() inout @property { return this[0]; }
2149             alias x = a;
2150             alias r = a;
2151             alias re = a;
2152         } : ""
2153         ) ~ 
2154         (rs*cs >= 2 ?
2155         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2156         q{
2157             auto ref b() inout @property { return this[1]; }
2158             alias y = b;
2159             alias im = b;
2160             alias i = b;
2161         } : ""
2162         ) ~ 
2163         (rs*cs >= 3 ?
2164         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2165         q{
2166             auto ref c() inout @property { return this[2]; }
2167             alias z = c;
2168             alias j = c;
2169         } : ""
2170         ) ~ 
2171         (rs*cs >= 4 ?
2172         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2173         q{
2174             auto ref d() inout @property { return this[3]; }
2175             alias k = d;
2176             alias w = d;
2177         } : ""
2178         ) ~ 
2179         (rs*cs >= 5 ?
2180         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2181         q{
2182             auto ref e() inout @property { return this[4]; }
2183         } : ""
2184         ) ~ 
2185         (rs*cs >= 6 ?
2186         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2187         q{
2188             auto ref f() inout @property { return this[5]; }
2189         } : ""
2190         ) ~ 
2191         (rs*cs >= 7 ?
2192         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2193         q{
2194             auto ref g() inout @property { return this[6]; }
2195         } : ""
2196         ) ~ 
2197         (rs*cs >= 8 ?
2198         format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2199         q{
2200             auto ref h() inout @property { return this[7]; }
2201         } : ""
2202         ) : ""
2203     );
2204 
2205 
2206     mixin template templateMixin()
2207     {
2208         mixin(stringMixin);
2209     }
2210 }
2211 
2212 
2213 /// ditto
2214 template ExpressionOperatorsInferable(size_t spec)
2215 {
2216     enum stringMixin = 
2217     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2218     q{
2219         alias at = opIndex;
2220     } ~
2221 
2222 
2223     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2224     q{
2225         bool opEquals(Rhs)(auto ref in Rhs mat) const
2226         if(isMatrix!Rhs && !is(Unqual!Rhs == typeof(this)) && !isAbstractMatrix!(Rhs))
2227         {
2228             static assert(isValidOperator!(Unqual!(typeof(this)), "+", Rhs));
2229 
2230             if(!this.inferSize(mat.rows, mat.cols).isValid)
2231                 return false;
2232 
2233             foreach(i; 0 .. mat.rows)
2234                 foreach(j; 0 .. mat.cols)
2235                     if(this[i, j] != mat.at(i, j))
2236                         return false;
2237             return true;
2238         }
2239     } ~
2240 
2241 
2242     (spec & ETOSpec.matrixAddMatrix ?
2243     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2244     q{
2245         auto opBinary(string op : "+", Rhs)(auto ref const Rhs mat) const
2246         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
2247         in{
2248             static if(!isAbstractMatrix!Rhs)
2249                 assert(this.inferSize(mat.rows, mat.cols).isValid);
2250         }
2251         body{
2252             static assert(isValidOperator!(typeof(this), op, Rhs));
2253             return matrixExpression!"+"(this, mat);
2254         }
2255     } : ""
2256     ) ~
2257 
2258 
2259     (spec & ETOSpec.matrixSubMatrix ?
2260     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2261     q{
2262         auto opBinary(string op : "-", Rhs)(auto ref const Rhs mat) const
2263         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
2264         in{
2265             static if(!isAbstractMatrix!Rhs)
2266                 assert(this.inferSize(mat.rows, mat.cols).isValid);
2267         }
2268         body{
2269             static assert(isValidOperator!(typeof(this), op, Rhs));
2270             return matrixExpression!"-"(this, mat);
2271         }
2272     } : ""
2273     ) ~
2274 
2275 
2276     (spec & ETOSpec.matrixMulMatrix ?
2277     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2278     q{
2279         auto opBinary(string op : "*", Rhs)(auto ref const Rhs mat) const
2280         if(isMatrix!Rhs || isAbstractMatrix!Rhs)
2281         in{
2282             static if(!isAbstractMatrix!Rhs)
2283                 assert(this.inferSize(wild, mat.rows).isValid);
2284         }
2285         body{
2286             static assert(isValidOperator!(typeof(this), op, Rhs));
2287             return matrixExpression!"*"(this, mat);
2288         }
2289     } : ""
2290     ) ~
2291 
2292 
2293     (spec & ETOSpec.matrixAddScalar ?
2294     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2295     q{
2296         auto opBinary(string op : "+", S)(const S s) const
2297         if(isNotVectorOrMatrix!S)
2298         {
2299             static assert(isValidOperator!(typeof(this), op, S));
2300             return matrixExpression!"+"(this, s);
2301         }
2302     } : ""
2303     ) ~
2304 
2305 
2306     (spec & ETOSpec.scalarAddMatrix ?
2307     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2308     q{
2309         auto opBinaryRight(string op : "+", S)(const S s) const
2310         if(isNotVectorOrMatrix!S)
2311         {
2312             static assert(isValidOperator!(S, op, typeof(this)));
2313             return matrixExpression!"+"(s, this);
2314         }
2315     } : ""
2316     ) ~
2317 
2318 
2319     (spec & ETOSpec.matrixSubScalar ?
2320     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2321     q{
2322         auto opBinary(string op : "-", S)(const S s) const
2323         if(isNotVectorOrMatrix!S)
2324         {
2325             static assert(isValidOperator!(typeof(this), op, S));
2326             return matrixExpression!"-"(this, s);
2327         }
2328     } : ""
2329     ) ~
2330 
2331 
2332     (spec & ETOSpec.scalarSubMatrix ?
2333     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2334     q{
2335         auto opBinaryRight(string op : "-", S)(const S s) const
2336         if(isNotVectorOrMatrix!S)
2337         {
2338             static assert(isValidOperator!(S, op, typeof(this)));
2339             return matrixExpression!"-"(s, this);
2340         }
2341     } : ""
2342     ) ~
2343 
2344 
2345     (spec & ETOSpec.matrixMulScalar ?
2346     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2347     q{
2348         auto opBinary(string op : "*", S)(const S s) const
2349         if(isNotVectorOrMatrix!S)
2350         {
2351             static assert(isValidOperator!(typeof(this), op, S));
2352             return matrixExpression!"*"(this, s);
2353         }
2354     } : ""
2355     ) ~
2356 
2357 
2358     (spec & ETOSpec.scalarMulMatrix ?
2359     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2360     q{
2361         auto opBinaryRight(string op : "*", S)(const S s) const
2362         if(isNotVectorOrMatrix!S)
2363         {
2364             static assert(isValidOperator!(S, op, typeof(this)));
2365             return matrixExpression!"*"(s, this);
2366         }
2367     } : ""
2368     ) ~
2369 
2370 
2371     (spec & ETOSpec.matrixDivScalar ?
2372     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2373     q{
2374         auto opBinary(string op : "/", S)(const S s) const
2375         if(isNotVectorOrMatrix!S)
2376         {
2377             static assert(isValidOperator!(typeof(this), op, S));
2378             return matrixExpression!"/"(this, s);
2379         }
2380     } : ""
2381     ) ~
2382 
2383     (spec & ETOSpec.scalarDivMatrix ?
2384     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2385     q{
2386         auto opBinaryRight(string op : "/", S)(const S s) const
2387         if(isNotVectorOrMatrix!S)
2388         {
2389             static assert(isValidOperator!(S, op, typeof(this)));
2390             return matrixExpression!"/"(s, this);
2391         }
2392     } : ""
2393     ) ~
2394 
2395 
2396     (spec & ETOSpec.addScalar ?
2397     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2398     q{
2399         void opOpAssign(string op : "+", S)(const S scalar)
2400         if(isNotVectorOrMatrix!S && is(typeof(this[0, 0] += scalar)))
2401         {
2402             foreach(r; 0 .. rows)
2403                 foreach(c; 0 .. cols)
2404                     this[r, c] +=  scalar;
2405         }
2406     } : ""
2407     ) ~
2408 
2409 
2410     (spec & ETOSpec.subScalar ?
2411     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2412     q{
2413         void opOpAssign(string op : "-", S)(const S scalar)
2414         if(isNotVectorOrMatrix!S && is(typeof(this[0, 0] -= scalar)))
2415         {
2416             foreach(r; 0 .. rows)
2417                 foreach(c; 0 .. cols)
2418                     this[r, c] -=  scalar;
2419         }
2420     } : ""
2421     ) ~
2422 
2423 
2424     (spec & ETOSpec.mulScalar ?
2425     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2426     q{
2427         void opOpAssign(string op : "*", S)(const S scalar)
2428         if(isNotVectorOrMatrix!S && is(typeof(this[0, 0] *= scalar)))
2429         {
2430             foreach(r; 0 .. rows)
2431                 foreach(c; 0 .. cols)
2432                     this[r, c] *=  scalar;
2433         }
2434     } : ""
2435     ) ~
2436 
2437 
2438     (spec & ETOSpec.divScalar ?
2439     format(`#line %s "%s"`, __LINE__+2, __FILE__) ~
2440     q{
2441         void opOpAssign(string op : "+", S)(const S scalar)
2442         if(isNotVectorOrMatrix!S && is(typeof(this[0, 0] /= scalar)))
2443         {
2444             foreach(r; 0 .. rows)
2445                 foreach(c; 0 .. cols)
2446                     this[r, c] /=  scalar;
2447         }
2448     } : ""
2449     );
2450 
2451 
2452     mixin template templateMixin()
2453     {
2454         mixin(stringMixin);
2455     }
2456 }
2457 
2458 
2459 /**
2460 全ての演算子をオーバーロードします。
2461 */
2462 template defaultExprOps(bool isInferable = false)
2463 {
2464     enum defaultExprOps = 
2465     isInferable ?
2466     q{
2467         mixin(ExpressionOperatorsInferable!(ETOSpec.all).stringMixin);
2468         //mixin(ExpressionOperatorsInferable!(ETOSpec.all & ~ETOSpec.opEquals & ~ETOSpec.toString).stringMixin);
2469         //mixin(ExpressionOperatorsInferable!(ETOSpec.modifiedOperator).stringMixin);
2470         //const{mixin(ExpressionOperatorsInferable!(ETOSpec.all & ~ETOSpec.modifiedOperator).stringMixin);}
2471         //immutable{mixin(ExpressionOperatorsInferable!(ETOSpec.all & ~ETOSpec.opEquals & ~ETOSpec.toString).stringMixin);}
2472     }
2473     :
2474     q{
2475         mixin(ExpressionOperators!(ETOSpec.all, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
2476         //mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.opEquals & ~ETOSpec.toString, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
2477         //mixin(ExpressionOperators!(ETOSpec.modifiedOperator, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
2478         //const{mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.modifiedOperator, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);}
2479         //immutable{mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.opEquals & ~ETOSpec.toString, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);}
2480     };
2481 }
2482 
2483 
2484 unittest{
2485     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2486     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2487 
2488 
2489     static struct M(size_t rs, size_t cs)
2490     {
2491         enum rows = rs;
2492         enum cols = cs;
2493 
2494         size_t opIndex(size_t i, size_t j) inout {return i + j;}
2495 
2496         //inout:
2497         mixin(defaultExprOps!(false));
2498     }
2499 
2500 
2501     alias S3 = M!(3, 3);
2502     alias S23 = M!(2, 3);
2503 
2504     static assert(isNarrowMatrix!S3);
2505     static assert(hasStaticRows!S3);
2506     static assert(hasStaticCols!S3);
2507     static assert(isNarrowMatrix!S23);
2508     static assert(hasStaticRows!S23);
2509     static assert(hasStaticCols!S23);
2510 
2511 
2512     M!(1, 1) m11;
2513     static assert(isNarrowMatrix!(typeof(m11)));
2514     size_t valueM11 = m11;
2515 
2516     M!(3, 1) m31;
2517     M!(1, 3) m13;
2518     valueM11 = m13 * m31;
2519 
2520 
2521     // swizzle
2522     M!(1, 8) m18;
2523     assert(m18[0] == m18.a);
2524     assert(m18[1] == m18.b);
2525     assert(m18[2] == m18.c);
2526     assert(m18[3] == m18.d);
2527     assert(m18[4] == m18.e);
2528     assert(m18[5] == m18.f);
2529     assert(m18[6] == m18.g);
2530     assert(m18[7] == m18.h);
2531 
2532     assert(m18[0] == m18.r);
2533     assert(m18[1] == m18.i);
2534     assert(m18[2] == m18.j);
2535     assert(m18[3] == m18.k);
2536 
2537     assert(m18[0] == m18.x);
2538     assert(m18[1] == m18.y);
2539     assert(m18[2] == m18.z);
2540     assert(m18[3] == m18.w);
2541 
2542     assert(m18[0] == m18.re);
2543     assert(m18[1] == m18.im);
2544 
2545 
2546     static struct I
2547     {
2548         size_t opIndex(size_t i, size_t j) inout { return i == j ? 1  : 0;}
2549         alias at = opIndex;
2550 
2551         static InferredResult inferSize(Msize_t r, Msize_t c)
2552         {
2553             if(r == wild && c == wild)
2554                 return InferredResult(false);
2555             else if(r == c || r == wild || c == wild)
2556                 return InferredResult(true, max(r, c), max(r, c));
2557             else
2558                 return InferredResult(false);
2559         }
2560 
2561         mixin(defaultExprOps!(true));
2562     }
2563 
2564     //static assert(isNarrowMatrix!I);
2565     static assert(isAbstractMatrix!I);
2566     static assert( I.inferSize(wild, 1).isValid);
2567     static assert( I.inferSize(3, 3).isValid);
2568     static assert(!I.inferSize(1, 3).isValid);
2569 
2570 
2571     static struct D{
2572         size_t rows;
2573         size_t cols;
2574 
2575         size_t opIndex(size_t i, size_t j) inout {return i + j;}
2576 
2577         mixin(defaultExprOps!(false));
2578     }
2579     static assert(isNarrowMatrix!D);
2580     static assert(hasDynamicRows!D);
2581     static assert(hasDynamicColumns!D);
2582 
2583 
2584     S3 a;
2585     auto add = a + a;
2586     static assert(isNarrowMatrix!(typeof(add)));
2587     static assert(hasStaticRows!(typeof(add)));
2588     static assert(hasStaticCols!(typeof(add)));
2589     assert(add[0, 0] == 0); assert(add[0, 1] == 2); assert(add[0, 2] == 4);
2590     assert(add[1, 0] == 2); assert(add[1, 1] == 4); assert(add[1, 2] == 6);
2591     assert(add[2, 0] == 4); assert(add[2, 1] == 6); assert(add[2, 2] == 8);
2592 
2593     auto mul = a * a;
2594     static assert(isNarrowMatrix!(typeof(mul)));
2595     static assert(hasStaticRows!(typeof(mul)));
2596     static assert(hasStaticCols!(typeof(mul)));
2597     assert(mul[0, 0] == 5); assert(mul[0, 1] == 8); assert(mul[0, 2] ==11);
2598     assert(mul[1, 0] == 8); assert(mul[1, 1] ==14); assert(mul[1, 2] ==20);
2599     assert(mul[2, 0] ==11); assert(mul[2, 1] ==20); assert(mul[2, 2] ==29);
2600 
2601     auto sadd = a + 3;
2602     static assert(isNarrowMatrix!(typeof(sadd)));
2603     static assert(hasStaticRows!(typeof(sadd)));
2604     static assert(hasStaticCols!(typeof(sadd)));
2605     assert(sadd[0, 0] == 3); assert(sadd[0, 1] == 4); assert(sadd[0, 2] == 5);
2606     assert(sadd[1, 0] == 4); assert(sadd[1, 1] == 5); assert(sadd[1, 2] == 6);
2607     assert(sadd[2, 0] == 5); assert(sadd[2, 1] == 6); assert(sadd[2, 2] == 7);
2608 
2609     // auto addMasS = a + m11;
2610 
2611     auto add5 = a + a + cast(const)(a) * 3;
2612     static assert(isNarrowMatrix!(typeof(add5)));
2613     static assert(hasStaticRows!(typeof(add5)));
2614     static assert(hasStaticCols!(typeof(add5)));
2615     assert(add5 == a * 5);
2616 
2617     I i;
2618     auto addi = a + i;
2619     static assert(isNarrowMatrix!(typeof(addi)));
2620     static assert(hasStaticRows!(typeof(addi)));    static assert(typeof(addi).rows == 3);
2621     static assert(hasStaticCols!(typeof(addi))); static assert(typeof(addi).cols == 3);
2622     assert(addi[0, 0] == 1); assert(addi[0, 1] == 1); assert(addi[0, 2] == 2);
2623     assert(addi[1, 0] == 1); assert(addi[1, 1] == 3); assert(addi[1, 2] == 3);
2624     assert(addi[2, 0] == 2); assert(addi[2, 1] == 3); assert(addi[2, 2] == 5);
2625 
2626     auto i2 = i * 2;
2627     static assert(!isNarrowMatrix!(typeof(i2)));
2628     static assert(isAbstractMatrix!(typeof(i2)));
2629     static assert( typeof(i2).inferSize(wild, 1).isValid);
2630     static assert( typeof(i2).inferSize(3, 3).isValid);
2631     static assert(!typeof(i2).inferSize(1, 3).isValid);
2632 
2633     auto addi2 = a + i2;
2634     static assert(isNarrowMatrix!(typeof(addi2)));
2635     static assert(hasStaticRows!(typeof(addi2)));    static assert(typeof(addi2).rows == 3);
2636     static assert(hasStaticCols!(typeof(addi2))); static assert(typeof(addi2).cols == 3);
2637     assert(addi2[0, 0] == 2); assert(addi2[0, 1] == 1); assert(addi2[0, 2] == 2);
2638     assert(addi2[1, 0] == 1); assert(addi2[1, 1] == 4); assert(addi2[1, 2] == 3);
2639     assert(addi2[2, 0] == 2); assert(addi2[2, 1] == 3); assert(addi2[2, 2] == 6);
2640 
2641     static assert(!is(typeof(S23.init + i)));
2642     static assert(!is(typeof(i + S23.init)));
2643     assert(S23.init * i == S23.init);
2644     assert(i * S23.init == S23.init);
2645 
2646 
2647     import core.exception, std.exception;
2648 
2649     D d33 = D(3, 3);
2650     auto addsd = a + d33;
2651     static assert(isNarrowMatrix!(typeof(addsd)));
2652     static assert(hasStaticRows!(typeof(addsd)));
2653     static assert(hasStaticCols!(typeof(addsd)));
2654     assert(addsd == a * 2);
2655     assert(addsd == d33 * 2);
2656 
2657     auto addsdr = d33 + a;
2658     static assert(isNarrowMatrix!(typeof(addsdr)));
2659     static assert(hasStaticRows!(typeof(addsdr)));
2660     static assert(hasStaticCols!(typeof(addsdr)));
2661     assert(addsdr == addsd);
2662     assert(addsdr == addsd);
2663 
2664     version(Release){}else assert(collectException!AssertError(D(2, 3) + a));
2665     version(Release){}else assert(collectException!AssertError(D(2, 3) + i));
2666     assert(D(2, 3) * i == D(2, 3));
2667 
2668     version(Release){}else assert(collectException!AssertError(D(2, 3) + D(2, 2)));
2669     version(Release){}else assert(collectException!AssertError(D(2, 3) + D(3, 3)));
2670     assert((D(2, 3) + D(2, 3)).rows == 2);
2671     assert((D(2, 3) + D(2, 3)).cols == 3);
2672     assert((D(2, 3) * D(3, 4)).rows == 2);
2673     assert((D(2, 3) * D(3, 4)).cols == 4);
2674 
2675     auto mulds = d33 * 3;
2676     assert(mulds == d33 + d33 + d33);
2677 }
2678 
2679 
2680 /**
2681 InferableMatrixをある大きさの行列へ固定します。
2682 */
2683 auto congeal(Msize_t rs, Msize_t cs, A)(A mat)
2684 if(isAbstractMatrix!A && A.inferSize(rs, cs).isValid)
2685 {
2686     static struct Result()
2687     {
2688         enum size_t rows = A.inferSize(rs, cs).rows;
2689         enum size_t cols = A.inferSize(rs, cs).cols;
2690 
2691         auto ref opIndex(size_t i, size_t j) inout
2692         in{
2693             assert(i < rows);
2694             assert(j < cols);
2695         }
2696         body{
2697             return _mat[i, j];
2698         }
2699 
2700 
2701       static if(carbon.linear.hasAssignableElements!A)
2702       {
2703         void opIndexAssign(E)(E e, size_t i, size_t j)
2704         in{
2705             assert(i < rows);
2706             assert(j < cols);
2707         }
2708         body{
2709             _mat[i, j] = e;
2710         }
2711       }
2712 
2713         mixin(defaultExprOps!(false));
2714 
2715       private:
2716         A _mat;
2717     }
2718 
2719     return Result!()(mat);
2720 }
2721 
2722 ///
2723 unittest{
2724     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2725     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2726 
2727 
2728     static struct I{
2729 
2730         size_t opIndex(size_t i, size_t j) inout { return i == j ? 1  : 0;}
2731 
2732         static InferredResult inferSize(Msize_t r, Msize_t c)
2733         {
2734             if(r == wild && c == wild)
2735                 return InferredResult(false);
2736             else if(isEqOrEitherEqX(r, c, wild))
2737                 return InferredResult(true, max(r, c), max(r, c));
2738             else
2739                 return InferredResult(false);
2740         }
2741 
2742         mixin(defaultExprOps!(true));
2743     }
2744 
2745     static assert(!isNarrowMatrix!I);
2746     static assert(isAbstractMatrix!I);
2747     static assert( I.inferSize(wild, 1).isValid);
2748     static assert( I.inferSize(3, 3).isValid);
2749     static assert(!I.inferSize(1, 3).isValid);
2750 
2751     I id;
2752     auto i3x3 = id.congeal!(3, 3)();
2753     static assert(isNarrowMatrix!(typeof(i3x3)));
2754     static assert(hasStaticRows!(typeof(i3x3)));
2755     static assert(hasStaticCols!(typeof(i3x3)));
2756     static assert(i3x3.rows == 3);
2757     static assert(i3x3.cols == 3);
2758     assert(i3x3[0, 0] == 1);assert(i3x3[1, 0] == 0);assert(i3x3[2, 0] == 0);
2759     assert(i3x3[0, 1] == 0);assert(i3x3[1, 1] == 1);assert(i3x3[2, 1] == 0);
2760     assert(i3x3[0, 2] == 0);assert(i3x3[1, 2] == 0);assert(i3x3[2, 2] == 1);
2761 }
2762 
2763 
2764 /// ditto
2765 auto congeal(A)(auto ref A mat, size_t r, size_t c)
2766 if(isAbstractMatrix!A)
2767 in{
2768     assert(A.inferSize(r, c).isValid);
2769 }
2770 body{
2771     static struct Result()
2772     {
2773         @property size_t rows() const { return _rs; }
2774         @property size_t cols() const { return _cs; }
2775 
2776         auto ref opIndex(size_t i, size_t j) inout
2777         in{
2778             assert(i < rows);
2779             assert(j < cols);
2780         }
2781         body{
2782             return _mat[i, j];
2783         }
2784 
2785 
2786       static if(carbon.linear.hasAssignableElements!A)
2787       {
2788         void opIndexAssign(E)(E e, size_t i, size_t j)
2789         in{
2790             assert(i < rows);
2791             assert(j < cols);
2792         }
2793         body{
2794             _mat[i, j] = e;
2795         }
2796       }
2797 
2798         mixin(defaultExprOps!(false));
2799 
2800         size_t _rs, _cs;
2801         A _mat;
2802     }
2803 
2804 
2805     return Result!()(r, c, mat);
2806 }
2807 
2808 
2809 ///
2810 unittest{
2811     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2812     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2813 
2814 
2815     static struct I{
2816 
2817         size_t opIndex(size_t i, size_t j) inout { return i == j ? 1  : 0;}
2818 
2819         static InferredResult inferSize(Msize_t r, Msize_t c)
2820         {
2821             if(r == wild && c == wild)
2822                 return InferredResult(false);
2823             else if(isEqOrEitherEqX(r, c, wild))
2824                 return InferredResult(true, max(r, c), max(r, c));
2825             else
2826                 return InferredResult(false);
2827         }
2828 
2829         mixin(defaultExprOps!(true));
2830     }
2831 
2832     static assert(!isNarrowMatrix!I);
2833     static assert(isAbstractMatrix!I);
2834     static assert( I.inferSize(wild, 1).isValid);
2835     static assert( I.inferSize(3, 3).isValid);
2836     static assert(!I.inferSize(1, 3).isValid);
2837 
2838     I id;
2839     auto i3x3 = id.congeal(3, 3);
2840     static assert(isNarrowMatrix!(typeof(i3x3)));
2841     static assert(hasDynamicRows!(typeof(i3x3)));
2842     static assert(hasDynamicColumns!(typeof(i3x3)));
2843     assert(i3x3.rows == 3);
2844     assert(i3x3.cols == 3);
2845     assert(i3x3[0, 0] == 1);assert(i3x3[1, 0] == 0);assert(i3x3[2, 0] == 0);
2846     assert(i3x3[0, 1] == 0);assert(i3x3[1, 1] == 1);assert(i3x3[2, 1] == 0);
2847     assert(i3x3[0, 2] == 0);assert(i3x3[1, 2] == 0);assert(i3x3[2, 2] == 1);
2848 }
2849 
2850 
2851 /**
2852 DynamicMatrixをある大きさへ固定します。
2853 */
2854 auto congeal(Msize_t rs, Msize_t cs, A)(auto ref A mat)
2855 //if(!isAbstractMatrix!A && (hasDynamicRows!A || rs == A.rows) || (hasDynamicColumns!A || cs == A.cols))
2856 if(is(typeof({
2857     static assert(!isAbstractMatrix!A);
2858   static if(hasStaticRows!A)
2859     static assert(rs == staticRows!A);
2860   static if(hasStaticCols!A)
2861     static assert(cs == staticCols!A);
2862   })))
2863 in{
2864     assert(mat.rows == rs);
2865     assert(mat.cols == cs);
2866 }
2867 body{
2868     static struct Result()
2869     {
2870         enum rows = rs;
2871         enum cols = cs;
2872 
2873 
2874         auto ref opIndex(size_t i, size_t j) inout
2875         in{
2876             assert(i < rows);
2877             assert(j < cols);
2878         }
2879         body{
2880             return _mat[i, j];
2881         }
2882 
2883 
2884         static if(carbon.linear.hasAssignableElements!A)
2885         {
2886           void opIndexAssign(E)(E e, size_t i, size_t j)
2887           in{
2888               assert(i < rows);
2889               assert(j < cols);
2890           }
2891           body{
2892               _mat[i, j] = e;
2893           }
2894         }
2895 
2896 
2897         mixin(defaultExprOps!(false));
2898 
2899       private:
2900         A _mat;
2901     }
2902 
2903     return Result!()(mat);
2904 }
2905 
2906 
2907 /// ditto
2908 unittest{
2909     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2910     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
2911 
2912 
2913     static struct D{
2914         size_t rows;
2915         size_t cols;
2916 
2917         size_t opIndex(size_t i, size_t j) inout {return i + j;}
2918 
2919         mixin(defaultExprOps!(false));
2920     }
2921     static assert(isNarrowMatrix!D);
2922     static assert(hasDynamicRows!D);
2923     static assert(hasDynamicColumns!D);
2924 
2925     D d3x3 = D(3, 3);
2926     auto s3x3 = d3x3.congeal!(3, 3)();
2927     static assert(isNarrowMatrix!(typeof(s3x3)));
2928     static assert(s3x3.rows == 3);
2929     static assert(s3x3.cols == 3);
2930     assert(s3x3[0, 0] == 0); assert(s3x3[1, 0] == 1); assert(s3x3[2, 0] == 2);
2931     assert(s3x3[0, 1] == 1); assert(s3x3[1, 1] == 2); assert(s3x3[2, 1] == 3);
2932     assert(s3x3[0, 2] == 2); assert(s3x3[1, 2] == 3); assert(s3x3[2, 2] == 4);
2933 }
2934 
2935 
2936 ///
2937 auto matrix(size_t rs, size_t cs, alias f, S...)(S sizes)
2938 if(is(typeof(f(0, 0))) && S.length == ((rs == 0) + (cs == 0)) && (S.length == 0 || is(CommonType!S : size_t)))
2939 {
2940     static struct Result()
2941     {
2942       static if(rs)
2943         enum rows = rs;
2944       else{
2945         private size_t _rs;
2946         @property size_t rows() const { return _rs; }
2947       }
2948 
2949       static if(cs)
2950         enum cols = cs;
2951       else{
2952         private size_t _cs;
2953         @property size_t cols() const { return _cs; }
2954       }
2955 
2956 
2957         auto ref opIndex(size_t i, size_t j) const
2958         in{
2959             assert(i < rows);
2960             assert(j < cols);
2961         }
2962         body{
2963             return f(i, j);
2964         }
2965 
2966 
2967         mixin(defaultExprOps!(false));
2968     }
2969 
2970     static if(S.length == 0)
2971       return Result!()();
2972     else static if(S.length == 1)
2973       return Result!()(sizes[0]);
2974     else static if(S.length == 2)
2975       return Result!()(sizes[0], sizes[1]);
2976 }
2977 
2978 
2979 auto matrix(alias f)(size_t r, size_t c)
2980 if(is(typeof(f(0, 0))))
2981 {
2982     return matrix!(0, 0, f)(r, c);
2983 }
2984 
2985 
2986 unittest{
2987     auto m = matrix!(2, 3, (i, j) => i * 3 + j);
2988     static assert(isNarrowMatrix!(typeof(m)));
2989     static assert(hasStaticRows!(typeof(m)));
2990     static assert(hasStaticCols!(typeof(m)));
2991     static assert(m.rows == 2);
2992     static assert(m.cols == 3);
2993     assert(m[0, 0] == 0); assert(m[0, 1] == 1); assert(m[0, 2] == 2);
2994     assert(m[1, 0] == 3); assert(m[1, 1] == 4); assert(m[1, 2] == 5);
2995 
2996 
2997     auto md = matrix!((i, j) => i * 3 + j)(2, 3);
2998     assert(m == md);
2999 }
3000 
3001 
3002 auto matrix(alias f)()
3003 {
3004     static struct Result()
3005     {
3006 
3007 
3008         static InferredResult inferSize(Msize_t r, Msize_t c)
3009         {
3010             if(r == wild && c == wild)
3011                 return  InferredResult(false);
3012             else if(r == wild || c == wild)
3013                 return InferredResult(true, max(r, c), max(r, c));
3014             else
3015                 return InferredResult(true, r, c);
3016         }
3017 
3018 
3019         auto ref opIndex(size_t i, size_t j) const { return f(i, j); }
3020 
3021 
3022         mixin(defaultExprOps!(true));
3023     }
3024 
3025       return Result!()();
3026 }
3027 unittest{
3028     auto mi = matrix!((i, j) => i * 3 + j);
3029     static assert(isAbstractMatrix!(typeof(mi)));
3030     assert(mi == matrix!((i, j) => i * 3 + j)(2, 3));
3031 }
3032 
3033 
3034 /**
3035 内部で2次元配列を持つ行列です
3036 */
3037 struct DMatrix(T, Msize_t rs = dynamic, Msize_t cs = dynamic, Major mjr = Major.row)
3038 {
3039     enum bool isColumnMajor = mjr == Major.column;
3040     enum bool isRowMajor    = mjr == Major.row;
3041     enum major = mjr;
3042 
3043 
3044   private
3045   {
3046     static if(rs == 1 || cs == 1)
3047     {
3048       T[] _array;
3049     }
3050     else
3051     {
3052       T[][] _array;
3053     }
3054   }
3055 
3056 
3057     this(M)(auto ref M m)
3058     if(!is(M == typeof(this)))
3059     {
3060       static if(isMatrix!M)
3061         this.noAlias = m;
3062       else
3063         this.opAssign(m);
3064     }
3065 
3066 
3067     static if(rs != dynamic)
3068     {
3069         enum size_t rows = rs;
3070     }
3071     else
3072     {
3073         @property
3074         size_t rows() const
3075         {
3076           static if(cs == 1)
3077             return _array.length;
3078           else static if(isColumnMajor)
3079           {
3080             if(this.tupleof[0].length)
3081                 return this.tupleof[0][0].length;
3082             else
3083                 return 0;
3084           }
3085           else
3086             return this.tupleof[0].length;
3087         }
3088 
3089 
3090         @property
3091         void rows(size_t newSize)
3092         {
3093           static if(rs == 1)
3094             return _array.length;
3095           else static if(isColumnMajor)
3096           {
3097             foreach(ref e; _array)
3098               e.length = newSize;
3099           }
3100           else
3101             _array.length = newSize;
3102         }
3103     }
3104 
3105     static if(cs != dynamic)
3106     {
3107         enum size_t cols = cs;
3108     }
3109     else
3110     {
3111         @property
3112         size_t cols() const
3113         {
3114           static if(rs == 1)
3115             return _array.length;
3116           else static if(isRowMajor){
3117             if(this.tupleof[0].length)
3118                 return this.tupleof[0][0].length;
3119             else
3120                 return 0;
3121           }
3122           else
3123             return this.tupleof[0].length;
3124         }
3125 
3126 
3127         @property
3128         void cols(size_t newSize)
3129         {
3130           static if(rs == 1)
3131             return _array.length = newSize;
3132           else static if(isRowMajor)
3133           {
3134             foreach(ref e; _array)
3135               e.length = newSize;
3136           }
3137           else
3138             _array.length = newSize;
3139         }
3140     }
3141 
3142 
3143     auto ref opIndex(size_t i, size_t j) inout
3144     in{
3145         assert(i < rows);
3146         assert(j < cols);
3147     }
3148     body{
3149       static if(rs == 1 || cs == 1)
3150         return _array[i+j];
3151       else static if(isRowMajor)
3152         return _array[i][j];
3153       else
3154         return _array[j][i];
3155     }
3156 
3157 
3158     mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.opAssign, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
3159     //mixin(defaultExprOps!(false));
3160 
3161 
3162     void opAssign(M)(auto ref M mat)
3163     if(!is(typeof(this) == M) && isValidOperator!(typeof(this), "=", M))
3164     in{
3165       static if(rs && hasDynamicRows!M)
3166         assert(this.rows == mat.rows);
3167 
3168       static if(cs && hasDynamicColumns!M)
3169         assert(this.cols == mat.cols);
3170 
3171       static if(isAbstractMatrix!M)
3172         assert(mat.inferSize(this.rows, this.cols).isValid);
3173     }
3174     body
3175     {
3176       static if(isAbstractMatrix!M)
3177       {
3178         immutable rl = this.rows,
3179                   cl = this.cols;
3180       }
3181       else
3182       {
3183         immutable rl = mat.rows,
3184                   cl = mat.cols;
3185       }
3186 
3187         immutable n = rl * cl;
3188 
3189         if(_buffer.length < n)
3190             _buffer.length = n;
3191 
3192         foreach(i; 0 .. rl)
3193             foreach(j; 0 .. cl)
3194             {
3195                 static if(major == Major.row)
3196                     _buffer[i * cl + j] = mat.at(i, j);
3197                 else
3198                     _buffer[j * rl + i] = mat.at(i, j);
3199             }
3200 
3201       static if(rs == dynamic)
3202         this.rows = rl;
3203 
3204       static if(cs == dynamic)
3205         this.cols = cl;
3206 
3207       static if(rs == 1 || cs == 1)
3208         _array[] = _buffer[0 .. n][];
3209       else{
3210         foreach(i; 0 .. _array.length)
3211             _array[i][] = _buffer[i * _array[0].length .. (i+1) * _array[0].length][];
3212       }
3213     }
3214 
3215 
3216     void opAssign(X)(X m)
3217     if(!isNarrowMatrix!X && isRandomAccessRange!X && (rs || !isInfinite!X)
3218                    && isRandomAccessRange!(std.range.ElementType!X)
3219                    && (cs || !isInfinite!(std.range.ElementType!X))
3220                    && isAssignable!(T, std.range.ElementType!X))
3221     {
3222         if(m.length && m[0].length){
3223           static if(rs == dynamic){
3224             if(m.length != this.rows)
3225                 this.rows = m.length;
3226           }
3227             
3228           static if(cs == dynamic){
3229             if(m[0].length != this.cols)
3230                 this.cols = m[0].length;
3231           }
3232 
3233             foreach(i; 0 .. this.rows)
3234                 foreach(j; 0 .. this.cols)
3235                     this[i, j] = m[i][j];
3236         }
3237     }
3238 
3239 
3240     void opAssign(X)(X m)
3241     if(!isNarrowMatrix!X && isRandomAccessRange!X && isAssignable!(T, std.range.ElementType!X))
3242     {
3243         foreach(i; 0 .. this.rows)
3244             foreach(j; 0 .. this.cols)
3245                 this[i, j] = m[i * this.cols + j];
3246     }
3247 
3248 
3249   static if(rs == 1 || cs == 1)
3250   {
3251     void opAssign(Array)(Array arr)
3252     if(!isNarrowMatrix!Array && isAssignable!(T, typeof(arr[size_t.init])))
3253     {
3254         foreach(i; 0 .. this.length)
3255             this[i] = arr[i];
3256     }
3257   }
3258 
3259 
3260     @property
3261     void noAlias(M)(auto ref M mat)
3262     if(isValidOperator!(typeof(this), "=", M) && ((!rs || !hasStaticRows!M) ||    is(typeof({static assert(this.rows == M.rows);})))
3263                                               && ((!cs || !hasStaticCols!M) || is(typeof({static assert(this.cols == M.cols);}))))
3264     in{
3265       static if(rs != dynamic)
3266         assert(this.rows == mat.rows);
3267 
3268       static if(cs != dynamic)
3269         assert(this.cols == mat.cols);
3270     }
3271     body{
3272       static if(is(typeof(this) == M))
3273         this = mat;
3274       else
3275       {
3276         immutable rl = mat.rows,
3277                   cl = mat.cols,
3278                   n = rl * cl;
3279 
3280       static if(is(typeof(_array) == T[]))
3281       {
3282         if(_array.length < n)
3283             _array.length = n;
3284       }
3285       else
3286       {
3287         immutable x = (major == Major.row) ? rl : cl,
3288                   y = (major == Major.row) ? cl : rl;
3289 
3290         if(_array.length < x)
3291             _array.length = x;
3292 
3293         foreach(ref e; _array)
3294             if(e.length < y)
3295                 e.length = y;
3296       }
3297 
3298         static if(rs == dynamic)
3299           this.rows = rl;
3300 
3301         static if(cs == dynamic)
3302           this.cols = cl;
3303 
3304         foreach(i; 0 .. rl)
3305             foreach(j; 0 .. cl)
3306             {
3307               static if(rs == 1 || cs == 1)
3308                 _array[i+j] = mat.at(i, j);
3309               else static if(major == Major.row)
3310                   _array[i][j] = mat.at(i, j);
3311               else
3312                   _array[j][i] = mat.at(i, j);
3313             }
3314       }
3315     }
3316 
3317 
3318     @property
3319     auto reference() inout
3320     {
3321         return this;
3322     }
3323 
3324 
3325   private:
3326 
3327   static:
3328     T[] _buffer;
3329 }
3330 
3331 unittest{
3332     DMatrix!float m = 
3333     [[1, 2, 3],
3334      [4, 5, 6]];
3335 
3336      assert(m.rows == 2);
3337      assert(m.cols == 3);
3338 
3339      assert(m[0, 0] == 1);
3340      assert(m[0, 1] == 2);
3341      assert(m[0, 2] == 3);
3342      assert(m[1, 0] == 4);
3343      assert(m[1, 1] == 5);
3344      assert(m[1, 2] == 6);
3345 }
3346 
3347 
3348 DMatrix!(T, r, c, mjr) matrix(T, Msize_t r = dynamic, Msize_t c = dynamic, Major mjr = Major.row, size_t N)(size_t[N] size...)
3349 if(N == (r == dynamic) + (c == dynamic))
3350 {
3351     typeof(return) dst;
3352 
3353     static if(r != dynamic)
3354         immutable size_t rs = r;
3355     else
3356         immutable size_t rs = size[0];
3357 
3358     static if(c != dynamic)
3359         immutable size_t cs = c;
3360     else
3361         immutable size_t cs = size[$-1];
3362 
3363     immutable h = mjr == Major.row ? rs : cs,
3364               w = mjr == Major.row ? cs : rs;
3365 
3366     static if(r == 1 || c == 1)
3367         dst._array = new T[h * w];
3368     else
3369         dst._array = new T[][](h, w);
3370 
3371     return dst;
3372 }
3373 
3374 unittest{
3375     foreach(major; TypeTuple!(Major.row, Major.column))
3376     {
3377         auto mr23 = matrix!(int, 2, 4, major)();
3378         static assert(isNarrowMatrix!(typeof(mr23)));
3379         static assert(hasStaticRows!(typeof(mr23)));
3380         static assert(hasStaticCols!(typeof(mr23)));
3381         static assert(mr23.rows == 2);
3382         static assert(mr23.cols == 4);
3383 
3384         auto mr2_ = matrix!(int, 2, dynamic, major)(4);
3385         static assert(isNarrowMatrix!(typeof(mr2_)));
3386         static assert(hasStaticRows!(typeof(mr2_)));
3387         static assert(hasDynamicColumns!(typeof(mr2_)));
3388         static assert(mr2_.rows == 2);
3389         assert(mr2_.cols == 4);
3390 
3391         auto mr_2 = matrix!(int, dynamic, 2, major)(4);
3392         static assert(isNarrowMatrix!(typeof(mr_2)));
3393         static assert(hasDynamicRows!(typeof(mr_2)));
3394         static assert(hasStaticCols!(typeof(mr_2)));
3395         assert(mr_2.rows == 4);
3396         static assert(mr_2.cols == 2);
3397 
3398         auto mr__ = matrix!(int, dynamic, dynamic, major)(2, 4);
3399         static assert(isNarrowMatrix!(typeof(mr__)));
3400         static assert(hasDynamicRows!(typeof(mr__)));
3401         static assert(hasDynamicColumns!(typeof(mr__)));
3402         assert(mr__.rows == 2);
3403         assert(mr__.cols == 4);
3404     }
3405 }
3406 
3407 
3408 DMatrix!(T, r, c, mjr) matrix(size_t r, size_t c, Major mjr = Major.row, T)(T[] arr)
3409 if(r != 0 || c != 0)
3410 in{
3411   static if(r != 0 && c != 0)
3412     assert(arr.length == r * c);
3413   else{
3414     assert(!(arr.length % r + c));
3415   }
3416 }
3417 body{
3418     static if(r == 1 || c == 1)
3419     {
3420       typeof(return) dst;
3421       dst._array = arr;
3422       return dst;
3423     }
3424     else
3425     {
3426       immutable rs = r == 0 ? arr.length / c : r;
3427       immutable cs = c == 0 ? arr.length / r : c;
3428 
3429       immutable h = mjr == Major.row ? rs : cs,
3430                 w = mjr == Major.row ? cs : rs;
3431 
3432       typeof(return) dst;
3433       dst._array.length = h;
3434       foreach(i; 0 .. h)
3435         dst._array[i] = arr[i * w .. (i+1) * w];
3436 
3437       return dst;
3438     }
3439 }
3440 
3441 unittest{
3442     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3443     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3444 
3445     auto mr = matrix!(2, 3)([0, 1, 2, 3, 4, 5]);
3446     static assert(isNarrowMatrix!(typeof(mr)));
3447     static assert(hasStaticRows!(typeof(mr)));
3448     static assert(hasStaticCols!(typeof(mr)));
3449     static assert(mr.rows == 2);
3450     static assert(mr.cols == 3);
3451     assert(mr[0, 0] == 0); assert(mr[0, 1] == 1); assert(mr[0, 2] == 2);
3452     assert(mr[1, 0] == 3); assert(mr[1, 1] == 4); assert(mr[1, 2] == 5);
3453 
3454     mr[0, 0] = 10;
3455     assert(mr[0, 0] == 10); assert(mr[0, 1] == 1); assert(mr[0, 2] == 2);
3456     assert(mr[1, 0] ==  3); assert(mr[1, 1] == 4); assert(mr[1, 2] == 5);
3457 
3458     mr = matrix!(2, 3, (i, j) => cast(int)((i*3+j)*2));
3459     assert(mr[0, 0] == 0); assert(mr[0, 1] == 2); assert(mr[0, 2] == 4);
3460     assert(mr[1, 0] == 6); assert(mr[1, 1] == 8); assert(mr[1, 2] == 10);
3461 
3462     auto mc = matrix!(2, 3, Major.column)([0, 1, 2, 3, 4, 5]);
3463     static assert(isNarrowMatrix!(typeof(mc)));
3464     static assert(hasStaticRows!(typeof(mc)));
3465     static assert(hasStaticCols!(typeof(mc)));
3466     static assert(mc.rows == 2);
3467     static assert(mc.cols == 3);
3468     assert(mc[0, 0] == 0); assert(mc[0, 1] == 2); assert(mc[0, 2] == 4);
3469     assert(mc[1, 0] == 1); assert(mc[1, 1] == 3); assert(mc[1, 2] == 5);
3470 
3471     mc[0, 0] = 10;
3472     assert(mc[0, 0] == 10); assert(mc[0, 1] == 2); assert(mc[0, 2] == 4);
3473     assert(mc[1, 0] ==  1); assert(mc[1, 1] == 3); assert(mc[1, 2] == 5);
3474 
3475     mc = matrix!(2, 3, (i, j) => cast(int)((i*3+j)*2));
3476     assert(mc[0, 0] == 0); assert(mc[0, 1] == 2); assert(mc[0, 2] == 4);
3477     assert(mc[1, 0] == 6); assert(mc[1, 1] == 8); assert(mc[1, 2] == 10);
3478 }
3479 
3480 
3481 DMatrix!(T, wild, wild, mjr) matrix(Major mjr = Major.row, T)(T[] arr, size_t r, size_t c)
3482 in{
3483   if(r != 0 && c != 0)
3484     assert(arr.length == r * c);
3485   else if(r != 0 || c != 0)
3486     assert(!(arr.length % (r + c)));
3487   else
3488     assert(0);
3489 }
3490 body{
3491     immutable rs = r == 0 ? arr.length / c : r;
3492     immutable cs = c == 0 ? arr.length / r : c;
3493 
3494     immutable h = mjr == Major.row ? rs : cs,
3495               w = mjr == Major.row ? rs : cs;
3496 
3497     typeof(return) dst;
3498     dst._array.length = h;
3499     foreach(i; 0 .. h)
3500       dst._array[i] = arr[i * w .. (i+1) * w];
3501 
3502     return dst;
3503 }
3504 
3505 unittest{
3506     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3507     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3508 
3509     auto mr = matrix!(2, 3)([0, 1, 2, 3, 4, 5]);
3510     static assert(isNarrowMatrix!(typeof(mr)));
3511     static assert(hasStaticRows!(typeof(mr)));
3512     static assert(hasStaticCols!(typeof(mr)));
3513     static assert(mr.rows == 2);
3514     static assert(mr.cols == 3);
3515     assert(mr[0, 0] == 0); assert(mr[0, 1] == 1); assert(mr[0, 2] == 2);
3516     assert(mr[1, 0] == 3); assert(mr[1, 1] == 4); assert(mr[1, 2] == 5);
3517 
3518 
3519     auto mc = matrix!(2, 3, Major.column)([0, 1, 2, 3, 4, 5]);
3520     static assert(isNarrowMatrix!(typeof(mc)));
3521     static assert(hasStaticRows!(typeof(mc)));
3522     static assert(hasStaticCols!(typeof(mc)));
3523     static assert(mc.rows == 2);
3524     static assert(mc.cols == 3);
3525     assert(mc[0, 0] == 0); assert(mc[0, 1] == 2); assert(mc[0, 2] == 4);
3526     assert(mc[1, 0] == 1); assert(mc[1, 1] == 3); assert(mc[1, 2] == 5);
3527 }
3528 
3529 
3530 auto matrix(Major mjr = Major.row, T, size_t N, size_t M)(ref T[M][N] arr)
3531 {
3532   static if(mjr == Major.row)
3533     DMatrix!(T, N, M, mjr) dst;
3534   else
3535     DMatrix!(T, M, N, mjr) dst;
3536 
3537     dst._array.length = N;
3538     foreach(i; 0 .. N)
3539       dst._array[i] = arr[i];
3540     return dst;
3541 }
3542 
3543 unittest{
3544     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3545     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3546 
3547     int[3][2] arr = [[0, 1, 2], [3, 4, 5]];
3548 
3549     auto mr = matrix(arr);
3550     static assert(isNarrowMatrix!(typeof(mr)));
3551     static assert(hasStaticRows!(typeof(mr)));
3552     static assert(hasStaticCols!(typeof(mr)));
3553     static assert(mr.rows == 2);
3554     static assert(mr.cols == 3);
3555     assert(mr[0, 0] == 0); assert(mr[0, 1] == 1); assert(mr[0, 2] == 2);
3556     assert(mr[1, 0] == 3); assert(mr[1, 1] == 4); assert(mr[1, 2] == 5);
3557 }
3558 
3559 auto matrix(Major mjr = Major.row, A)(A mat)
3560 if(isNarrowMatrix!A && !isAbstractMatrix!A)
3561 {
3562   static if(hasStaticRows!A && hasStaticCols!A)
3563     DMatrix!(ElementType!A, A.rows, A.cols, mjr) dst;
3564   else static if(hasStaticRows!A)
3565     DMatrix!(ElementType!A, A.rows, wild, mjr) dst;
3566   else static if(hasStaticCols!A)
3567     DMatrix!(ElementType!A, wild, A.cols, mjr) dst;
3568   else
3569     DMatrix!(ElementType!A, wild, wild, mjr) dst;
3570 
3571     dst.noAlias = mat;
3572     return dst;
3573 }
3574 
3575 
3576 auto matrix(Msize_t rs, Msize_t cs = 0, Major mjr = Major.row, A)(A mat)
3577 if(isAbstractMatrix!A && A.inferSize(rs, cs).isValid)
3578 {
3579     return mat.congeal!(rs, cs).matrix();
3580 }
3581 
3582 
3583 auto matrix(Major mjr = Major.row, A)(A mat, size_t r, size_t c = 0)
3584 if(isAbstractMatrix!A)
3585 in{
3586   assert(A.inferSize(r, c).isValid);
3587 }
3588 body{
3589   return mat.congeal(r, c).matrix();
3590 }
3591 
3592 
3593 /**
3594 要素がメモリ上に連続して存在するような行列
3595 */
3596 struct SMatrix(T, Msize_t rs = 0, Msize_t cs = 0, Major mjr = Major.row)
3597 if(rs >= 0 && cs >= 0)
3598 {
3599     enum bool isColumnMajor = mjr == Major.column;
3600     enum bool isRowMajor    = mjr == Major.row;
3601     enum major = mjr;
3602     enum size_t rows = rs;
3603     enum size_t cols = cs;
3604 
3605 
3606     this(M)(auto ref M mat)
3607     if(!is(M == typeof(this)))
3608     {
3609       static if(isNarrowMatrix!M)
3610         this.noAlias = mat;
3611       else
3612         this.opAssign(mat);
3613     }
3614 
3615 
3616     //@disable this(this);
3617 
3618 
3619     auto ref opIndex(size_t i, size_t j) inout
3620     in{
3621         assert(i < rows);
3622         assert(j < cols);
3623     }
3624     body{
3625         static if(major == Major.row)
3626             return _array[i * cols + j];
3627         else
3628             return _array[j * rows + i];
3629     }
3630 
3631 
3632     @property
3633     auto array() pure nothrow @safe inout
3634     {
3635         return _array[];
3636     }
3637 
3638 
3639     void opAssign(M)(auto ref M mat)
3640     if(isValidOperator!(typeof(this), "=", M))
3641     {
3642         auto buffer = {
3643             if(__ctfe)
3644                 return new T[rs * cs];
3645             else
3646                 return SMatrix._buffer[];
3647         }();
3648 
3649         foreach(i; 0 .. rows)
3650             foreach(j; 0 .. cols)
3651             {
3652                 static if(major == Major.row)
3653                     buffer[i * cols + j] = mat.at(i, j);
3654                 else
3655                     buffer[j * rows + i] = mat.at(i, j);
3656             }
3657         
3658         _array[] = buffer[];
3659     }
3660 
3661 
3662     @property
3663     void noAlias(M)(auto ref M mat)
3664     if(isValidOperator!(typeof(this), "=", M))
3665     {
3666         foreach(i; 0 .. rows)
3667             foreach(j; 0 .. cols)
3668             {
3669                 static if(major == Major.row)
3670                     _array[i * cols + j] = mat[i, j];
3671                 else
3672                     _array[j * rows + i] = mat[i, j];
3673             }
3674     }
3675 
3676 
3677     //@property
3678     //auto stackRef() inout pure nothrow @safe
3679     //{
3680     //    //Issue: 9983 http://d.puremagic.com/issues/show_bug.cgi?id=9983
3681     //    //return matrix!(rows, cols)(_array[]);
3682     //    return _referenceImpl(this);
3683     //}
3684 
3685 
3686     //alias reference this;
3687 
3688     mixin(ExpressionOperators!(ETOSpec.all & ~ETOSpec.opAssign, mixin(is(typeof({enum _unused_ = rows;})) ? "this.rows" : "wild"), mixin(is(typeof({enum _unused_ = cols;})) ? "this.cols" : "wild")).stringMixin);
3689     //mixin(defaultExprOps!(false));
3690 
3691 
3692   private:
3693     T[rs * cs] _array;
3694 
3695   static:
3696     T[rs * cs] _buffer;
3697 
3698 
3699     //// Workaround of issue 9983 http://d.puremagic.com/issues/show_bug.cgi?id=9983
3700     //auto _referenceImpl(M)(ref M m) @trusted pure nothrow
3701     //{
3702     //    static if(is(M == immutable(M)))
3703     //        return _referenceImplImmutable(cast(immutable(T)[])m._array[]);
3704     //    else static if(is(M == const(M)))
3705     //        return _referenceImplConst(cast(const(T)[])m._array[]);
3706     //    else
3707     //        return _referenceImplMutable(cast(T[])m._array[]);
3708     //}
3709 
3710 
3711     //auto _referenceImplMutable(E)(E[] arr)
3712     //{
3713     //    return arr.matrix!(rows, cols);
3714     //}
3715 
3716 
3717     //auto _referenceImplConst(E)(const E[] arr)
3718     //{
3719     //    return arr.matrix!(rows, cols);
3720     //}
3721 
3722 
3723     //auto _referenceImplImmutable(E)(immutable E[] arr)
3724     //{
3725     //    return arr.matrix!(rows, cols);
3726     //}
3727 }
3728 
3729 unittest{
3730     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3731     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3732 
3733 
3734     SMatrix!(int, 3, 3) m;
3735     m[0, 0] = 0; m[0, 1] = 1; m[0, 2] = 2;
3736     m[1, 0] = 1; m[1, 1] = 2; m[1, 2] = 3;
3737     m[2, 0] = 2; m[2, 1] = 3; m[2, 2] = 4;
3738 
3739     auto mref = m.pref;
3740 
3741     SMatrix!(int, 3, 3) m2 = mref * mref;
3742     mref = mref * mref;
3743     assert(mref == m2);
3744 }
3745 
3746 unittest{
3747     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3748     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3749 
3750 
3751     SMatrix!(int, 2, 2, Major.row) mr;    // 2x2, int型, 行優先
3752     assert(mr.array.equal([0, 0, 0, 0]));       // 初期化される
3753 
3754     mr[0, 1] = 1;
3755     mr[1, 0] = 2;
3756     mr[1, 1] = 3;
3757     assert(mr.array.equal([0, 1, 2, 3]));       // 行優先順
3758 
3759 
3760     SMatrix!(int, 2, 2, Major.column) mc; // 2x2, int型, 列優先
3761     assert(mc.array.equal([0, 0, 0, 0]));       // 初期化される
3762 
3763     mc[0, 1] = 1;
3764     mc[1, 0] = 2;
3765     mc[1, 1] = 3;
3766     assert(mc.array.equal([0, 2, 1, 3]));       // 列優先順
3767 
3768 
3769     SMatrix!(int, 2, 2, Major.row) minit = mc;
3770     assert(minit.array.equal([0, 1, 2, 3]));   // 全要素12で初期化されている
3771 }
3772 
3773 unittest{
3774     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3775     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3776 
3777 
3778     SMatrix!(int, 1, 3) m;
3779     m[0] = 3;
3780     assert(m[0] == 3);
3781     static assert(m.length == 3);
3782     assert(m[$-1] == 0);
3783 }
3784 
3785 unittest{
3786     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3787     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3788 
3789 
3790     SMatrix!(int, 2, 2) m;
3791     auto rm = m.pref;
3792 
3793     assert(rm + rm == m.pref + m);
3794     assert(rm - rm == m.pref - m);
3795     assert(rm * rm == m.pref * m);
3796 
3797     m = [[1, 2], [2, 3]];
3798 
3799     SMatrix!(int, 2, 2) m2 = m;
3800     m.noAlias = m2.pref + m2;
3801     assert(m[0, 0] == 2);
3802 }
3803 
3804 
3805 unittest{
3806     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3807     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3808 
3809 
3810     alias SRVector!(int, 3) R;
3811     R rv1;
3812     static assert(rv1.rows == 1);
3813     static assert(rv1.cols == 3);
3814     static assert(rv1.length  == 3);
3815 
3816     rv1[0] = 3;
3817     assert(rv1[0] == 3);
3818     assert(rv1[1] == 0);
3819     assert(rv1[2] == 0);
3820     rv1 += 3;
3821     assert(rv1[0] == 6);
3822     assert(rv1[1] == 3);
3823     assert(rv1[2] == 3);
3824     rv1[0] += 3;
3825     assert(rv1[0] == 9);
3826     assert(rv1[1] == 3);
3827     assert(rv1[2] == 3);
3828 
3829     SRVector!(int, 4) rv2;
3830     static assert(rv2.rows == 1);
3831     static assert(rv2.cols == 4);
3832     static assert(rv2.length  == 4);
3833 
3834     SCVector!(int, 3) cv1;
3835     static assert(cv1.rows == 3);
3836     static assert(cv1.cols == 1);
3837     static assert(cv1.length  == 3);
3838 
3839     SCVector!(int, 4) cv2;
3840     static assert(cv2.rows == 4);
3841     static assert(cv2.cols == 1);
3842     static assert(cv2.length  == 4);
3843 }
3844 
3845 
3846 ///ditto
3847 template SRVector(T, Msize_t size)
3848 {
3849     alias SMatrix!(T, 1, size, Major.row) SRVector;
3850 }
3851 
3852 ///ditto
3853 template SCVector(T, Msize_t size)
3854 {
3855     alias SMatrix!(T, size, 1, Major.column) SCVector;
3856 }
3857 
3858 ///ditto
3859 template SVector(T, Msize_t size)
3860 {
3861     alias SCVector!(T, size) SVector;
3862 }
3863 
3864 
3865 /**
3866 転置行列を返します。
3867 */
3868 @property
3869 auto transpose(A)(A mat)
3870 if(isNarrowMatrix!A)
3871 {
3872     static struct Transposed()
3873     {
3874       static if(isAbstractMatrix!A)
3875       {
3876         enum size_t rows = wild;
3877         enum size_t cols = wild;
3878 
3879         static InferredResult inferSize(Msize_t rs, Msize_t cs)
3880         {
3881             return A.inferSize(cs, rs);
3882         }
3883       }
3884       else
3885       {
3886         static if(hasStaticCols!A)
3887             enum size_t rows = A.cols;
3888         else
3889             @property auto ref rows() const { return _mat.cols; }
3890 
3891         static if(hasStaticRows!A)
3892             enum size_t cols = A.rows;
3893         else
3894             @property auto ref cols() const { return _mat.rows; }
3895       }
3896 
3897 
3898         auto ref opIndex(size_t i, size_t j) inout
3899         in{
3900             assert(i < rows);
3901             assert(j < cols);
3902         }
3903         body{
3904             return _mat[j, i];
3905         }
3906 
3907 
3908       static if(carbon.linear.hasAssignableElements!A)
3909       {
3910         void opIndexAssign(E)(E e, size_t i, size_t j)
3911         in{
3912             assert(i < rows);
3913             assert(j < cols);
3914         }
3915         body{
3916             _mat[j, i] = e;
3917         }
3918 
3919         static if(isVector!A)
3920         {
3921             void opIndexAssign(E)(E e, size_t i)
3922             in{
3923                 assert(i < this.length);
3924             }
3925             body{
3926                 static if(is(typeof({static assert(rows == 1);})))
3927                     this[0 , i] = e;
3928                 else
3929                     this[i, 0] = e;
3930             }
3931         }
3932       }
3933 
3934         mixin(defaultExprOps!(isAbstractMatrix!A));
3935 
3936 
3937         auto ref transpose() @property inout
3938         {
3939             return _mat;
3940         }
3941 
3942 
3943       private:
3944         A _mat;
3945     }
3946 
3947 
3948     return Transposed!()(mat);
3949 }
3950 unittest{
3951     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3952     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3953 
3954 
3955     SMatrix!(int, 2, 2) m;
3956     m = [[0, 1],
3957          [2, 3]];
3958 
3959     auto t = m.pref.transpose;
3960     assert(t[0, 0] == 0);
3961     assert(t[0, 1] == 2);
3962     assert(t[1, 0] == 1);
3963     assert(t[1, 1] == 3);
3964 }
3965 unittest{
3966     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3967     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3968 
3969 
3970     SCVector!(int, 3) v;
3971     v[0] = 1; v[1] = 2; v[2] = 3;
3972 
3973     auto t = v.pref.transpose;
3974     t[0] = 1;
3975     t[1] = 2;
3976     t[2] = 3;
3977     //t = [1, 2, 3];
3978 
3979     assert(t.rows == 1);
3980     assert(t.cols == 3);
3981 
3982 
3983     static assert(is(typeof(v.pref) == typeof(t.transpose)));
3984 }
3985 
3986 
3987 /**
3988 エルミート行列を返します
3989 */
3990 auto hermitian(A)(A mat)
3991 if(isNarrowMatrix!A)
3992 {
3993     static struct Hermitian()
3994     {
3995       static if(isAbstractMatrix!A)
3996       {
3997         enum size_t rows = wild;
3998         enum size_t cols = wild;
3999 
4000         static InferredResult inferSize(Msize_t rs, Msize_t cs)
4001         {
4002             return A.inferSize(cs, rs);
4003         }
4004       }
4005       else
4006       {
4007         static if(hasStaticCols!A)
4008             enum size_t rows = A.cols;
4009         else
4010             @property auto ref rows() inout { return _mat.cols; }
4011 
4012         static if(hasStaticRows!A)
4013             enum size_t cols = A.rows;
4014         else
4015             @property auto ref cols() inout { return _mat.rows; }
4016       }
4017 
4018 
4019         auto opIndex(size_t i, size_t j) inout
4020         in{
4021             assert(i < rows);
4022             assert(j < cols);
4023         }
4024         body{
4025             return _mat[j, i].conj;
4026         }
4027 
4028 
4029         mixin(defaultExprOps!(isAbstractMatrix!A));
4030 
4031 
4032         auto ref hermitian() @property inout
4033         {
4034             return _mat;
4035         }
4036 
4037 
4038       private:
4039         A _mat;
4040     }
4041 
4042     return Hermitian!()(mat);
4043 }
4044 unittest{
4045     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4046     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4047 
4048 
4049     SMatrix!(cfloat, 2, 2) m;
4050     m = [[0+0i, 1+1i],
4051          [2+2i, 3+3i]];
4052 
4053     auto t = m.pref.hermitian;
4054     assert(t[0, 0] == 0-0i);
4055     assert(t[0, 1] == 2-2i);
4056     assert(t[1, 0] == 1-1i);
4057     assert(t[1, 1] == 3-3i);
4058 }
4059 
4060 
4061 
4062 /**
4063 
4064 */
4065 auto toRange(A)(A mat)
4066 if(isNarrowMatrix!A)
4067 {
4068     static struct ToRange()
4069     {
4070         static struct Element()
4071         {
4072             @property auto ref front() { return _mat[_r, _cf]; }
4073 
4074             @property auto ref back() { return _mat[_r, _cb]; }
4075 
4076             auto ref opIndex(size_t i) { i += _cf; return _mat[_r, i]; }
4077 
4078             void popFront() { ++_cf; }
4079             void popBack() { --_cb; }
4080 
4081             @property bool empty() { return _cf == _cb; }
4082             @property size_t length() { return _cb - _cf; }
4083             alias opDollar = length;
4084 
4085             @property auto save() { return this; }
4086 
4087             auto opSlice() { return this.save; }
4088             auto opSlice(size_t i, size_t j) { return typeof(this)(_mat, _r, _cf + i, j); }
4089 
4090 
4091           private:
4092             A _mat;
4093             size_t _r;
4094             size_t _cf = 0;
4095             size_t _cb;
4096         }
4097 
4098 
4099         @property auto front() { return Element!()(this._mat, _rf, 0, this._mat.cols); }
4100 
4101         @property auto back() { return Element!()(this._mat, _rb, 0, this._mat.cols); }
4102 
4103         auto opIndex(size_t i) { i += _rf; return Element!()(this._mat, i, 0, this._mat.cols);}
4104 
4105         void popFront() { ++_rf; }
4106         void popBack() { --_rb; }
4107 
4108         @property bool empty() { return _rf == _rb; }
4109         @property size_t length() { return _rb - _rf; }
4110         alias opDollar = length;
4111 
4112         @property auto save() { return this; }
4113 
4114         auto opSlice() { return this.save; }
4115         auto opSlice(size_t i, size_t j) { return typeof(this)(_mat, _rf + i, j); }
4116 
4117       private:
4118         A _mat;
4119         size_t _rf = 0;
4120         size_t _rb;
4121     }
4122 
4123 
4124     return ToRange!()(mat, 0, mat.rows);
4125 }
4126 
4127 unittest{
4128     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4129     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4130 
4131 
4132     SMatrix!(int, 3, 3) rm33;
4133     rm33[0, 0] = 1; rm33[0, 1] = 2; rm33[0, 2] = 3;
4134     assert(equal!"equal(a, b)"(rm33.pref.toRange, [[1, 2, 3], [0, 0, 0], [0, 0, 0]]));
4135 
4136     SMatrix!(int, 1, 1) rm11;
4137     assert(equal!"equal(a, b)"(rm11.pref.toRange, [[0]]));
4138 }
4139 
4140 
4141 /**
4142 行列をレンジにします
4143 */
4144 auto toFlatten(A)(A mat)
4145 if(isNarrowMatrix!A && !isAbstractMatrix!A)
4146 {
4147     alias ElementType!A E;
4148 
4149     static struct ToFlatten()
4150     {
4151         @property
4152         auto ref front()
4153         {
4154             return _mat[_f / _mat.cols, _f % _mat.cols];
4155         }
4156 
4157 
4158         @property
4159         auto ref back()
4160         {
4161             return _mat[_b / _mat.cols, _b % _mat.cols];
4162         }
4163 
4164 
4165         auto ref opIndex(size_t i) inout
4166         in{
4167             assert(_f + i < _b);
4168         }body{
4169             i += _f;
4170             return _mat[i / _mat.cols, i % _mat.cols];
4171         }
4172 
4173 
4174         static if(hasAssignableElements!A)
4175         {
4176             @property
4177             void front(E v)
4178             {
4179                 _mat[_f / _mat.cols, _f % _mat.cols] = v;
4180             }
4181 
4182 
4183             @property
4184             void back(E v)
4185             {
4186                 _mat[_b / _mat.cols, _b % _mat.cols] = v;
4187             }
4188 
4189 
4190             void opIndexAssign(E v, size_t i)
4191             in{
4192                 assert(_f + i < _b);
4193             }
4194             body{
4195                 i += _f;
4196                 _mat[i / _mat.cols, i % _mat.cols] = v;
4197             }
4198         }
4199 
4200 
4201         @property
4202         bool empty() pure nothrow @safe const
4203         {
4204             return _f >= _b;
4205         }
4206 
4207 
4208         void popFront() pure nothrow @safe
4209         {
4210             _f++;
4211         }
4212 
4213 
4214         void popBack() pure nothrow @safe
4215         {
4216             _b--;
4217         }
4218 
4219 
4220         @property
4221         size_t length() pure nothrow @safe const
4222         {
4223             return _b - _f;
4224         }
4225 
4226 
4227         alias length opDollar;
4228 
4229 
4230         @property
4231         typeof(this) save() pure nothrow @safe
4232         {
4233             return this;
4234         }
4235 
4236 
4237     private:
4238         A _mat;
4239         size_t _f, _b;
4240     }
4241 
4242     return ToFlatten!()(mat, 0, mat.rows * mat.cols);
4243 }
4244 unittest{
4245     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4246     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4247 
4248 
4249     SMatrix!(int, 3, 3, Major.row) rm33;
4250     rm33[0, 0] = 1; rm33[0, 1] = 2; rm33[0, 2] = 3;
4251     //writeln(rm33.array.length;)
4252     assert(rm33.array == [1, 2, 3, 0, 0, 0, 0, 0, 0]);
4253 
4254     alias Rt1 = typeof(toFlatten(rm33));
4255     static assert(isRandomAccessRange!(Rt1));
4256     static assert(std.range.hasLvalueElements!(Rt1));
4257     static assert(std.range.hasAssignableElements!(Rt1));
4258     static assert(hasLength!(Rt1));
4259     assert(equal(rm33.toFlatten, rm33.array));
4260 
4261     SMatrix!(int, 3, 3, Major.column) cm33;
4262     cm33[0, 0] = 1; cm33[0, 1] = 2; cm33[0, 2] = 3;
4263     assert(cm33.array == [1, 0, 0, 2, 0, 0, 3, 0, 0]);
4264     assert(equal(cm33.toFlatten, [1, 2, 3, 0, 0, 0, 0, 0, 0]));
4265 }
4266 
4267 
4268 
4269 /**
4270 レンジから行列を作ります。
4271 */
4272 auto toMatrix(Msize_t rs, Msize_t cs, Major mjr = Major.row, R)(R range)
4273 if(isRandomAccessRange!R && isNotVectorOrMatrix!(Unqual!(std.range.ElementType!R)) && (mjr == Major.row ? (cs != wild) : (rs != wild)))
4274 {
4275   //static if(mjr == Major.column)
4276     //return range.toMatrix!(cs, rs, Major.row).transpose;
4277   //else
4278   //{
4279     alias E = Unqual!(std.range.ElementType!R);
4280 
4281     static struct ToMatrix()
4282     {
4283       static if(rs != wild)
4284         enum size_t rows = rs;
4285       else
4286         auto ref rows() const @property
4287         {
4288             return _range.length / typeof(this).cols;
4289         }
4290 
4291       static if(cs != wild)
4292         enum size_t cols = cs;
4293       else
4294         auto ref cols() const @property
4295         {
4296             return _range.length / typeof(this).rows;
4297         }
4298 
4299 
4300         auto ref opIndex(size_t i, size_t j) inout
4301         in{
4302             assert(i < rows || rows == 0);
4303             assert(j < cols || cols == 0);
4304 
4305           static if(hasLength!R && mjr == Major.row)
4306             assert(i * cols + j < this._range.length);
4307 
4308           static if(hasLength!R && mjr == Major.column)
4309             assert(j * rows + i < this._range.length);
4310         }
4311         body{
4312           static if(mjr == Major.row)
4313             return this._range[i * cols + j];
4314           else
4315             return this._range[j * rows + i];
4316         }
4317 
4318 
4319         mixin(defaultExprOps!(false));
4320 
4321       private:
4322         R _range;
4323     }
4324 
4325     return ToMatrix!()(range);
4326   //}
4327 }
4328 
4329 unittest{
4330     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4331     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4332 
4333 
4334     auto r = iota(4);
4335     auto mr = toMatrix!(2, 2)(r);
4336     assert(mr.toFlatten.equal([0, 1, 2, 3]));
4337 
4338     auto mc = r.toMatrix!(2, 2, Major.column);
4339     assert(mc.toFlatten.equal([0, 2, 1, 3]));
4340 }
4341 unittest{
4342     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4343     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4344 
4345 
4346     auto mem = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
4347     auto mr = mem.toMatrix!(3, 3);
4348     static assert(isNarrowMatrix!(typeof(mr)));
4349     static assert(hasLvalueElements!(typeof(mr)));
4350     assert(mr.toFlatten.equal(mem[0 .. 9]));
4351 
4352     mem.length = 16;
4353     auto mc = mem.toMatrix!(4, 4, Major.column);
4354     static assert(isNarrowMatrix!(typeof(mr)));
4355     static assert(hasLvalueElements!(typeof(mr)));
4356     mc[3, 3] = 15;
4357     assert(mc.transpose.toFlatten.equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
4358                                             0, 0, 0, 0, 0, 15]));
4359 }
4360 unittest{
4361     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4362     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4363 
4364 
4365     auto mem = [0, 1, 2, 3];
4366     auto r1 = mem.toMatrix!(wild, 1, Major.row);
4367     assert(equal(r1.toFlatten, mem[0 .. 4]));
4368 
4369     mem ~= [4, 5];
4370     auto r2 = mem.toMatrix!(wild, 2, Major.row);
4371     assert(r2[2, 0] == 4);
4372     assert(r2[2, 1] == 5);
4373 
4374     auto c1 = mem.toMatrix!(1, wild, Major.column);
4375     assert(equal(c1.toFlatten, mem));
4376 }
4377 
4378 
4379 
4380 auto toMatrix(Msize_t rs, Msize_t cs, Major mjr = Major.row, R)(R range)
4381 if(isRandomAccessRange!R && isRandomAccessRange!(Unqual!(std.range.ElementType!R)) && isNotVectorOrMatrix!(Unqual!(std.range.ElementType!(Unqual!(std.range.ElementType!R)))))
4382 {
4383     static struct ToMatrix()
4384     {
4385       static if(rs != dynamic)
4386         enum size_t rows = rs;
4387       else
4388         auto ref rows() const @property
4389         {
4390           static if(mjr == Major.row)
4391             return _range.length;
4392           else
4393             return _range[0].length;
4394         }
4395 
4396 
4397       static if(cs != dynamic)
4398         enum size_t cols = cs;
4399       else
4400         auto ref cols() const @property
4401         {
4402           static if(mjr == Major.column)
4403             return _range.length;
4404           else
4405             return _range[0].length;
4406         }
4407 
4408 
4409         auto ref opIndex(size_t i, size_t j) inout
4410         in{
4411             assert(i < rows || rows == 0);
4412             assert(j < cols || cols == 0);
4413 
4414           static if(hasLength!R)
4415             assert((mjr == Major.row ? i : j) < _range.length);
4416 
4417           static if(hasLength!(Unqual!(std.range.ElementType!R)))
4418             assert((mjr == Major.row ? j : i) < _range[i].length);
4419         }
4420         body{
4421           static if(mjr == Major.row)
4422             return _range[i][j];
4423           else
4424             return _range[j][i];
4425         }
4426 
4427         mixin(defaultExprOps!(false));
4428 
4429       private:
4430         R _range;
4431     }
4432   
4433     return ToMatrix!()(range);
4434 }
4435 unittest{
4436     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4437     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4438 
4439 
4440     auto arr = [[0, 1], [2, 3], [4, 5]];
4441     auto r1 = toMatrix!(3, 2, Major.row)(arr);
4442     static assert(isNarrowMatrix!(typeof(r1)));
4443     assert(equal!"equal(a, b)"(r1.toRange, arr));
4444 
4445     auto r2 = arr.toMatrix!(1, 1, Major.row);
4446     assert(r2[0] == 0);
4447 
4448     auto r3 = arr.toMatrix!(dynamic, 2, Major.row);
4449     assert(r3.congeal!(3, 2) == r1);
4450 
4451     auto r4 = arr.toMatrix!(2, dynamic, Major.row);
4452     assert(equal(r4.congeal!(2, 2)().toFlatten(), [0, 1, 2, 3]));
4453 
4454     auto r5 = arr.toMatrix!(dynamic, dynamic, Major.row);
4455     assert(r5 == r1);
4456 }
4457 unittest{
4458     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4459     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4460 
4461 
4462     auto arr = [[0, 1], [2, 3], [4, 5]];
4463     auto r1 = arr.toMatrix!(2, 3, Major.column);
4464     assert(equal!"equal(a, b)"(r1.transpose.toRange, arr));
4465     assert(r1[0, 0] == 0); assert(r1[0, 1] == 2); assert(r1[0, 2] == 4);
4466     assert(r1[1, 0] == 1); assert(r1[1, 1] == 3); assert(r1[1, 2] == 5);
4467 
4468     auto r2 = arr.toMatrix!(1, 1, Major.column);
4469     assert(r2[0] == 0);
4470 
4471     auto r3 = arr.toMatrix!(dynamic, 3, Major.column);
4472     assert(r3 == r1);
4473 
4474     auto r4 = arr.toMatrix!(2, dynamic, Major.column);
4475     assert(equal(r4.transpose.toFlatten, [0, 1, 2, 3, 4, 5]));
4476 
4477     auto r5 = arr.toMatrix!(dynamic, dynamic, Major.column);
4478     assert(r5 == r1);
4479 }
4480 
4481 
4482 /**
4483 単位行列
4484 */
4485 @property
4486 auto identity(E)()if(isNotVectorOrMatrix!E)
4487 {
4488     static struct Identity()
4489     {
4490         static InferredResult inferSize(Msize_t i, Msize_t j)
4491         {
4492             if(i < 0 && j < 0)
4493                 return InferredResult(false);
4494             else if(i < 0 || j < 0)
4495                 return InferredResult(true, max(i, j), max(i, j));
4496             else if(i == j)
4497                 return InferredResult(true, i, j);
4498             else
4499                 return InferredResult(false);
4500         }
4501 
4502 
4503         E opIndex(size_t i, size_t j) inout
4504         {
4505             return (i == j) ? (cast(E)1) : (cast(E)0);
4506         }
4507 
4508         mixin(defaultExprOps!(true));
4509     }
4510 
4511     static assert(isAbstractMatrix!(Identity!()));
4512     return Identity!()();
4513 }
4514 unittest{
4515     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4516     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4517 
4518 
4519     auto id = identity!int;
4520     static assert(isAbstractMatrix!(typeof(id)));
4521     static assert(typeof(id).inferSize(4, 4).isValid);
4522     static assert(typeof(id).inferSize(wild, 2).isValid);
4523     static assert(!typeof(id).inferSize(1, 3).isValid);
4524 
4525     auto m1 = SMatrix!(int, 2, 2).init;
4526     m1.array[] = [0, 1, 2, 3];
4527     assert(equal((m1.pref * id).toFlatten, [0, 1, 2, 3]));
4528 
4529     auto id2 = id + id;
4530     static assert(isAbstractMatrix!(typeof(id2)));
4531     static assert(typeof(id2).inferSize(4, 4).isValid);
4532 
4533 
4534     auto id22 = id.congeal!(wild, 2);
4535     static assert(id22.rows == 2);
4536     static assert(id22.cols == 2);
4537     assert(equal(id22.toFlatten, [1, 0, 0, 1]));
4538 
4539     auto id3 = id22 * id;
4540     static assert(id3.rows == 2);
4541     static assert(id3.cols == 2);
4542     assert(equal(id3.toFlatten, [1, 0, 0, 1]));
4543 
4544     auto ins = id2.congeal!(2, 2);
4545     static assert(isNarrowMatrix!(typeof(ins)));
4546     assert(equal(ins.toFlatten, [2, 0, 0, 2]));
4547 }
4548 
4549 
4550 /**
4551 全要素が1な行列を返します。
4552 */
4553 @property
4554 auto ones(E)()if(isNotVectorOrMatrix!E)
4555 {
4556     static struct Ones()
4557     {
4558         E opIndex(size_t i, size_t j) inout
4559         {
4560             return cast(E)1;
4561         }
4562 
4563 
4564         static InferredResult inferSize(Msize_t i, Msize_t j)
4565         {
4566             if(i < 0 && j < 0)
4567                 return InferredResult(false);
4568             else if(i < 0 || j < 0)
4569                 return InferredResult(true, max(i, j), max(i, j));
4570             else if(i == j)
4571                 return InferredResult(true, i, j);
4572             else
4573                 return InferredResult(true, i, j);
4574         }
4575 
4576 
4577         mixin(defaultExprOps!(true));
4578     }
4579 
4580     static assert(isAbstractMatrix!(Ones!()));
4581 
4582     return Ones!().init;
4583 }
4584 unittest{
4585     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4586     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4587 
4588 
4589     auto m1 = ones!float;
4590     assert(m1[0, 1] == 1);
4591 
4592     auto m3 = m1 * 3;
4593     assert(m3[0, 1] == 3);
4594 
4595     auto m9 = m3 * 3;
4596     assert(m9[0, 1] == 9);
4597 }
4598 
4599 
4600 /**
4601 部分行列を返します
4602 */
4603 auto sub(alias rArray, alias cArray, A)(A mat)
4604 if(isArray!(typeof(rArray)) && isArray!(typeof(cArray)) && isNarrowMatrix!A && !isAbstractMatrix!A
4605     && (hasDynamicRows!A || is(typeof({static assert(rArray.find!"a>=b"(A.rows).empty);})))
4606     && (hasDynamicColumns!A || is(typeof({static assert(cArray.find!"a>=b"(A.cols).empty);}))))
4607 in{
4608     static if(hasDynamicRows!A)
4609         assert(rArray.find!"a>=b"(mat.rows).empty);
4610     static if(hasDynamicColumns!A)
4611         assert(cArray.find!"a>=b"(mat.cols).empty);
4612 }
4613 body{
4614   static if(rArray.length == 0 && cArray.length == 0)
4615     return mat;
4616   else
4617   {
4618     static struct Sub()
4619     {
4620       static if(rArray.length == 0)
4621         alias rows = _mat.rows;
4622       else
4623         enum rows = rArray.length;
4624 
4625       static if(cArray.length == 0)
4626         alias cols = _mat.cols;
4627       else
4628         enum cols = cArray.length;
4629 
4630 
4631         auto ref opIndex(size_t i, size_t j) inout
4632         in{
4633             assert(i < rows);
4634             assert(j < cols);
4635         }
4636         body{
4637           static if(rArray.length && cArray.length)
4638             return _mat[rArray[i], cArray[j]];
4639           else static if(rArray.length)
4640             return _mat[rArray[i], j];
4641           else static if(cArray.length)
4642             return _mat[i, cArray[j]];
4643           else
4644             static assert(0);
4645         }
4646 
4647 
4648         mixin(defaultExprOps!(false));
4649 
4650 
4651       private:
4652         A _mat;
4653     }
4654 
4655     return Sub!()(mat);
4656   }
4657 }
4658 unittest{
4659     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4660     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4661 
4662 
4663     auto m1 = [[0, 1], [2, 3], [4, 5]].toMatrix!(3, 2, Major.row);
4664     auto s1 = m1.sub!([1, 2], [0]);
4665     static assert(s1.rows == 2);
4666     static assert(s1.cols == 1);
4667 
4668     assert(s1[0, 0] == 2);
4669     assert(s1[1, 0] == 4);
4670 
4671 
4672     auto m2 = [[0, 1], [2, 3], [4, 5]].toMatrix!(dynamic, dynamic, Major.row)();
4673     auto s2 = sub!((size_t[]).init, (size_t[]).init)(m2);
4674     assert(m1 == s2.congeal!(3, 2));
4675 
4676 
4677     auto m3 = identity!int.congeal!(2, 2)().sub!([0, 0, 0], [0, 0, 0])();
4678     assert(m3 == ones!int);
4679 }
4680 
4681 
4682 /**
4683 swizzle : glm参照
4684 */
4685 auto swizzle(A)(A mat) @property
4686 if(isNarrowMatrix!A && !isAbstractMatrix!A)
4687 {
4688     static struct Swizzle()
4689     {
4690         auto opDispatch(string exp)()
4691         if((isVector!A ? (isSwizzleExp(exp) && isSwizzlable!A(exp)) : false) || (isSliceExp(exp) && isSlicable!(A, exp)))
4692         {
4693             static struct SwizzleResult()
4694             {
4695               static if(isSwizzleExp(exp))
4696               {
4697                 static if(A.cols == 1)
4698                 {
4699                   enum size_t rows = exp.length;
4700                   enum size_t cols = 1;
4701                 }
4702                 else
4703                 {
4704                   enum size_t rows = 1;
4705                   enum size_t cols = exp.length;
4706                 }
4707 
4708 
4709                 auto ref opIndex(size_t i, size_t j) inout
4710                 in{
4711                     assert((i+j) < (rows+cols-1));
4712                 }
4713                 body{
4714                     immutable size_t s = swizzleType(exp) == 'a' ? exp[i] - 'a' : (exp[i] == 'w' ? 3 : (exp[i] - 'x'));
4715 
4716                   static if(cols == 1)
4717                     return _mat[s, 0];
4718                   else
4719                     return _mat[0, s];
4720                 }
4721               }
4722               else      // isSliceExp
4723               {
4724                 private enum _swizzleExpSpec = spec(exp);
4725                 enum size_t rows = mixin(_swizzleExpSpec.cs);
4726                 enum size_t cols = mixin(_swizzleExpSpec.rs);
4727 
4728 
4729                 auto ref opIndex(size_t i, size_t j) inout
4730                 in{
4731                     assert(i < rows);
4732                     assert(j < cols);
4733                 }
4734                 body{
4735                     immutable size_t r = mixin(_swizzleExpSpec.rb) + i,
4736                                      c = mixin(_swizzleExpSpec.cb) + j;
4737 
4738                     return _mat[r, c];
4739                 }
4740               }
4741 
4742 
4743                 mixin(defaultExprOps!(false));
4744 
4745               private:
4746                 A _mat;
4747             }
4748 
4749 
4750             return SwizzleResult!()(_mat);
4751         }
4752 
4753       private:
4754         A _mat;
4755 
4756       static:
4757 
4758         bool isSwizzleExp(string str) pure nothrow @safe
4759         {
4760             char d;
4761             foreach(c; str)
4762                 if(!(('a' <= c && c <= 'h') || (c == 'x' || c == 'y' || c == 'z' || c == 'w')))
4763                     return false;
4764                 else if('a' <= c && c <= 'h'){
4765                     if(d == char.init)
4766                         d = 'a';
4767                     else if(d != 'a')
4768                         return false;
4769                 }else{
4770                     if(d == char.init)
4771                         d = 'x';
4772                     else if(d != 'x')
4773                         return false;
4774                 }
4775 
4776             return true;
4777         }
4778         unittest{
4779             assert(isSwizzleExp("aaaaaaa"));
4780             assert(isSwizzleExp("aaaahaa"));
4781             assert(!isSwizzleExp("aaaaiaa"));
4782             assert(!isSwizzleExp("aaxa"));
4783             assert(isSwizzleExp("xxxx"));
4784             assert(isSwizzleExp("xyzw"));
4785             assert(!isSwizzleExp("xyza"));
4786         }
4787 
4788 
4789         // pure nothrow @safeにするため
4790         string find_(string str, char c) pure nothrow @safe
4791         {
4792             while(str.length && str[0] != c)
4793                 str = str[1 .. $];
4794             return str;
4795         }
4796 
4797 
4798         string until_(string str, char c) pure nothrow @safe
4799         {
4800             foreach(i; 0 .. str.length)
4801                 if(str[i] == c)
4802                     return str[0 .. i];
4803 
4804             return str;
4805         }
4806 
4807 
4808         // for matrix, format: r<bias>c<bias>m<row>x<cols>
4809         alias ExpSpec = Tuple!(string, "rb", string, "cb", string, "rs", string, "cs");
4810 
4811 
4812         ExpSpec spec(string exp) pure nothrow @safe
4813         {
4814             ExpSpec spec = ExpSpec("0", "0", "", "");
4815             {
4816                 auto t = until_(until_(find_(exp, 'r'), 'c'), 'm');
4817                 if(t.length > 1)        //r<Num>の形式なので、rを加えて1文字以上無いといけない
4818                     spec.rb = t[1 .. $];
4819             }
4820 
4821             {
4822                 auto t = until_(find_(exp, 'c'), 'm');
4823                 if(t.length > 1)        //c<Num>の形式なので、rを加えて1文字以上無いといけない
4824                     spec.cb = t[1 .. $];
4825             }
4826 
4827             {
4828                 auto t = until_(find_(exp, 'm'), 'x');
4829                 if(t.length > 1)        //m<Num>の形式なので、mを加えて1文字以上無いといけない
4830                     spec.rs = t[1 .. $];
4831             }
4832 
4833             {
4834                 auto t = find_(exp, 'x');
4835                 if(t.length > 1)
4836                     spec.cs = t[1 .. $];
4837             }
4838             return spec;
4839         }
4840         unittest{
4841             assert(spec("r1c1m1x1") == tuple("1", "1", "1", "1"));
4842             assert(spec("r1_100c21m5x5") == tuple("1_100", "21", "5", "5"));
4843             assert(spec("m1x2") == tuple("0", "0", "1", "2"));
4844         }
4845 
4846 
4847         bool isSliceExp(string exp) pure nothrow @safe
4848         {
4849             bool isAllDigit(string str) pure nothrow @safe
4850             {
4851                 if(str.length == 0)
4852                     return false;
4853 
4854                 foreach(c; str)
4855                     if(!(c.isDigit || c == '_'))
4856                         return false;
4857                 return true;
4858             }
4859 
4860             auto sp = spec(exp);
4861             return (exp[0] == 'm' || exp[0] == 'r' || exp[0] == 'c') && isAllDigit(sp.rb) && isAllDigit(sp.cb) && isAllDigit(sp.rs) && isAllDigit(sp.cs);
4862         }
4863         unittest{
4864             assert(isSliceExp("r1c1m1x1"));
4865             assert(isSliceExp("r1_100c21m5x5"));
4866             assert(isSliceExp("m1x2"));
4867             assert(!isSliceExp("m2m1"));
4868             assert(!isSliceExp("_2mx1"));
4869             assert(isSliceExp("c1m1x1"));
4870         }
4871 
4872 
4873         // for vec
4874         char swizzleType(string exp) pure nothrow @safe
4875         {
4876             if('a' <= exp[0] && exp[0] <= 'h')
4877                 return 'a';
4878             else
4879                 return 'x';
4880         }
4881         unittest{
4882             assert(swizzleType("aaaaaaa") == 'a');
4883             assert(swizzleType("aaaahaa") == 'a');
4884             assert(swizzleType("xxxx") == 'x');
4885             assert(swizzleType("xyzv") == 'x');
4886         }
4887 
4888 
4889         bool isSwizzlable(T)(string exp) pure nothrow @safe
4890         {
4891             static if(isVector!T){
4892               enum size = T.length - 1;
4893 
4894               if(swizzleType(exp) == 'a'){
4895                   foreach(c; exp)
4896                       if(c > 'a' + size)
4897                           return false;
4898                   return true;
4899               }else{
4900                   foreach(c; exp)
4901                       if(c != 'x' && c != 'y' && c != 'z' && c != 'w')
4902                           return false;
4903                   return true;
4904               }
4905             }
4906             else
4907               return false;
4908         }
4909         unittest{
4910             alias V3 = SMatrix!(int, 1, 3);
4911             assert(isSwizzlable!V3("aaa"));
4912             assert(isSwizzlable!V3("abc"));
4913             assert(!isSwizzlable!V3("abd"));
4914             assert(isSwizzlable!V3("xyz"));
4915             assert(!isSwizzlable!V3("xyzv"));
4916 
4917             alias V4 = SMatrix!(int, 1, 4);
4918             assert(isSwizzlable!V4("xyzw"));
4919             assert(!isSwizzlable!V4("xyzv"));
4920         }
4921 
4922 
4923         bool isSlicable(T, string exp)() pure nothrow @safe
4924         {
4925           static if(isSliceExp(exp)){
4926             enum sp = spec(exp);
4927             return ((mixin(sp.rs) + mixin(sp.rb)) <= T.cols) && ((mixin(sp.cs) + mixin(sp.cb)) <= T.rows);
4928           }
4929           else
4930             return false;
4931         }
4932         unittest{
4933             alias M33 = SMatrix!(int, 3, 3);
4934             assert(isSlicable!(M33, "m3x3"));
4935             assert(isSlicable!(M33, "m1x3"));
4936             assert(isSlicable!(M33, "r1m2x3"));
4937             assert(isSlicable!(M33, "c1m2x2"));
4938         }
4939     }
4940 
4941 
4942     return Swizzle!()(mat);
4943 }
4944 
4945 unittest{
4946     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4947     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
4948 
4949 
4950     auto org = matrix!((i, j) => i * 3 + j)();
4951     SMatrix!(size_t, 4, 4) a = org;
4952     auto m = a.swizzle.m2x2;
4953     static assert(isNarrowMatrix!(typeof(m)));
4954     assert(m == org);
4955 
4956 
4957     auto m2 = a.swizzle.r1c1m2x2;
4958     static assert(isNarrowMatrix!(typeof(m2)));
4959     assert(m2 == matrix!((i, j) => (i+1)*3 + j + 1)());
4960 
4961 
4962     assert(a.swizzle.m1x4.swizzle.xyzw == a.swizzle.m1x4);
4963 }
4964 
4965 
4966 /**
4967 行ベクトルのランダムアクセスレンジ
4968 */
4969 auto rowVectors(A)(A mat) @property
4970 if(isNarrowMatrix!A && !isAbstractMatrix!A)
4971 {
4972     static struct RowVectors()
4973     {
4974         auto front() @property { return this.opIndex(0); }
4975         auto back() @property { return this.opIndex(_end-1); }
4976         void popFront() @property { ++_idx; }
4977         void popBack() @property { --_end; }
4978         bool empty() @property const { return _idx == _end; }
4979         auto save() @property { return this; }
4980 
4981 
4982 
4983         auto opIndex(size_t i)
4984         {
4985             static struct RowVectorByIndex()
4986             {
4987                 alias rows = _m.rows;
4988                 enum cols = 1;
4989 
4990 
4991                 auto ref opIndex(size_t i, size_t j) inout
4992                 in{
4993                     assert(i < rows);
4994                     assert(j < cols);
4995                 }
4996                 body{
4997                     return _m[i, _idx];
4998                 }
4999 
5000 
5001                 mixin(defaultExprOps!(false));
5002 
5003 
5004                 size_t _idx;
5005                 A _m;
5006             }
5007 
5008 
5009             return RowVectorByIndex!()(i + _idx, _m);
5010         }
5011 
5012 
5013         size_t length() const @property
5014         {
5015             return _end - _idx;
5016         }
5017 
5018 
5019         alias opDispatch = length;
5020 
5021       private:
5022         size_t _idx;
5023         size_t _end;
5024         A _m;
5025     }
5026 
5027 
5028     return RowVectors!()(0, mat.cols, mat);
5029 }
5030 unittest
5031 {
5032     real[3][3] mStack = [[1, 2, 2],
5033                          [2, 1, 1],
5034                          [2, 2, 2]];
5035 
5036     auto r = matrix(mStack).rowVectors;
5037 
5038     static assert(isRandomAccessRange!(typeof(r)));
5039 
5040     foreach(i; 0 .. 3)
5041         foreach(j; 0 .. 3)
5042             assert(r[i][j] == mStack[j][i]);
5043 }
5044 
5045 
5046 /**
5047 行ベクトルのランダムアクセスレンジ
5048 */
5049 auto columnVectors(A)(A mat) @property
5050 if(isNarrowMatrix!A && !isAbstractMatrix!A)
5051 {
5052     static struct ColumnVectors()
5053     {
5054         auto front() @property { return this.opIndex(0); }
5055         auto back() @property { return this.opIndex(_end-1); }
5056         void popFront() @property { ++_idx; }
5057         void popBack() @property { --_end; }
5058         bool empty() @property const { return _idx == _end; }
5059         auto save() @property { return this; }
5060 
5061 
5062 
5063         auto opIndex(size_t i)
5064         {
5065             static struct ColumnVectorByIndex()
5066             {
5067                 enum rows = 1;
5068                 alias cols = _m.cols;
5069 
5070 
5071                 auto ref opIndex(size_t i, size_t j) inout
5072                 in{
5073                     assert(i < rows);
5074                     assert(j < cols);
5075                 }
5076                 body{
5077                     return _m[_idx, j];
5078                 }
5079 
5080 
5081                 mixin(defaultExprOps!(false));
5082 
5083 
5084                 size_t _idx;
5085                 A _m;
5086             }
5087 
5088             return ColumnVectorByIndex!()(i + _idx, _m);
5089         }
5090 
5091 
5092         size_t length() const @property
5093         {
5094             return _end - _idx;
5095         }
5096 
5097 
5098         alias opDispatch = length;
5099 
5100       private:
5101         size_t _idx;
5102         size_t _end;
5103         A _m;
5104     }
5105 
5106 
5107     return ColumnVectors!()(0, mat.rows, mat);
5108 }
5109 unittest
5110 {
5111     real[3][3] mStack = [[1, 2, 2],
5112                          [2, 1, 1],
5113                          [2, 2, 2]];
5114 
5115     auto r = matrix(mStack).columnVectors;
5116 
5117     static assert(isRandomAccessRange!(typeof(r)));
5118 
5119     foreach(i; 0 .. 3)
5120         foreach(j; 0 .. 3)
5121             assert(r[i][j] == mStack[i][j]);
5122 }
5123 
5124 
5125 /**
5126 行列の跡(trace)を返します。正方行列についてのみ定義されます
5127 */
5128 ElementType!A trace(A)(A mat)
5129 if(isNarrowMatrix!A && !isAbstractMatrix!A && (!(hasStaticRows!A && hasStaticCols!A) || is(typeof({static assert(A.rows == A.cols);}))))
5130 {
5131     alias ElementType!A T;
5132     T sum = cast(T)0;
5133 
5134     foreach(i; 0 .. mat.rows)
5135         sum += mat[i, i];
5136 
5137     return sum;
5138 }
5139 unittest{
5140     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5141     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5142 
5143 
5144     auto m = SMatrix!(int, 2, 2)();
5145     m[0, 0] = 0; m[0, 1] = 1;
5146     m[1, 0] = 2; m[1, 1] = 3;
5147 
5148     auto tr = m.trace;
5149     assert(tr == 3);
5150 }
5151 
5152 
5153 auto dot(V1, V2)(V1 vec1, V2 vec2)
5154 if(isVector!V1 && isVector!V2 && (!(hasStaticLength!V1 && hasStaticLength!V2) || is(typeof({static assert(V1.length == V2.length);}))))
5155 in{
5156     static if(!(hasStaticLength!V1 && hasStaticLength!V2))
5157     {
5158         assert(vec1.length == vec2.length);
5159     }
5160 }
5161 body{
5162     alias Unqual!(typeof(ElementType!V1.init * ElementType!V2.init)) T;
5163     T sum = cast(T)0;
5164 
5165     foreach(i; 0 .. vec1.length){
5166         sum += vec1[i] * vec2[i];
5167     }
5168 
5169     return sum;
5170 }
5171 unittest{
5172     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5173     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5174 
5175 
5176     auto rv = SRVector!(int, 3)(),
5177          cv = SCVector!(int, 3)();
5178 
5179     rv.array[] = [0, 1, 2];
5180     cv.array[] = [1, 2, 3];
5181 
5182     assert((rv.pref * cv)[0] == 8);  //8
5183     assert(rv.dot(cv) == 8);
5184     assert(cv.dot(rv) == 8);
5185 
5186     assert(rv.dot(rv) == 5);
5187     assert(cv.dot(cv) == 14);
5188 
5189 
5190     assert(approxEqual((rv.pref * 0.5).dot(rv), 2.5));
5191 }
5192 
5193 
5194 /**
5195 ベクトル同士のクロス積
5196 */
5197 auto cross(Major mjr = Major.column, V1, V2)(V1 vec1, V2 vec2)
5198 if(isVector!V1 && isVector!V2 && (hasStaticLength!V1 && is(typeof({static assert(V1.length == 3);})))
5199                               && (hasStaticLength!V2 && is(typeof({static assert(V2.length == 3);}))))
5200 in{
5201     assert(vec1.length == 3);
5202     assert(vec2.length == 3);
5203 }
5204 body{
5205     static struct CrossResult
5206     {
5207         enum rows = mjr == Major.row ? 1 : 3;
5208         enum cols = mjr == Major.row ? 3 : 1;
5209 
5210 
5211         auto opIndex(size_t i, size_t j) const
5212         in{
5213             assert(i < rows);
5214             assert(j < cols);
5215         }
5216         body{
5217             switch(i + j){
5218               case 0: return _v1[1] * _v2[2] - _v1[2] * _v2[1];
5219               case 1: return _v1[2] * _v2[0] - _v1[0] * _v2[2];
5220               case 2: return _v1[0] * _v2[1] - _v1[1] * _v2[0];
5221               default: assert(0);
5222             }
5223         }
5224 
5225         mixin(defaultExprOps!(false));
5226 
5227       private:
5228         V1 _v1;
5229         V2 _v2;
5230     }
5231 
5232     return CrossResult(vec1, vec2);
5233 }
5234 unittest{
5235     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5236     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5237 
5238 
5239     auto rv = SVector!(int, 3)(),
5240          cv = SVector!(int, 3)();
5241 
5242     rv.array[] = [0, 1, 2];
5243     cv.array[] = [1, 2, 3];
5244 
5245     auto cp = rv.cross(cv);
5246 
5247     static assert(isVector!(typeof(cp)));
5248     static assert(hasStaticLength!(typeof(cp)));
5249     static assert(hasStaticRows!(typeof(cp)));
5250     static assert(hasStaticCols!(typeof(cp)));
5251 
5252     assert(cp[0] == -1);
5253     assert(cp[1] == 2);
5254     assert(cp[2] == -1);
5255 }
5256 
5257 
5258 /**
5259 直積
5260 */
5261 auto cartesian(V1, V2)(V1 vec1, V2 vec2)
5262 if(isVector!V1 && isVector!V2)
5263 {
5264     static struct Cartesian()
5265     {
5266         alias rows = _vec1.length;
5267         alias cols = _vec2.length;
5268 
5269 
5270         auto opIndex(size_t i, size_t j) const
5271         in{
5272             assert(i < rows);
5273             assert(j < cols);
5274         }
5275         body{
5276             return _vec1[i] * _vec2[j];
5277         }
5278 
5279 
5280         mixin(defaultExprOps!(false));
5281 
5282 
5283       private:
5284         V1 _vec1;
5285         V2 _vec2;
5286     }
5287 
5288 
5289     return Cartesian!()(vec1, vec2);
5290 }
5291 unittest{
5292     scope(failure) {writefln("Unittest failure :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5293     scope(success) {writefln("Unittest success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
5294 
5295 
5296     auto v1 = [0, 1, 2, 3].toMatrix!(3, 1);
5297     auto v2 = [2, 3, 4, 5].toMatrix!(1, 2);
5298 
5299     assert(v1.cartesian(v2) == v1 * v2);
5300     static assert(hasStaticRows!(typeof(v1.cartesian(v2))));
5301     static assert(hasStaticCols!(typeof(v1.cartesian(v2))));
5302 }
5303 
5304 
5305 
5306 /**
5307 置換行列を作ります
5308 */
5309 auto permutation(size_t size = wild, size_t)(const size_t[] pos) pure nothrow @safe
5310 in{
5311     foreach(e; pos)
5312         assert(e < pos.length);
5313 
5314   static if(size != wild)
5315     assert(pos.length == size);
5316 }
5317 body{
5318     static struct Permutation
5319     {
5320       static if(size != wild)
5321         enum rows = size;
5322       else
5323         size_t rows() pure nothrow @safe const @property { return _pos.length; }
5324 
5325         alias cols = rows;
5326 
5327 
5328         auto opIndex(size_t i, size_t j) pure nothrow @safe const 
5329         {
5330             return _pos[i] == j ? 1 : 0;
5331         }
5332 
5333 
5334         mixin(defaultExprOps!(false));
5335 
5336 
5337         @property auto inverse() pure nothrow @safe const
5338         {
5339             static struct InvPermutation
5340             {
5341                 static if(size != wild)
5342                 enum rows = size;
5343               else
5344                 size_t rows() pure nothrow @safe const @property { return _pos.length; }
5345 
5346                 alias cols = rows;
5347 
5348 
5349                 auto opIndex(size_t i, size_t j) pure nothrow @safe const
5350                 {
5351                     return _pos[j] == i ? 1 : 0;
5352                 }
5353 
5354 
5355                 mixin(defaultExprOps!(false));
5356 
5357 
5358                 @property auto inverse() pure nothrow @safe const
5359                 {
5360                     return Permutation(_pos);
5361                 }
5362 
5363 
5364               private:
5365                 const(size_t)[] _pos;
5366             }
5367 
5368 
5369             return InvPermutation(_pos);
5370         }
5371 
5372 
5373         @property const(size_t)[] exchangeTable() pure nothrow @safe const
5374         {
5375             return _pos;
5376         }
5377 
5378 
5379       private:
5380         const(size_t)[] _pos;
5381     }
5382 
5383 
5384     return Permutation(pos);
5385 }
5386 
5387 
5388 template isPermutationMatrix(A)
5389 {
5390     enum isPermutationMatrix = isNarrowMatrix!A && is(Unqual!(typeof(A.init.exchangeTable)) : size_t[]);
5391 }
5392 
5393 
5394 
5395 struct PLU(M)
5396 if(isNarrowMatrix!M && !isAbstractMatrix!M)
5397 {
5398   static if(hasStaticRows!M)
5399     alias rows = lu.rows;
5400   else
5401     @property size_t rows() pure nothrow @safe const { return piv.length; }
5402 
5403     alias cols = rows;
5404 
5405     size_t[] piv;
5406     bool isEvenP;
5407     M lu;
5408 
5409 
5410     auto p() pure nothrow @safe const
5411     {
5412         return permutation(piv);
5413     }
5414 
5415 
5416 
5417     auto l() pure nothrow @safe
5418     {
5419         static struct L()
5420         {
5421           static if(hasStaticRows!M)
5422             enum rows = M.rows;
5423           else static if(hasStaticCols!M)
5424             enum rows = M.cols;
5425           else
5426             size_t rows() const  @property { return _lu.rows; }
5427 
5428             alias cols = rows;
5429 
5430 
5431             typeof(_lu[0, 0]) opIndex(size_t i, size_t j) const
5432             in{
5433                 assert(i < rows);
5434                 assert(j < cols);
5435             }
5436             body{
5437                 if(i == j)
5438                     return cast(typeof(return))1;
5439                 else if(i < j)
5440                     return cast(typeof(return))0;
5441                 else
5442                     return _lu[i, j];
5443             }
5444 
5445 
5446             mixin(defaultExprOps!(false));
5447 
5448 
5449           private:
5450             M _lu;
5451         }
5452 
5453 
5454         return L!()(lu);
5455     }
5456 
5457 
5458 
5459     auto u() pure nothrow @safe
5460     {
5461         static struct U()
5462         {
5463           static if(hasStaticRows!M)
5464             enum rows = M.rows;
5465           else static if(hasStaticCols!M)
5466             enum rows = M.cols;
5467           else
5468             size_t rows() const  @property { return _lu.rows; }
5469 
5470             alias cols = rows;
5471 
5472 
5473             typeof(_lu[0, 0]) opIndex(size_t i, size_t j) const
5474             in{
5475                 assert(i < rows);
5476                 assert(j < cols);
5477             }
5478             body{
5479                 if(i > j)
5480                     return cast(typeof(return))0;
5481                 else
5482                     return _lu[i, j];
5483             }
5484 
5485 
5486             mixin(defaultExprOps!(false));
5487 
5488 
5489           private:
5490             M _lu;
5491         }
5492 
5493 
5494         return U!()(lu);
5495     }
5496 
5497 
5498     /**
5499     Ax = bとなるxを解きます
5500     */
5501     auto solveInPlace(V)(V b)
5502     if(isVector!V /*&& isFloatingPoint!(ElementType!V) && is(typeof({b[0] = real.init;}))*/ )
5503     in{
5504         assert(b.length == rows);
5505     }
5506     body{
5507         /*
5508         Ax = bの両辺にPをかけることにより
5509         PAx = Pbとなるが、LU分解によりPA = LUであるから、
5510         LUx = Pbである。
5511 
5512         ここで、y=Uxとなるyベクトルを考える。
5513         Ly = Pbである。
5514         Lは下三角行列なので、簡単にyベクトルは求まる。
5515 
5516         次に、Ux=yより、xベクトルを同様に求めれば良い
5517         */
5518 
5519         immutable size_t size = rows;
5520 
5521         // b <- Pb
5522         b = this.p * b;
5523 
5524         // Ly=Pbからyを求める
5525         foreach(i; 1 .. size)
5526             foreach(j; 0 .. i)
5527                 b[i] -= lu[i, j] * b[j];
5528 
5529         // Ux=Py
5530         foreach_reverse(i; 0 .. size){
5531             foreach_reverse(j; i+1 .. size)
5532                 b[i] -= lu[i, j] * b[j];
5533 
5534             b[i] /= lu[i, i];
5535         }
5536     }
5537 
5538 
5539     /**
5540     逆行列を求める
5541     */
5542     M inverse() @property
5543     {
5544         immutable size_t size = lu.rows;
5545 
5546         M m = identity!(ElementType!M)().congeal(size, size);
5547 
5548         foreach(i; 0 .. lu.cols)
5549             this.solveInPlace(m.rowVectors[i]);
5550 
5551         return m;
5552     }
5553 
5554 
5555     auto det() @property
5556     {
5557         auto dst = cast(ElementType!M)(isEvenP ? 1 : -1);
5558         foreach(i; 0 .. rows)
5559             dst *= lu[i, i];
5560 
5561         return dst;
5562     }
5563 }
5564 
5565 
5566 /**
5567 In-Placeで、行列をLU分解します。
5568 
5569 "Numerical Recipes in C"
5570 */
5571 PLU!(A) pluDecomposeInPlace(A)(A m)
5572 if(isNarrowMatrix!A && hasLvalueElements!A && (!hasStaticRows!A || !hasStaticCols!A || is(typeof({static assert(A.rows == A.cols);}))))
5573 in{
5574     assert(m.rows == m.cols);
5575 }
5576 body{
5577     immutable size = m.rows;
5578     scope vv = new real[size];
5579     bool isEvenP;
5580     size_t[] idx = new size_t[size];
5581 
5582     foreach(i, ref e; idx)
5583         e = i;
5584 
5585     foreach(i; 0 .. size){
5586         real big = 0;
5587 
5588         foreach(j; 0 .. size){
5589             immutable temp = m[i, j].abs();
5590             if(temp > big)
5591                 big = temp;
5592         }
5593 
5594         if(big == 0) enforce("Input matrix is a singular matrix");
5595 
5596         vv[i] = 1.0 / big;
5597     }
5598 
5599 
5600     foreach(j; 0 .. size){
5601         foreach(i; 0 .. j){
5602             auto sum = m[i, j];
5603             foreach(k; 0 .. i) sum -= m[i, k] * m[k, j];
5604             m[i, j] = sum;
5605         }
5606 
5607         real big = 0;
5608         size_t imax;
5609         foreach(i; j .. size){
5610             auto sum = m[i, j];
5611             foreach(k; 0 .. j) sum -= m[i, k] * m[k, j];
5612             m[i, j] = sum;
5613 
5614             immutable dum = vv[i] * sum.abs();
5615             if(dum >= big){
5616                 big = dum;
5617                 imax = i;
5618             }
5619         }
5620 
5621         if(j != imax){
5622             foreach(k; 0 .. size)
5623                 swap(m[imax, k], m[j, k]);
5624 
5625             isEvenP = !isEvenP;
5626             vv[imax] = vv[j];
5627 
5628             swap(idx[j], idx[imax]);
5629         }
5630 
5631         //idx[j] = imax;
5632 
5633         //if(m[j, j] == 0) m[j, j] = 1.0E-20;
5634 
5635         if(j != size-1){
5636             immutable dum = 1 / m[j, j];
5637             foreach(i; j+1 .. size)
5638                 m[i, j] *= dum;
5639         }
5640     }
5641 
5642     return PLU!A(idx, isEvenP, m);
5643 }
5644 unittest{
5645     real[3][3] mStack = [[1, 2, 2],
5646                          [2, 1, 1],
5647                          [2, 2, 2]];
5648 
5649     auto m = matrix(mStack);
5650 
5651     SMatrix!(real, 3, 3) org = m;
5652     auto plu = m.pluDecomposeInPlace();
5653 
5654     SMatrix!(real, 3, 3) result = plu.p.inverse * plu.l * plu.u;
5655 
5656     foreach(i; 0 .. 3) foreach(j; 0 .. 3)
5657         assert(approxEqual(result[i, j], org[i, j]));   // A = P^(-1)LU
5658 
5659     assert(approxEqual(plu.det, 0));
5660 }
5661 
5662 unittest{
5663     real[3][3] mStack = [[2, 4, 2],
5664                          [4, 10, 3],
5665                          [3, 7, 1]];
5666 
5667     auto m = mStack.matrix();
5668 
5669     SMatrix!(real, 3, 3) org = m;
5670     auto plu = m.pluDecomposeInPlace();
5671 
5672     auto v = matrix!(3, 1)(cast(real[])[8, 17, 11]);
5673 
5674     plu.solveInPlace(v);
5675     foreach(i; 0 .. 3)
5676         assert(approxEqual(v[i], 1));
5677 }
5678 
5679 unittest{
5680     real[3][3] mStack = [[2, 4, 2],
5681                          [4, 10, 3],
5682                          [3, 7, 1]];
5683 
5684     auto m = mStack.matrix();
5685 
5686     SMatrix!(real, 3, 3) org = m;
5687     auto plu = m.pluDecomposeInPlace();
5688     auto iden = org.pref * plu.inverse;
5689     
5690     foreach(i; 0 .. 3)
5691         foreach(j; 0 .. 3)
5692             assert(approxEqual(iden[i, j], identity!real[i, j]));
5693 }
5694 
5695 
5696 /**
5697 ベクトルのノルムを計算します
5698 */
5699 auto norm(real N = 2, V)(V v)
5700 {
5701     real sum = 0;
5702     foreach(i; 0 .. v.length)
5703         sum += v[i] ^^ N;
5704     return sum ^^ (1/N);
5705 }