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 }