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