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 }