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