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