1 module data.vector;
2 
3 /++
4   Vector is default class for Statistics
5 +/
6 struct Vector {
7   import std.math : sqrt;
8   
9   double[] comp;
10 
11   // ===========================================================================
12   // Constructor
13   // ===========================================================================
14   /++
15     Like iota
16   +/
17   this(double start, double end, double step = 1) {
18     long l = cast(long)((end - start + 1) / step);
19     this.comp.length = l;
20     foreach(i; 0 .. l) {
21       this.comp[i] = start + cast(double)i * step;
22     }
23   }
24 
25   /++
26     array to Vector
27   +/
28   this(double[] vec) {
29     this.comp = vec;
30   }
31 
32   /++
33     Intialize with number
34   +/
35   this(double num, long l) {
36     this.comp.length = l;
37     foreach(i; 0 .. l) {
38       this.comp[i] = num;
39     }
40   }
41 
42   void toString(scope void delegate(const(char)[]) sink) const {
43     import std.stdio : write;
44 
45     sink("Vector ");
46     this.comp.write;
47   }
48 
49   // ===========================================================================
50   // Basic Operator
51   // ===========================================================================
52   pure long length() const {
53     return this.comp.length;
54   }
55   
56   // ===========================================================================
57   //    Void Functions
58   // ===========================================================================
59   void add_void(T)(T x) {
60     auto X = cast(double)x;
61     foreach(i; 0 .. this.comp.length) {
62       this.comp[i] += X;
63     }
64   }
65 
66   void sub_void(T)(T x) {
67     auto X = cast(double)x;
68     foreach(i; 0 .. this.comp.length) {
69       this.comp[i] -= X;
70     }
71   }
72 
73   void mul_void(T)(T x) {
74     auto X = cast(double)x;
75     foreach(i; 0 .. this.comp.length) {
76       this.comp[i] *= X;
77     }
78   }
79 
80   void div_void(T)(T x) {
81     auto X = cast(double)x;
82     foreach(i; 0 .. this.comp.length) {
83       this.comp[i] /= X;
84     }
85   }
86 
87   void pow_void(T)(T x) {
88     auto X = cast(double)x;
89     foreach(i; 0 .. this.comp.length) {
90       this.comp[i] ^^= X;
91     }
92   }
93 
94   void sqrt_void() {
95     foreach(i; 0 .. this.comp.length) {
96       this.comp[i] = sqrt(this.comp[i]);
97     }
98   }
99 
100   // TODO: What is it delegate
101   void fmap_void(double delegate(double) f) {
102     foreach(i; 0 .. this.comp.length) {
103       this.comp[i] = f(this.comp[i]);
104     }
105   }
106 
107   // ===========================================================================
108   //    Vector Function
109   // ===========================================================================
110   Vector fmap(double delegate(double) f) {
111     Vector that = Vector(comp);
112     that.fmap_void(f);
113     return that;
114   }
115 
116   const double mapReduce(double delegate(double) f) {
117     double s = 0;
118     foreach(e; this.comp) {
119       s += f(e);
120     }
121     return s;
122   }
123 
124   Vector sqrt() {
125     return this.fmap(t => t.sqrt);
126   }
127   // ===========================================================================
128   // Operator Overloading
129   // ===========================================================================
130   /++
131     Getter
132   +/
133   pure double opIndex(size_t i) const {
134     return this.comp[i];
135   }
136 
137   /++
138     Setter
139   +/
140   void opIndexAssign(double value, size_t i) {
141     this.comp[i] = value;
142   }
143 
144   /++
145     Binary Operator with Scalar
146   +/
147   Vector opBinary(string op)(double rhs) {
148     double[] temp;
149     auto l = this.comp.length;
150     temp.length = l;
151     temp[] = 0;
152 
153     switch(op) {
154       case "+":
155         foreach(i; 0 .. l) {
156           temp[i] = this.comp[i] + rhs;
157         }
158         break;
159       case "-":
160         foreach(i; 0 .. l) {
161           temp[i] = this.comp[i] - rhs;
162         }
163         break;
164       case "*":
165         foreach(i; 0 .. l) {
166           temp[i] = this.comp[i] * rhs;
167         }
168         break;
169       case "/":
170         foreach(i; 0 .. l) {
171           temp[i] = this.comp[i] / rhs;
172         }
173         break;
174       case "^^":
175         foreach(i; 0 .. l) {
176           temp[i] = this.comp[i] ^^ rhs;
177         }
178         break;
179       default:
180         break;
181     }
182     return Vector(temp);
183   }
184 
185   /++
186     Binary Operator with Vector
187   +/
188   Vector opBinary(string op)(Vector rhs) {
189     double[] temp;
190     auto l = this.comp.length;
191     temp.length = l;
192     temp[] = 0;
193 
194     switch(op) {
195       case "+":
196         foreach(i; 0 .. l) {
197           temp[i] = this.comp[i] + rhs.comp[i];
198         }
199         break;
200       case "-":
201         foreach(i; 0 .. l) {
202           temp[i] = this.comp[i] - rhs.comp[i];
203         }
204         break;
205       case "*":
206         foreach(i; 0 .. l) {
207           temp[i] = this.comp[i] * rhs.comp[i];
208         }
209         break;
210       case "/":
211         foreach(i; 0 .. l) {
212           temp[i] = this.comp[i] / rhs.comp[i];
213         }
214         break;
215       default:
216         break;
217     }
218     return Vector(temp);
219   }
220 
221   /++
222     Inner Product
223   +/
224   double dot(Vector rhs) {
225     double s = 0;
226     foreach(i; 0 .. this.comp.length) {
227       s += cast(double)this[i] * cast(double)rhs[i];
228     }
229     return s;
230   }
231 }
232 
233 // =============================================================================
234 // Matrix
235 // =============================================================================
236 /++
237   Matrix Structure
238 +/
239 struct Matrix {
240   import std.array : join;
241   // import std.parallelism : taskPool, parallel; // Perfect Parallel!
242 
243   Vector val;
244   long row;
245   long col;
246   bool byRow;
247   double[][] data;
248   
249   // ===========================================================================
250   // Constructor
251   // ===========================================================================
252   this(double[] vec, long r, long c, bool byrow = false) {
253     this.val = Vector(vec);
254     this.row = r;
255     this.col = c;
256     this.byRow = byrow;
257     this.data = this.matForm; // heavy cost
258   }
259 
260   this(Vector vec, long r, long c, bool byrow = false) {
261     this.val = vec;
262     this.row = r;
263     this.col = c;
264     this.byRow = byrow;
265     this.data = this.matForm; // heavy cost
266   }
267 
268   this(double[][] mat) {
269     this.val = Vector(mat.join); // join is cheap
270     this.row = mat.length;
271     this.col = mat[0].length;
272     this.byRow = true;
273     this.data = mat; // no cost
274   }
275 
276   this(Matrix mat) {
277     this.val = mat.val;
278     this.row = mat.row;
279     this.col = mat.col;
280     this.byRow = mat.byRow;
281     this.data = mat.data;
282   }
283 
284   this(double num, long r, long c) {
285     this.val = Vector(num, r*c);
286     this.row = r;
287     this.col = c;
288     this.byRow = false;
289     this.data = this.matForm;
290   }
291 
292   // ===========================================================================
293   // String
294   // ===========================================================================
295   void toString(scope void delegate(const(char)[]) sink) const {
296     import std.stdio : write;
297 
298     sink("Matrix ");
299     this.data.write;
300   }
301 
302   double[][] matForm() const {
303     long c = this.col;
304     long r = this.row;
305     double[][] mat;
306     mat.length = r;
307 
308     if (byRow) {
309       foreach(i; 0 .. r) {
310         mat[i].length = c;
311         foreach(j; 0 .. c) {
312           long k = c*i + j;
313           mat[i][j] = this.val[k];
314         }
315       }
316     } else {
317       foreach(j; 0 .. c) {
318         foreach(i; 0 .. r) {
319           mat[i].length = c;
320           long k = r*j + i;
321           mat[i][j] = this.val[k];
322         }
323       }
324     }
325     return mat;
326   }
327 
328   /++
329     Reduce cost
330   +/
331   void refresh() {
332     this.data = this.matForm;
333   }
334   // ===========================================================================
335   // Operator Overloading
336   // ===========================================================================
337   /++
338     Getter
339   +/
340   double opIndex(size_t i, size_t j) const {
341     return this.data[i][j];
342   }
343 
344   /++
345     Setter
346   +/
347   void opIndexAssign(double value, size_t i, size_t j) {
348     this.data[i][j] = value;
349   }
350 
351   /++
352     Binary Operator with Scalar
353   +/
354   Matrix opBinary(string op)(double rhs) {
355     auto r = this.row;
356     auto c = this.col;
357     
358     double[][] temp = zerosMat(r, c);
359     
360     switch(op) {
361       case "+":
362         foreach(i, ref rows; temp) {
363           foreach(j; 0 .. c) {
364             rows[j] = this.data[i][j] + rhs;
365           }
366         }
367         break;
368       case "-":
369         foreach(i, ref rows; temp) {
370           foreach(j; 0 .. c) {
371             rows[j] = this.data[i][j] - rhs;
372           }
373         }
374         break;
375       case "*":
376         foreach(i, ref rows; temp) {
377           foreach(j; 0 .. c) {
378             rows[j] = this.data[i][j] * rhs;
379           }
380         }
381         break;
382       case "/":
383         foreach(i, ref rows; temp) {
384           foreach(j; 0 .. c) {
385             rows[j] = this.data[i][j] / rhs;
386           }
387         }
388         break;
389       case "^^":
390         foreach(i, ref rows; temp) {
391           foreach(j; 0 .. c) {
392             rows[j] = this.data[i][j] ^^ rhs;
393           }
394         }
395         break;
396       default:
397         break;
398     }
399     return Matrix(temp);
400   }
401 
402   /++
403     Binary Operator with Matrix
404   +/
405   Matrix opBinary(string op)(Matrix rhs) {
406     auto r = this.row;
407     auto c = this.col;
408     
409     double[][] temp = zerosMat(r, c);
410 
411     switch(op) {
412       case "+":
413         foreach(i, ref rows; temp) {
414           foreach(j; 0 .. c) {
415             rows[j] = this.data[i][j] + rhs.data[i][j];
416           }
417         }
418         break;
419       case "-":
420         foreach(i, ref rows; temp) {
421           foreach(j; 0 .. c) {
422             rows[j] = this.data[i][j] - rhs.data[i][j];
423           }
424         }
425         break;
426       case "*":
427         foreach(i, ref rows; temp) {
428           foreach(j; 0 .. c) {
429             rows[j] = this.data[i][j] * rhs.data[i][j];
430           }
431         }
432         break;
433       case "/":
434         foreach(i, ref rows; temp) {
435           foreach(j; 0 .. c) {
436             rows[j] = this.data[i][j] / rhs.data[i][j];
437           }
438         }
439         break;
440       case "%": // Parallel Multiplication
441         assert(this.col == rhs.row);
442         
443         auto m = this.data;
444         auto n = rhs.data;
445         auto l1 = this.row;
446         auto l2 = rhs.col;
447 
448         auto target = initMat(l1, l2);
449 
450         foreach(i, ref rows; target) {
451           foreach(j; 0 .. l2) {
452             double s = 0;
453             foreach(k; 0 .. this.col) {
454               s += m[i][k] * n[k][j];
455             }
456             rows[j] = s;
457           }
458         }
459         temp = target;
460         break;
461       default:
462         break;
463     }
464 
465     return Matrix(temp);
466   }
467 
468   // ===========================================================================
469   // Matrix Utils
470   // ===========================================================================
471   /++
472     True -> False
473   +/
474   Matrix makeFalse() {
475     assert(this.byRow);
476     double[] v_ref = this.val.comp; // Double array
477     auto r = this.row;
478     auto c = this.col;
479     auto l = r * c - 1;
480     
481     double[] v_con;
482     v_con.length = l + 1;
483 
484     foreach(i; 0 .. l) {
485       auto s = (i * c) % l;
486       v_con[i] = v_ref[s];
487     }
488     v_con[l] = v_ref[l];
489 
490     return Matrix(v_con, r, c);
491   }
492 
493   /++
494     Transpose
495   +/
496   Matrix transpose() const { // Serial
497     auto l1 = this.row;
498     auto l2 = this.col;
499     auto m = this.data;
500     Matrix temp;
501     auto target = initMat(l2, l1);
502     foreach(i, ref rows; target) {
503       foreach(j; 0 .. l1) {
504         rows[j] = m[j][i];
505       }
506     }
507     temp = Matrix(target);
508     return temp;
509   }
510 
511   // Matrix transpose() const { // Parallel
512   //   auto l1 = this.row;
513   //   auto l2 = this.col;
514   //   auto m = this.data;
515   //   Matrix temp;
516   //   auto target = initMat(l2, l1);
517   //   foreach(i, ref rows; taskPool.parallel(target)) {
518   //     foreach(j; 0 .. l1) {
519   //       rows[j] = m[j][i];
520   //     }
521   //   }
522   //   temp = Matrix(target);
523   //   return temp;
524   // }
525 
526   /++
527     Check Square Matrix
528   +/
529   bool isSquare() const {
530     return this.row == this.col;
531   }
532 
533   import std.typecons : tuple;
534 
535   /++
536     LU Decomposition
537   +/
538   auto lu() const {
539     auto n = this.row;
540     assert(this.isSquare);
541 
542     const double[][] m = this.data;
543     double[][] u = zerosMat(n,n);
544     double[][] l = eyeMat(n);
545     u[0][] = m[0][];
546 
547     foreach(i; 0 .. n) {
548       foreach(k; i .. n) {
549         double s = 0;
550         foreach(j; 0 .. i) {
551           s += l[i][j] * u[j][k];
552         }
553         u[i][k] = m[i][k] - s;
554       }
555 
556       foreach(k; i+1 .. n) {
557         double s = 0;
558         foreach(j; 0 .. i) {
559           s += l[k][j] * u[j][i];
560         }
561         l[k][i] = (m[k][i] - s) / u[i][i];
562       }
563     }
564     Matrix L = Matrix(l);
565     Matrix U = Matrix(u);
566     return tuple(L, U);
567   }
568 
569   /++
570     Determinant (Using LU Decomposition)
571   +/
572   double det() const { // Use LU Decomposition
573     auto res = this.lu;
574     Matrix U = res[1];
575     
576     double u = 1;
577 
578     foreach(i; 0 .. U.row) {
579       u *= U[i,i];
580     }
581     return u;
582   }
583 
584   /++
585     Inverse
586   +/
587   Matrix inv() const {
588     auto res = this.lu();
589     Matrix L = res[0];
590     Matrix U = res[1];
591 
592     Matrix Uinv = U.invU;
593     Matrix Linv = L.invL;
594 
595     return Uinv % Linv; 
596   }
597 
598   Matrix invL() {
599     if (this.row == 1) {
600       return this;
601     } else if (this.row == 2) {
602       auto m = this.data;
603       m[1][0] = -this.data[1][0];
604       return Matrix(m);
605     } else {
606       auto l1 = this.block(1);
607       auto l2 = this.block(2);
608       auto l3 = this.block(3);
609       auto l4 = this.block(4);
610 
611       auto m1 = l1.invL;
612       auto m2 = l2;
613       auto m4 = l4.invL;
614       auto m3 = (m4 % l3 % m1) * (-1);
615 
616       return combine(m1, m2, m3, m4);
617     }
618   }
619 
620   Matrix invU() {
621     if (this.row == 1) {
622       auto m = this.data;
623       m[0][0] = 1 / this.data[0][0];
624       return Matrix(m);
625     } else if (this.row == 2) {
626       auto m = this.data;
627       auto a = m[0][0];
628       auto b = m[0][1];
629       auto c = m[1][1];
630       auto d = a * c;
631 
632       m[0][0] = 1 / a;
633       m[0][1] = - b / d;
634       m[1][1] = 1 / c;
635 
636       return Matrix(m);
637     } else {
638       auto u1 = this.block(1);
639       auto u2 = this.block(2);
640       auto u3 = this.block(3);
641       auto u4 = this.block(4);
642 
643       auto m1 = u1.invU;
644       auto m3 = u3;
645       auto m4 = u4.invU;
646       auto m2 = (m1 % u2 % m4) * (-1);
647 
648       return combine(m1, m2, m3, m4);
649     }
650   }
651 
652   /++
653     Partitioning matrix
654   +/
655   Matrix block(int quad) {
656     auto r = this.row;
657     assert(this.isSquare);
658 
659     auto l = r / 2;
660     auto m = this.data;
661 
662     Matrix target;
663     
664     switch(quad) {
665       case 1:
666         double[][] temp = initMat(l,l);
667         foreach(i; 0 .. l) {
668           foreach(j; 0 .. l) {
669             temp[i][j] = m[i][j];
670           }
671         }
672         target = Matrix(temp);
673         break;
674       case 2:
675         double[][] temp = initMat(l,r - l);
676         foreach(i; 0 .. l) {
677           foreach(j; l .. r) {
678             temp[i][j - l] = m[i][j];
679           }
680         }
681         target = Matrix(temp);
682         break;
683       case 3:
684         double[][] temp = initMat(r-l, l);
685         foreach(i; l .. r) {
686           foreach(j; 0 .. l) {
687             temp[i - l][j] = m[i][j];
688           }
689         }
690         target = Matrix(temp);
691         break;
692       case 4:
693         double[][] temp = initMat(r-l, r-l);
694         foreach(i; l .. r) {
695           foreach(j; l .. r) {
696             temp[i - l][j - l] = m[i][j];
697           }
698         }
699         target = Matrix(temp);
700         break;
701       default:
702         break;
703     }
704     return target;
705   }
706 }
707 
708 // =============================================================================
709 // Functions of vector or matrices
710 // =============================================================================
711 /++
712   Concate two Vectors to Vector
713 +/
714 Vector cbind(Vector m, Vector n) {
715   import std.array : join;
716 
717   Vector container;
718 
719   container.comp = join([m.comp, n.comp]);
720   return container;
721 }
722 
723 /++
724   Concate two Vectors to Matrix
725 +/
726 Matrix rbind(Vector m, Vector n) {
727   assert(m.length == n.length);
728   Vector v = cbind(m, n);
729 
730   return Matrix(v, 2, m.length, true);
731 }
732 
733 /++
734   Insert Vector to Matrix
735 +/
736 Matrix rbind(Matrix m, Vector v) {
737   assert(m.col == v.length);
738   Matrix n = Matrix(v, 1, v.length, true);
739 
740   return rbind(m, n);
741 }
742 
743 /++
744   Concate two Matrix to Matrix with col direction
745 +/
746 Matrix cbind(Matrix m, Matrix n) {
747   assert(m.row == n.row);
748   Matrix container;
749   container.row = m.row;
750   container.col = m.col + n.col;
751   
752   if (m.byRow && n.byRow) {
753     m = m.makeFalse;
754     n = n.makeFalse;
755   } else if (n.byRow) {
756     n = n.makeFalse;
757   } else if (m.byRow) {
758     m = m.makeFalse;
759   }
760 
761   container.val = cbind(m.val, n.val);
762   container.refresh;
763   return container;
764 }
765 
766 /++
767   Concate to Matrix to Matrix with row direction
768 +/
769 Matrix rbind(Matrix m, Matrix n) {
770   assert(m.col == n.col);  
771   
772   import std.array : join;
773 
774   auto mat = join([m.data, n.data]);
775 
776   return Matrix(mat);
777 }
778 
779 
780 // =============================================================================
781 // Array of Array Utils
782 // =============================================================================
783 
784 double[][] initMat(long r, long c) {
785   double[][] m;
786   m.length = r;
787   foreach(i; 0 .. r) {
788     m[i].length = c;
789   }
790   return m;
791 }
792 
793 double[][] eyeMat(long l) {
794   double[][] m = zerosMat(l, l);
795   foreach(i; 0 .. l) {
796     m[i][i] = 1;
797   }
798   return m;
799 }
800 
801 double[][] zerosMat(long r, long c) {
802   double[][] m = initMat(r, c);
803   foreach(i, ref rows; m) {
804     foreach(j; 0 .. c) {
805       rows[j] = 0;
806     }
807   }
808   return m;
809 }
810 
811 /++
812   Combine
813 +/
814 Matrix combine(Matrix p, Matrix q, Matrix r, Matrix s) {
815   auto a = p.data;
816   auto b = q.data;
817   auto c = r.data;
818   auto d = s.data;
819   
820   auto x1 = a[0].length;
821   auto x2 = b[0].length;
822   auto y1 = a.length;
823   auto y2 = c.length;
824 
825   auto lx = x1 + x2;
826   auto ly = y1 + y2;
827 
828   double[][] m;
829   m.length = ly;
830 
831   foreach(i; 0 .. y1) {
832     m[i].length = lx;
833     foreach(j; 0 .. x1) {
834       m[i][j] = a[i][j];
835     }
836     foreach(j; x1 .. lx) {
837       m[i][j] = b[i][j - x1];
838     }
839   }
840 
841   foreach(i; y1 .. ly) {
842     m[i].length = lx;
843     foreach(j; 0 .. x1) {
844       m[i][j] = c[i - y1][j];
845     }
846     foreach(j; x1 .. lx) {
847       m[i][j] = d[i - y1][j - x1];
848     }
849   }
850 
851   return Matrix(m);
852 }