1 module data.vector;
2 
3 import std.stdio : writeln;
4 
5 /++
6   Vector is default class for Statistics
7 +/
8 struct Vector {
9   import std.math : sqrt;
10   
11   double[] comp;
12 
13   // ===========================================================================
14   // Constructor
15   // ===========================================================================
16   /++
17     Like iota
18   +/
19   this(double start, double end, double step = 1) {
20     long l = cast(long)((end - start + 1) / step);
21     this.comp.length = l;
22     foreach(i; 0 .. l) {
23       this.comp[i] = start + cast(double)i * step;
24     }
25   }
26 
27   /++
28     Uninitialized
29   +/
30   this(long l) {
31     this.comp.length = l;
32   }
33 
34   /++
35     array to Vector
36   +/
37   this(double[] vec) {
38     this.comp = vec;
39   }
40 
41   void toString(scope void delegate(const(char)[]) sink) const {
42     import std.stdio : write;
43 
44     sink("Vector ");
45     this.comp.write;
46   }
47 
48   // ===========================================================================
49   // Basic Operator
50   // ===========================================================================
51   pure long length() const {
52     return this.comp.length;
53   }
54   
55   // ===========================================================================
56   //    Void Functions
57   // ===========================================================================
58   void add_void(T)(T x) {
59     auto X = cast(double)x;
60     foreach(i; 0 .. this.comp.length) {
61       this.comp[i] += X;
62     }
63   }
64 
65   void sub_void(T)(T x) {
66     auto X = cast(double)x;
67     foreach(i; 0 .. this.comp.length) {
68       this.comp[i] -= X;
69     }
70   }
71 
72   void mul_void(T)(T x) {
73     auto X = cast(double)x;
74     foreach(i; 0 .. this.comp.length) {
75       this.comp[i] *= X;
76     }
77   }
78 
79   void div_void(T)(T x) {
80     auto X = cast(double)x;
81     foreach(i; 0 .. this.comp.length) {
82       this.comp[i] /= X;
83     }
84   }
85 
86   void pow_void(T)(T x) {
87     auto X = cast(double)x;
88     foreach(i; 0 .. this.comp.length) {
89       this.comp[i] ^^= X;
90     }
91   }
92 
93   void sqrt_void() {
94     foreach(i; 0 .. this.comp.length) {
95       this.comp[i] = sqrt(this.comp[i]);
96     }
97   }
98 
99   // TODO: What is it delegate
100   void fmap_void(double delegate(double) f) {
101     foreach(i; 0 .. this.comp.length) {
102       this.comp[i] = f(this.comp[i]);
103     }
104   }
105 
106   // ===========================================================================
107   //    Vector Function
108   // ===========================================================================
109   Vector fmap(double delegate(double) f) {
110     Vector that = Vector(comp);
111     that.fmap_void(f);
112     return that;
113   }
114 
115   const double mapReduce(double delegate(double) f) {
116     double s = 0;
117     foreach(e; this.comp) {
118       s += f(e);
119     }
120     return s;
121   }
122 
123   Vector sqrt() {
124     return this.fmap(t => t.sqrt);
125   }
126   // ===========================================================================
127   // Operator Overloading
128   // ===========================================================================
129   /++
130     Getter
131   +/
132   double opIndex(size_t i) const {
133     return this.comp[i];
134   }
135 
136   /++
137     Setter
138   +/
139   void opIndexAssign(double value, size_t i) {
140     this.comp[i] = value;
141   }
142 
143   /++
144     Binary Operator with Scalar
145   +/
146   Vector opBinary(string op)(double rhs) {
147     Vector temp = Vector(this.comp);
148     switch(op) {
149       case "+":
150         temp.add_void(rhs);
151         break;
152       case "-":
153         temp.sub_void(rhs);
154         break;
155       case "*":
156         temp.mul_void(rhs);
157         break;
158       case "/":
159         temp.div_void(rhs);
160         break;
161       case "^^":
162         temp.pow_void(rhs);
163         break;
164       default:
165         break;
166     }
167     return temp;
168   }
169 
170   /++
171     Binary Operator with Vector
172   +/
173   Vector opBinary(string op)(Vector rhs) {
174     Vector temp = Vector(this.comp);
175     switch(op) {
176       case "+":
177         foreach(i; 0 .. temp.length) {
178           temp.comp[i] += rhs.comp[i];
179         }
180         break;
181       case "-":
182         foreach(i; 0 .. temp.length) {
183           temp.comp[i] -= rhs.comp[i];
184         }
185         break;
186       case "*":
187         foreach(i; 0 .. temp.length) {
188           temp.comp[i] *= rhs.comp[i];
189         }
190         break;
191       case "/":
192         foreach(i; 0 .. temp.length) {
193           temp.comp[i] /= rhs.comp[i];
194         }
195         break;
196       default:
197         break;
198     }
199     return temp;
200   }
201 
202   /++
203     Inner Product
204   +/
205   double dot(Vector rhs) {
206     double s = 0;
207     foreach(i; 0 .. this.comp.length) {
208       s += cast(double)this[i] * cast(double)rhs[i];
209     }
210     return s;
211   }
212 
213   // ===========================================================================
214   // Statistics Operator
215   // ===========================================================================
216   pure double sum() const {
217     double s = 0;
218     foreach(e; this.comp) {
219       s += e;
220     }
221     return s;
222   }
223   
224   pure double mean() const {
225     double s = 0;
226     double l = 0;
227     foreach(e; this.comp) {
228       l++;
229       s += e;
230     }
231     return s / l;
232   }
233 
234   pure double var() const {
235     double m = 0;
236     double l = 0;
237     double v = 0;
238     foreach(e; this.comp) {
239       l++;
240       m += e;
241       v += e ^^ 2;
242     }
243     return (v / l - (m / l)^^2) * l / (l - 1);
244   }
245 
246   pure double std() const {
247     return sqrt(var);
248   }
249 }
250 
251 // =============================================================================
252 // Matrix
253 // =============================================================================
254 /++
255   Matrix Structure
256 +/
257 struct Matrix {
258   import std.array : join;
259   import std.parallelism : taskPool, parallel; // Perfect Parallel!
260 
261   Vector val;
262   long row;
263   long col;
264   bool byRow;
265   double[][] data;
266   
267   // ===========================================================================
268   // Constructor
269   // ===========================================================================
270   this(double[] vec, long r, long c, bool byrow = false) {
271     this.val = Vector(vec);
272     this.row = r;
273     this.col = c;
274     this.byRow = byrow;
275     this.data = this.matForm; // heavy cost
276   }
277 
278   /++
279     Uninitialized Matrix
280   +/
281   this(long r, long c, bool byrow = false) {
282     this.val = Vector(r*c);
283     this.row = r;
284     this.col = c;
285     this.byRow = byrow;
286     this.data = this.matForm;
287   }
288 
289   this(Vector vec, long r, long c, bool byrow = false) {
290     this.val = vec;
291     this.row = r;
292     this.col = c;
293     this.byRow = byrow;
294     this.data = this.matForm; // heavy cost
295   }
296 
297   this(double[][] mat) {
298     this.val = Vector(mat.join); // join is cheap
299     this.row = mat.length;
300     this.col = mat[0].length;
301     this.byRow = true;
302     this.data = mat; // no cost
303   }
304 
305   this(Matrix mat) {
306     this.val = mat.val;
307     this.row = mat.row;
308     this.col = mat.col;
309     this.byRow = mat.byRow;
310     this.data = mat.data;
311   }
312 
313   // ===========================================================================
314   // String
315   // ===========================================================================
316   void toString(scope void delegate(const(char)[]) sink) const {
317     import std.stdio : write;
318 
319     sink("Matrix ");
320     this.data.write;
321   }
322 
323   double[][] matForm() const {
324     long c = this.col;
325     long r = this.row;
326     double[][] mat;
327     mat.length = r;
328 
329     if (byRow) {
330       foreach(i; 0 .. r) {
331         mat[i].length = c;
332         foreach(j; 0 .. c) {
333           long k = c*i + j;
334           mat[i][j] = this.val[k];
335         }
336       }
337     } else {
338       foreach(j; 0 .. c) {
339         foreach(i; 0 .. r) {
340           mat[i].length = c;
341           long k = r*j + i;
342           mat[i][j] = this.val[k];
343         }
344       }
345     }
346     return mat;
347   }
348 
349   /++
350     Reduce cost
351   +/
352   void refresh() {
353     this.data = this.matForm;
354   }
355   // ===========================================================================
356   // Operator Overloading
357   // ===========================================================================
358   /++
359     Getter
360   +/
361   double opIndex(size_t i, size_t j) const {
362     return this.data[i][j];
363   }
364 
365   /++
366     Setter
367   +/
368   void opIndexAssign(double value, size_t i, size_t j) {
369     this.data[i][j] = value;
370   }
371 
372   /++
373     Binary Operator with Scalar
374   +/
375   Matrix opBinary(string op)(double rhs) {
376     Matrix temp = Matrix(this.data); // No Cost
377     switch(op) {
378       case "+":
379         temp.val.add_void(rhs);
380         break;
381       case "-":
382         temp.val.sub_void(rhs);
383         break;
384       case "*":
385         temp.val.mul_void(rhs);
386         break;
387       case "/":
388         temp.val.div_void(rhs);
389         break;
390       case "^^":
391         temp.val.pow_void(rhs);
392         break;
393       default:
394         break;
395     }
396     temp.refresh;
397     return temp;
398   }
399 
400   /++
401     Binary Operator with Matrix
402   +/
403   Matrix opBinary(string op)(Matrix rhs) {
404     Matrix temp = Matrix(this.val, this.row, this.col, this.byRow); // Guess heavy cost but..
405     switch(op) {
406       case "+":
407         foreach(i; 0 .. temp.val.length) {
408           temp.val.comp[i] += rhs.val.comp[i];
409         }
410         break;
411       case "-":
412         foreach(i; 0 .. temp.val.length) {
413           temp.val.comp[i] -= rhs.val.comp[i];
414         }
415         break;
416       case "*":
417         foreach(i; 0 .. temp.val.length) {
418           temp.val.comp[i] *= rhs.val.comp[i];
419         }
420         break;
421       case "/":
422         foreach(i; 0 .. temp.val.length) {
423           temp.val.comp[i] /= rhs.val.comp[i];
424         }
425         break;
426       case "%": // Parallel Multiplication
427         assert(this.col == rhs.row);
428         
429         auto m = this.data;
430         auto n = rhs.data;
431         auto l1 = this.row;
432         auto l2 = rhs.col;
433 
434         auto target = initMat(l1, l2);
435 
436         foreach(i, ref rows; taskPool.parallel(target)) {
437           foreach(j; 0 .. l2) {
438             double s = 0;
439             foreach(k; 0 .. this.col) {
440               s += m[i][k] * n[k][j];
441             }
442             rows[j] = s;
443           }
444         }
445         temp = Matrix(target);
446         break;
447       default:
448         break;
449     }
450     temp.refresh;
451     return temp;
452   }
453 
454   // ===========================================================================
455   // Matrix Utils
456   // ===========================================================================
457   /++
458     True -> False
459   +/
460   Matrix makeWrong() {
461     assert(this.byRow);
462     double[] v_ref = this.val.comp; // Double array
463     auto r = this.row;
464     auto c = this.col;
465     auto l = r * c - 1;
466     v_con.length = l + 1;
467 
468     foreach(i; 0 .. l) {
469       auto s = (i * c) % l;
470       v_con[i] = v_ref[s];
471     }
472     v_con[l] = v_ref[l];
473 
474     return Matrix(v_con, r, c);
475   }
476 
477   /++
478     Transpose
479   +/
480   Matrix transpose() { // Parallel
481     auto l1 = this.row;
482     auto l2 = this.col;
483     auto m = this.data;
484     Matrix temp;
485     auto target = initMat(l2, l1);
486     foreach(i, ref rows; taskPool.parallel(target)) {
487       foreach(j; 0 .. l1) {
488         rows[j] = m[j][i];
489       }
490     }
491     temp = Matrix(target);
492     return temp;
493   }
494 
495   /++
496     Check Square Matrix
497   +/
498   bool isSquare() {
499     return this.row == this.col;
500   }
501 
502   import std.typecons : tuple;
503 
504   /++
505     LU Decomposition
506   +/
507   auto lu() {
508     auto n = this.row;
509     assert(this.isSquare);
510 
511     double[][] m = this.data;
512     double[][] u = zerosMat(n,n);
513     double[][] l = eyeMat(n);
514     u[0] = m[0];
515 
516     foreach(i; 0 .. n) {
517       foreach(k; i .. n) {
518         double s = 0;
519         foreach(j; 0 .. i) {
520           s += l[i][j] * u[j][k];
521         }
522         u[i][k] = m[i][k] - s;
523       }
524 
525       foreach(k; i+1 .. n) {
526         double s = 0;
527         foreach(j; 0 .. i) {
528           s += l[k][j] * u[j][i];
529         }
530         l[k][i] = (m[k][i] - s) / u[i][i];
531       }
532     }
533     Matrix L = Matrix(l);
534     Matrix U = Matrix(u);
535     return tuple(L, U);
536   }
537 
538   /++
539     Determinant (Using LU Decomposition)
540   +/
541   double det() { // Use LU Decomposition
542     auto res = this.lu;
543     Matrix U = res[1];
544     
545     double u = 1;
546 
547     foreach(i; 0 .. U.row) {
548       u *= U[i,i];
549     }
550     return u;
551   }
552 
553   /++
554     Inverse
555   +/
556   // Matrix inv() {
557   //   auto res = this.lu();
558   //   Matrix L = res[0];
559   //   Matrix U = res[1];
560 
561   // }
562 
563   /++
564     Partitioning matrix
565   +/
566   Matrix block(int quad) {
567     auto r = this.row;
568     assert(this.isSquare);
569 
570     auto l = r / 2;
571     auto m = this.data;
572 
573     Matrix target;
574     
575     switch(quad) {
576       case 1:
577         double[][] temp = initMat(l,l);
578         foreach(i; 0 .. l) {
579           foreach(j; 0 .. l) {
580             temp[i][j] = m[i][j];
581           }
582         }
583         target = Matrix(temp);
584         break;
585       case 2:
586         double[][] temp = initMat(l,r - l);
587         foreach(i; 0 .. l) {
588           foreach(j; l .. r) {
589             temp[i][j - l] = m[i][j];
590           }
591         }
592         target = Matrix(temp);
593         break;
594       case 3:
595         double[][] temp = initMat(r-l, l);
596         foreach(i; l .. r) {
597           foreach(j; 0 .. l) {
598             temp[i - l][j] = m[i][j];
599           }
600         }
601         target = Matrix(temp);
602         break;
603       case 4:
604         double[][] temp = initMat(r-l, r-l);
605         foreach(i; l .. r) {
606           foreach(j; l .. r) {
607             temp[i - l][j - l] = m[i][j];
608           }
609         }
610         target = Matrix(temp);
611         break;
612       default:
613         break;
614     }
615     return target;
616   }
617 }
618 
619 // =============================================================================
620 // Functions of vector or matrices
621 // =============================================================================
622 Matrix cbind(Matrix m, Matrix n) {
623   assert(m.row == n.row);
624   Matrix container;
625   container.row = m.row;
626   container.col = m.col + n.col;
627 }
628 
629 
630 
631 // =============================================================================
632 // Array of Array Utils
633 // =============================================================================
634 
635 double[][] initMat(long r, long c) {
636   double[][] m;
637   m.length = r;
638   foreach(i; 0 .. r) {
639     m[i].length = c;
640   }
641   return m;
642 }
643 
644 double[][] eyeMat(long l) {
645   double[][] m = zerosMat(l, l);
646   foreach(i; 0 .. l) {
647     m[i][i] = 1;
648   }
649   return m;
650 }
651 
652 double[][] zerosMat(long r, long c) {
653   double[][] m = initMat(r, c);
654   foreach(i, ref rows; m) {
655     foreach(j; 0 .. c) {
656       rows[j] = 0;
657     }
658   }
659   return m;
660 }