matrix   F
last analyzed

Complexity

Total Complexity 284

Size/Duplication

Total Lines 1391
Duplicated Lines 0 %

Importance

Changes 4
Bugs 3 Features 0
Metric Value
wmc 284
eloc 494
c 4
b 3
f 0
dl 0
loc 1391
rs 2

102 Methods

Rating   Name   Duplication   Size   Complexity  
A addScaleRow() 0 3 2
A scaleDigonalCol() 0 8 4
A joinAbove() 0 15 5
A greater() 0 8 3
A is_zero() 0 5 2
B setData() 0 14 9
A sumScalar() 0 6 2
A subtractScalar() 0 6 2
A getShape() 0 2 1
A divideScalar() 0 6 2
A getDiagonalVal() 0 3 2
A uniform() 0 7 2
B less() 0 14 7
A diagonal() 0 7 2
A gaussian() 0 28 5
A scaleCol() 0 3 2
A asVector() 0 6 2
A eign() 0 2 1
A subtract() 0 7 3
A median() 0 15 3
A equalVector() 0 9 5
A asArray() 0 8 3
A normINF() 0 2 1
A modVector() 0 9 4
A ref() 0 2 1
A __toString() 0 2 1
A ar() 0 8 3
A rref() 0 2 1
A modMatrix() 0 7 3
A powVector() 0 9 4
A multiplyVector() 0 9 4
A zeros() 0 6 2
A printMatrix() 0 7 3
A equalScalar() 0 6 3
A swapRows() 0 5 2
A full() 0 6 2
A identity() 0 12 5
A normL2() 0 2 1
A diagonalAsVector() 0 9 3
A powScalar() 0 6 2
A subtractVector() 0 9 4
A argMax() 0 6 2
A powMatrix() 0 7 3
A mean() 0 2 1
A dignoalInterChange() 0 5 3
A diminish_right() 0 8 3
A __construct() 0 6 3
A swapValue() 0 4 1
A svd() 0 2 1
A trace() 0 13 5
A factory() 0 2 1
A variance() 0 13 4
A joinRight() 0 15 5
A cholesky() 0 2 1
A divideMatrix() 0 7 3
A isSymmetric() 0 13 4
A normL1() 0 2 1
A multiplyMatrix() 0 9 4
A reciprocal() 0 2 1
A square() 0 2 1
A greaterScalar() 0 6 3
A null() 0 6 2
A scale() 0 11 3
A subtractMatrix() 0 7 3
A sumRows() 0 10 3
A sumMatrix() 0 7 3
A getDtype() 0 2 1
A convolve() 0 2 1
A isSquare() 0 5 2
A divide() 0 7 3
A is_rowZero() 0 7 3
A subtractColumnVector() 0 9 4
A transpose() 0 8 3
A normFrob() 0 2 1
A sum() 0 7 3
A joinLeft() 0 15 5
A joinBelow() 0 15 5
A equalMatrix() 0 7 4
A pow() 0 7 3
A det() 0 11 2
A rowAsVector() 0 6 2
A flattenArray() 0 9 5
A scaleRow() 0 3 2
A ones() 0 6 2
A randn() 0 7 2
A argMin() 0 7 2
A swapCols() 0 5 2
A poisson() 0 16 4
A has_ZeroRow() 0 7 3
A mod() 0 7 3
A diminish_left() 0 8 3
A modScalar() 0 6 2
A greaterVector() 0 9 5
A colAsVector() 0 6 2
A greaterMatrix() 0 7 4
A equal() 0 8 3
A lu() 0 2 1
A covariance() 0 13 3
A sumVector() 0 9 4
A divideVector() 0 9 4
A getSize() 0 2 1
A multiply() 0 7 3

How to fix   Complexity   

Complex Class

Complex classes like matrix often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use matrix, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Np;
6
7
use Np\core\{nd,blas,lapack};
8
use Np\linAlgb\reductions\{ref,rref};
9
use Np\linAlgb\decompositions\{lu,svd,eigen,cholesky};
10
11
/**
12
 * Matrix
13
 * 
14
 * @package   Np
15
 * @category  Scientific Computing
16
 * @author    ghost (Shubham Chaudhary)
17
 * @email     [email protected]
18
 * @copyright (c) 2020-2021, Shubham Chaudhary
19
 */
20
class matrix extends nd {
21
22
    use ops,linAlgb\linAlg;
23
24
    /**
25
     * create empty 2d matrix for given data type
26
     * @param int $row  num of rows 
27
     * @param int $col  num of cols
28
     * @return \Np\matrix
29
     */
30
    public static function factory(int $row, int $col): matrix {
31
        return new self($row, $col);
32
    }
33
34
    /**
35
     * create 2d matrix using php array
36
     * @param array $data
37
     * @return \Np\matrix
38
     */
39
    public static function ar(array $data): matrix {
40
        if (is_array($data) && is_array($data[0])) {
41
            $ar = self::factory(count($data), count($data[0]));
42
            $ar->setData($data);
43
            unset($data);
44
            return $ar;
45
        } else {
46
            self::_err('given array is not rank-2 or given is not an array');
47
        }
48
    }
49
50
    /**
51
     * create one like 2d matrix
52
     * @param int $row
53
     * @param int $col
54
     * @return \Np\matrix
55
     */
56
    public static function ones(int $row, int $col): matrix {
57
        $ar = self::factory($row, $col);
58
        for ($i = 0; $i < $ar->ndim; ++$i) {
59
            $ar->data[$i] = 1;
60
        }
61
        return $ar;
62
    }
63
64
    /**
65
     * Create Matrix with random values
66
     * @param int $row
67
     * @param int $col
68
     * @return \Np\matrix
69
     */
70
    public static function randn(int $row, int $col): matrix {
71
        $ar = self::factory($row, $col);
72
        $max = getrandmax();
73
        for ($i = 0; $i < $ar->ndim; ++$i) {
74
            $ar->data[$i] = rand() / $max;
75
        }
76
        return $ar;
77
    }
78
79
    /**
80
     * Return 2d matrix with uniform values
81
     * @param int $row
82
     * @param int $col
83
     * @return \Np\matrix
84
     */
85
    public static function uniform(int $row, int $col): matrix {
86
        $ar = self::factory($row, $col);
87
        $max = getrandmax();
88
        for ($i = 0; $i < $ar->ndim; ++$i) {
89
            $ar->data[$i] = rand(-$max, $max) / $max;
90
        }
91
        return $ar;
92
    }
93
94
    /**
95
     * Return a zero matrix with the given dimensions.
96
     * @param int $row
97
     * @param int $col
98
     * @return \Np\matrix
99
     */
100
    public static function zeros(int $row, int $col): matrix {
101
        $ar = self::factory($row, $col);
102
        for ($i = 0; $i < $ar->ndim; ++$i) {
103
            $ar->data[$i] = 0.0;
104
        }
105
        return $ar;
106
    }
107
108
    /**
109
     * create a null like 2d matrix
110
     * @param int $row
111
     * @param int $col
112
     * @return \Np\matrix
113
     */
114
    public static function null(int $row, int $col): matrix {
115
        $ar = self::factory($row, $col);
116
        for ($i = 0; $i < $ar->ndim; ++$i) {
117
            $ar->data[$i] = null;
118
        }
119
        return $ar;
120
    }
121
122
    /**
123
     * create a 2d matrix with given scalar value
124
     * @param int $row
125
     * @param int $col
126
     * @param int|float $val
127
     * @return \Np\matrix
128
     */
129
    public static function full(int $row, int $col, int|float $val): matrix {
130
        $ar = self::factory($row, $col);
131
        for ($i = 0; $i < $ar->ndim; ++$i) {
132
            $ar->data[$i] = $val;
133
        }
134
        return $ar;
135
    }
136
137
    /**
138
     * create a diagonal 2d matrix with given 1d array;
139
     * @param array $elements
140
     * @return \Np\matrix
141
     */
142
    public static function diagonal(array $elements): matrix {
143
        $n = count($elements);
144
        $ar = self::factory($n, $n);
145
        for ($i = 0; $i < $n; ++$i) {
146
            $ar->data[$i * $n + $i] = $elements[$i]; #for ($j = 0; $j < $n; ++$j) {$i === $j ? $elements[$i] : 0;#} 
147
        }
148
        return $ar;
149
    }
150
151
    /**
152
     * Generate a m x n matrix with elements from a Poisson distribution.
153
     * @param int $row
154
     * @param int $col
155
     * @param float $lambda
156
     * @return \Np\matrix
157
     */
158
    public static function poisson(int $row, int $col, float $lambda = 1.0): matrix {
159
        $ar = self::factory($row, $col);
160
        $max = getrandmax();
161
        $l = exp(-$lambda);
162
        for ($i = 0; $i < $row; ++$i) {
163
            for ($j = 0; $j < $col; ++$j) {
164
                $k = 0;
165
                $p = 1.0;
166
                while ($p > $l) {
167
                    ++$k;
168
                    $p = $p * rand() / $max;
169
                }
170
                $ar->data[$i * $col + $j] = $k - 1;
171
            }
172
        }
173
        return $ar;
174
    }
175
176
    /**
177
     * Return a standard normally distributed random matrix i.e values
178
     * between -1 and 1.
179
     * @param int $row
180
     * @param int $col
181
     * @return \Np\matrix
182
     */
183
    public static function gaussian(int $row, int $col): matrix {
184
        $max = getrandmax();
185
        $a = $extras = [];
186
187
        while (count($a) < $row) {
188
            $rowA = [];
189
190
            if (!empty($extras)) {
191
                $rowA[] = array_pop($extras);
192
            }
193
194
            while (count($rowA) < $col) {
195
                $r = sqrt(-2.0 * log(rand() / $max));
196
197
                $phi = rand() / $max * self::TWO_PI;
198
199
                $rowA[] = $r * sin($phi);
200
                $rowA[] = $r * cos($phi);
201
            }
202
203
            if (count($rowA) > $col) {
204
                $extras[] = array_pop($rowA);
205
            }
206
207
            $a[] = $rowA;
208
        }
209
210
        return self::ar($a);
211
    }
212
213
    /**
214
     * create an identity matrix with the given dimensions.
215
     * @param int $n
216
     * @return matrix
217
     * @throws \InvalidArgumentException
218
     */
219
    public static function identity(int $n): matrix {
220
        if ($n < 1) {
221
            self::_dimensionaMisMatchErr('dimensionality must be greater than 0 on all axes.');
222
        }
223
224
        $ar = self::factory($n, $n);
225
        for ($i = 0; $i < $n; ++$i) {
226
            for ($j = 0; $j < $n; ++$j) {
227
                $ar->data[$i * $n + $j] = $i === $j ? 1 : 0;
228
            }
229
        }
230
        return $ar;
231
    }
232
233
    /**
234
     * Return a row as vector from the matrix.
235
     * @param int $index
236
     * @return \Np\vector
237
     */
238
    public function rowAsVector(int $index): vector {
239
        $vr = vector::factory($this->col);
240
        for ($j = 0; $j < $this->col; ++$j) {
241
            $vr->data[$j] = $this->data[$index * $this->col + $j];
242
        }
243
        return $vr;
244
    }
245
246
    /**
247
     * Return a col as vector from the matrix.
248
     * @param int $index
249
     * @return \Np\vector
250
     */
251
    public function colAsVector(int $index): vector {
252
        $vr = vector::factory($this->row);
253
        for ($i = 0; $i < $this->row; ++$i) {
254
            $vr->data[$i] = $this->data[$i * $this->row + $index];
255
        }
256
        return $vr;
257
    }
258
259
    /**
260
     * Return the diagonal elements of a square matrix as a vector.
261
     * @return \Np\vector
262
     */
263
    public function diagonalAsVector(): vector {
264
        if ($this->isSquare()) {
265
            $vr = vector::factory($this->row);
266
            for ($i = 0; $i < $this->row; ++$i) {
267
                $vr->data[$i] = $this->getDiagonalVal($i);
268
            }
269
            return $vr;
270
        }
271
        self::_err('Can not trace of a none square matrix');
272
    }
273
274
    /**
275
     * Flatten i.e unravel the matrix into a vector.
276
     *
277
     * @return \Np\vector
278
     */
279
    public function asVector(): vector {
280
        $vr = vector::factory($this->ndim);
281
        for ($i = 0; $i < $this->ndim; ++$i) {
282
            $vr->data[$i] = $this->data[$i];
283
        }
284
        return $vr;
285
    }
286
287
    /**
288
     * 2D convolution between a matrix ma and kernel kb, with a given stride.
289
     * @param \Np\matrix $m
290
     * @param int $stride
291
     * @return matrix
292
     */
293
    public function convolve(matrix $m, int $stride = 1): matrix {
294
        return convolve::conv2D($this, $m, $stride);
295
    }
296
297
    /**
298
     * Calculate the determinant of the matrix.
299
     * @return float
300
     */
301
    public function det(): float {
302
        if (!$this->isSquare()) {
303
            self::_err('determinant is undefined for a non square matrix');
304
        }
305
        $lu = $this->lu();
306
        $nSwaps = $lu->p()->diagonalAsVector()->subtract($lu->p()->diagonalAsVector()->sum())->col - 1;
307
        $detP = (-1) ** $nSwaps;
308
        $detL = $lu->l()->diagonalAsVector()->product();
309
        $detU = $lu->u()->diagonalAsVector()->product();
310
        unset($lu);
311
        return ($detP * $detL * $detU);
312
    }
313
314
    /**
315
     * Return the trace of the matrix i.e the sum of all diagonal elements of a square matrix.
316
     * @return float
317
     */
318
    public function trace(): float {
319
        if (!$this->isSquare()) {
320
            self::_err('Error::matrix is not a squared can not Trace!');
321
        }
322
        $trace = 0.0;
323
        for ($i = 0; $i < $this->row; ++$i) {
324
            for ($j = 0; $j < $this->col; ++$j) {
325
                if ($i == $j) {
326
                    $trace += $this->data[$i * $this->col + $i];
327
                }
328
            }
329
        }
330
        return $trace;
331
    }
332
333
    /**
334
     * dignoalInterChange
335
     */
336
    public function dignoalInterChange() {
337
        for ($i = 0; $i < $this->row; ++$i) {
338
            for ($j = 0; $j < $this->col; ++$j) {
339
                $tmp = $this->data[$i * $this->col - $j];
340
                $this->data[$i * $this->col - $j] = $tmp;
341
            }
342
        }
343
    }
344
345
    //---------------Arthmetic Opreations-----------------------------------
346
347
    /**
348
     * multiply this matrix with another matrix|scalar element-wise
349
     * Matrix Scalar\Matrix multiplication
350
     * @param int|float|matrix|vector $m
351
     * @return matrix|vector
352
     */
353
    public function multiply(int|float|matrix|vector $m): matrix|vector {
354
        if ($m instanceof self) {
355
            return $this->multiplyMatrix($m);
356
        } else if ($m instanceof vector) {
357
            return $this->multiplyVector($m);
358
        } else {
359
            return $this->scale($m);
360
        }
361
    }
362
363
    /**
364
     * 
365
     * @param \Np\vector $v
366
     * @return matrix
367
     */
368
    protected function multiplyVector(vector $v): matrix {
369
        if ($this->checkDimensions($v, $this)) {
370
            $ar = matrix::factory($this->row, $this->col);
371
            for ($i = 0; $i < $this->row; ++$i) {
372
                for ($j = 0; $j < $this->col; ++$j) {
373
                    $ar->data[$i * $this->col + $j] = $v->data[$j] * $this->data[$i * $this->col + $j];
374
                }
375
            }
376
            return $ar;
377
        }
378
    }
379
380
    /**
381
     * 
382
     * @param \Np\matrix $m
383
     * @return matrix
384
     */
385
    protected function multiplyMatrix(matrix $m): matrix {
386
        if ($this->checkShape($this, $m)) {
387
            $ar = self::factory($this->row, $this->col);
388
            for ($i = 0; $i < $this->row; ++$i) {
389
                for ($j = 0; $j < $this->col; ++$j) {
390
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] * $m->data[$i * $this->col + $j];
391
                }
392
            }
393
            return $ar;
394
        }
395
    }
396
397
    /**
398
     * Sum of two matrix, vector or a scalar to current matrix
399
     * 
400
     * @param int|float|matrix|vector $m
401
     * @return matrix
402
     */
403
    public function sum(int|float|matrix|vector $m): matrix {
404
        if ($m instanceof self) {
405
            return $this->sumMatrix($m);
406
        } elseif ($m instanceof vector) {
407
            return $this->sumVector($m);
408
        } else {
409
            return $this->sumScalar($m);
410
        }
411
    }
412
413
    protected function sumScalar(int|float $s): matrix {
414
        $ar = self::factory($this->row, $this->col);
415
        for ($i = 0; $i < $this->ndim; ++$i) {
416
            $ar->data[$i] = $this->data[$i] + $s;
417
        }
418
        return $ar;
419
    }
420
421
    protected function sumMatrix(matrix $m): matrix {
422
        if ($this->checkShape($this, $m)) {
423
            $ar = self::factory($this->row, $this->col);
424
            for ($i = 0; $i < $this->ndim; ++$i) {
425
                $ar->data[$i] = $this->data[$i] + $m->data[$i];
426
            }
427
            return $ar;
428
        }
429
    }
430
431
    protected function sumVector(vector $v): matrix {
432
        if ($this->checkDimensions($v, $this)) {
433
            $ar = self::factory($this->row, $this->col);
434
            for ($i = 0; $i < $this->row; ++$i) {
435
                for ($j = 0; $j < $this->col; ++$j) {
436
                    $ar->data[$i * $this->col + $j] = $v->data[$j] + $this->data[$i * $this->col + $j];
437
                }
438
            }
439
            return $ar;
440
        }
441
    }
442
443
    /**
444
     * Sum of Rows of matrix
445
     * @return vector
446
     */
447
    public function sumRows(): vector {
448
        $vr = vector::factory($this->row);
449
        for ($i = 0; $i < $this->row; ++$i) {
450
            $sum = 0.0;
451
            for ($j = 0; $j < $this->col; ++$j) {
452
                $sum += $this->data[$i * $this->col + $j];
453
            }
454
            $vr->data[$i] = $sum;
455
        }
456
        return $vr;
457
    }
458
459
    /**
460
     * subtract another matrix, vector or a scalar to this matrix
461
     * @param int|float|matrix|vector $d matrix|$scalar to subtract this matrix
462
     * @return \Np\matrix
463
     */
464
    public function subtract(int|float|matrix|vector $d): matrix {
465
        if ($d instanceof self) {
466
            return $this->subtractMatrix($d);
467
        } elseif ($d instanceof vector) {
468
            return $this->subtractVector($d);
469
        } else {
470
            return $this->subtractScalar($d);
471
        }
472
    }
473
474
    protected function subtractScalar(int|float $s): matrix {
475
        $ar = self::factory($this->row, $this->col);
476
        for ($i = 0; $i < $this->ndim; ++$i) {
477
            $ar->data[$i] = $this->data[$i] - $s;
478
        }
479
        return $ar;
480
    }
481
482
    /**
483
     * 
484
     * @param matrix $m
485
     * @return matrix
486
     */
487
    protected function subtractMatrix(matrix $m): matrix {
488
        if ($this->checkShape($this, $m)) {
489
            $ar = self::factory($this->row, $this->col);
490
            for ($i = 0; $i < $this->ndim; ++$i) {
491
                $ar->data[$i] = $this->data[$i] - $m->data[$i];
492
            }
493
            return $ar;
494
        }
495
    }
496
497
    /**
498
     * 
499
     * @param vector $v
500
     * @return matrix
501
     */
502
    protected function subtractVector(vector $v): matrix {
503
        if ($this->checkDimensions($v, $this)) {
504
            $ar = self::factory($this->row, $this->col);
505
            for ($i = 0; $i < $this->row; ++$i) {
506
                for ($j = 0; $j < $this->col; ++$j) {
507
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] - $v->data[$j];
508
                }
509
            }
510
            return $ar;
511
        }
512
    }
513
514
    /**
515
     * 
516
     * @param vector $v
517
     * @return matrix
518
     */
519
    public function subtractColumnVector(vector $v): matrix {
520
        if ($this->checkDimensions($v, $this)) {
521
            $ar = self::factory($this->row, $this->col);
522
            for ($j = 0; $j < $this->col; ++$j) {
523
                for ($i = 0; $i < $this->row; ++$i) {
524
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] - $v->data[$i];
525
                }
526
            }
527
            return $ar;
528
        }
529
    }
530
531
    /**
532
     * Return the division of two elements, element-wise.
533
     * @param int|float|matrix $d
534
     * @return matrix
535
     */
536
    public function divide(int|float|matrix|vector $d): matrix {
537
        if ($d instanceof self) {
538
            return $this->divideMatrix($d);
539
        } elseif ($d instanceof vector) {
540
            return $this->divideVector($d);
541
        } else {
542
            return $this->divideScalar($d);
543
        }
544
    }
545
546
    protected function divideMatrix(matrix $m): matrix {
547
        if ($this->checkShape($this, $m)) {
548
            $ar = self::factory($this->row, $this->col);
549
            for ($i = 0; $i < $this->ndim; ++$i) {
550
                $ar->data[$i] = $this->data[$i] / $m->data[$i];
551
            }
552
            return $ar;
553
        }
554
    }
555
556
    protected function divideVector(vector $v): matrix {
557
        if ($this->checkDimensions($v, $this)) {
558
            $ar = self::factory($this->row, $this->col);
559
            for ($i = 0; $i < $this->row; ++$i) {
560
                for ($j = 0; $j < $this->col; ++$j) {
561
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] / $v->data[$j];
562
                }
563
            }
564
            return $ar;
565
        }
566
    }
567
568
    protected function divideScalar(int|float $s): matrix {
569
        $ar = self::factory($this->row, $this->col);
570
        for ($i = 0; $i < $this->ndim; ++$i) {
571
            $ar->data[$i] = $this->data[$i] / $s;
572
        }
573
        return $ar;
574
    }
575
576
    /**
577
     * 
578
     * Raise this matrix to the power of the element-wise entry in another matrix.
579
     * 
580
     * @param int|float|matrix $m
581
     * @return matrix
582
     */
583
    public function pow(int|float|matrix|vector $d): matrix {
584
        if ($d instanceof self) {
585
            return $this->powMatrix($d);
586
        } else if ($d instanceof vector) {
587
            return $this->powVector($d);
588
        } else {
589
            return $this->powScalar($d);
590
        }
591
    }
592
593
    protected function powMatrix(matrix $m): matrix {
594
        if ($this->checkShape($this, $m)) {
595
            $ar = self::factory($this->row, $this->col);
596
            for ($i = 0; $i < $this->ndim; ++$i) {
597
                $ar->data[$i] = $this->data[$i] ** $m->data[$i];
598
            }
599
            return $ar;
600
        }
601
    }
602
603
    protected function powVector(vector $v): matrix {
604
        if ($this->checkDimensions($v, $this)) {
605
            $ar = self::factory($this->row, $this->col);
606
            for ($i = 0; $i < $this->row; ++$i) {
607
                for ($j = 0; $j < $this->col; ++$j) {
608
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] ** $v->data[$j];
609
                }
610
            }
611
            return $ar;
612
        }
613
    }
614
615
    protected function powScalar(int|float $s): matrix {
616
        $ar = $this->copy();
617
        for ($i = 0; $i < $this->ndim; ++$i) {
618
            $ar->data[$i] **= $s;
619
        }
620
        return $ar;
621
    }
622
623
    /**
624
     * Calculate the modulus i.e remainder of division between this matrix and another matrix.
625
     * @param int|float|matrix|vector $d
626
     * @return matrix
627
     */
628
    public function mod(int|float|matrix|vector $d): matrix {
629
        if ($d instanceof self) {
630
            $this->modMatrix($d);
631
        } else if ($d instanceof vector) {
632
            $this->modVector($d);
633
        } else {
634
            $this->modScalar($d);
635
        }
636
    }
637
638
    protected function modMatrix(matrix $m): matrix {
639
        if ($this->checkShape($this, $m)) {
640
            $ar = self::factory($this->row, $this->col);
641
            for ($i = 0; $i < $this->ndim; ++$i) {
642
                $ar->data[$i] = $this->data[$i] % $m->data[$i];
643
            }
644
            return $ar;
645
        }
646
    }
647
648
    protected function modVector(vector $v): matrix {
649
        if ($this->checkDimensions($v, $this)) {
650
            $ar = self::factory($this->row, $this->col);
651
            for ($i = 0; $i < $this->row; ++$i) {
652
                for ($j = 0; $j < $this->col; ++$j) {
653
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] % $v->data[$j];
654
                }
655
            }
656
            return $ar;
657
        }
658
    }
659
660
    protected function modScalar(int|float $s): matrix {
661
        $ar = $this->copy();
662
        for ($i = 0; $i < $this->ndim; ++$i) {
663
            $ar->data[$i] %= $s;
664
        }
665
        return $ar;
666
    }
667
668
    /**
669
     * Return the element-wise reciprocal of the matrix.
670
     * 
671
     * @return matrix
672
     */
673
    public function reciprocal(): matrix {
674
        return self::ones($this->row, $this->col)->divideMatrix($this);
675
    }
676
677
    /**
678
     * Transpose the matrix i.e row become cols and cols become rows.
679
     * @return \Np\matrix
680
     */
681
    public function transpose(): matrix {
682
        $ar = self::factory($this->col, $this->row);
683
        for ($i = 0; $i < $ar->row; ++$i) {
684
            for ($j = 0; $j < $ar->col; ++$j) {
685
                $ar->data[$i * $ar->col + $j] = $this->data[$j * $this->col + $i];
686
            }
687
        }
688
        return $ar;
689
    }
690
691
    /**
692
     * swap specific values in matrix
693
     * @param int $i1
694
     * @param int $i2
695
     */
696
    public function swapValue(int $i1, int $i2) {
697
        $tmp = $this->data[$i1];
698
        $this->data[$i1] = $this->data[$i2];
699
        $this->data[$i2] = $tmp;
700
    }
701
702
    /**
703
     * swap specific rows in matrix
704
     * @param int $r1
705
     * @param int $r2
706
     */
707
    public function swapRows(int $r1, int $r2) {
708
        for ($i = 0; $i < $this->col; ++$i) {
709
            $tmp = $this->data[$r1 * $this->col + $i];
710
            $this->data[$r1 * $this->col + $i] = $this->data[$r2 * $this->col + $i];
711
            $this->data[$r2 * $this->col + $i] = $tmp;
712
        }
713
    }
714
715
    /**
716
     * swap specific cols in matrix
717
     * @param int $c1
718
     * @param int $c2
719
     */
720
    public function swapCols(int $c1, int $c2) {
721
        for ($i = 0; $i < $this->row; ++$i) {
722
            $tmp = $this->data[$i * $this->row + $c1];
723
            $this->data[$i * $this->row + $c1] = $this->data[$i * $this->row + $c2];
724
            $this->data[$i * $this->row + $c2] = $tmp;
725
        }
726
    }
727
728
    /**
729
     * 
730
     * @param int|float $scalar
731
     * @return matrix
732
     */
733
    public function scale(int|float $scalar): matrix {
734
        if ($scalar == 0) {
735
            return self::zeros($this->row, $this->col);
736
        }
737
738
        $ar = $this->copy();
739
        for ($i = 0; $i < $this->ndim; ++$i) {
740
            $ar->data[$i] *= $scalar;
741
        }
742
743
        return $ar;
744
    }
745
746
    /**
747
     * scale all the elements of a row 
748
     * @param int $row
749
     * @param int|float $c
750
     */
751
    public function scaleRow(int $row, int|float $c) {
752
        for ($i = 0; $i < $this->col; ++$i) {
753
            $this->data[$row * $this->col + $i] *= $c;
754
        }
755
    }
756
757
    /**
758
     * scale all the elements of 
759
     * @param int $col
760
     * @param int|float $c
761
     */
762
    public function scaleCol(int $col, int|float $c) {
763
        for ($i = 0; $i < $this->row; ++$i) {
764
            $this->data[$i * $this->col + $col] *= $c;
765
        }
766
    }
767
768
    /**
769
     * Scale digonally 
770
     * @param int|float $c
771
     * @param bool $lDig
772
     */
773
    public function scaleDigonalCol(int|float $c, bool $lDig = true) {
774
        if ($lDig) {
775
            for ($i = 0; $i < $this->row; ++$i) {
776
                $this->data[$i * $this->col + $i] *= $c;
777
            }
778
        } else {
779
            for ($i = $this->row; $i > 0; --$i) {
780
                $this->data[$i * $this->col - $i] *= $c;
781
            }
782
        }
783
    }
784
785
    /**
786
     * 
787
     * @param int $r1
788
     * @param int $r2
789
     * @param float $c
790
     */
791
    public function addScaleRow(int $r1, int $r2, float $c) {
792
        for ($i = 0; $i < $this->col; ++$i) {
793
            $this->data[$r2 * $this->col + $i] += $this->data[$r1 * $this->col + $i] * $c;
794
        }
795
    }
796
797
    /**
798
     * Attach given matrix to the left of this matrix.
799
     * 
800
     * @param \Np\matrix $m
801
     * @return \Np\matrix
802
     */
803
    public function joinLeft(matrix $m): matrix {
804
        if ($this->row == $m->row) {
805
            $col = $this->col + $m->col;
806
            $ar = self::factory($this->row, $col);
807
            for ($i = 0; $i < $this->row; ++$i) {
808
                for ($j = 0; $j < $this->col; ++$j) {
809
                    $ar->data[$i * $col + $j] = $this->data[$i * $this->col + $j];
810
                }
811
                for ($j = 0; $j < $m->col; ++$j) {
812
                    $ar->data[$i * $col + ($this->col + $j)] = $m->data[$i * $m->col + $j];
813
                }
814
            }
815
            return $ar;
816
        }
817
        self::_err('Error::Invalid size! or DataType!');
818
    }
819
820
    /**
821
     * Join matrix m to the Right of this matrix.
822
     * @param \Np\matrix $m
823
     * @return matrix
824
     */
825
    public function joinRight(matrix $m): matrix {
826
        if ($this->row == $m->row) {
827
            self::_err('Error::Invalid size! or DataType!');
828
        }
829
        $col = $this->col + $m->col;
830
        $ar = self::factory($this->row, $col);
831
        for ($i = 0; $i < $m->row; ++$i) {
832
            for ($j = 0; $j < $m->col; ++$j) {
833
                $ar->data[$i * $col + $j] = $m->data[$i * $m->col + $j];
834
            }
835
            for ($j = 0; $j < $this->col; ++$j) {
836
                $ar->data[$i * $col + ($this->col + $j)] = $this->data[$i * $this->col + $j];
837
            }
838
        }
839
        return $ar;
840
    }
841
842
    /**
843
     * Join matrix m Above this matrix.
844
     * @param \Np\matrix $m
845
     * @return matrix
846
     */
847
    public function joinAbove(matrix $m): matrix {
848
        if ($this->col == $m->col) {
849
            $row = $this->row + $m->row;
850
            $ar = self::factory($row, $this->col);
851
            for ($i = 0; $i < $m->row; ++$i) {
852
                for ($j = 0; $j < $m->col; ++$j) {
853
                    $ar->data[$i * $m->col + $j] = $m->data[$i * $m->col + $j];
854
                }
855
                for ($j = 0; $j < $this->col; ++$j) {
856
                    $ar->data[($i + $this->row) * $this->col + $j] = $this->data[$i * $this->col + $j];
857
                }
858
            }
859
            return $ar;
860
        }
861
        self::_err('Error::Invalid size! or DataType!');
862
    }
863
864
    /**
865
     * Join matrix m below this matrix.
866
     * @param \Np\matrix $m
867
     * @return matrix
868
     */
869
    public function joinBelow(matrix $m): matrix {
870
        if ($this->col == $m->col) {
871
            $row = $this->row + $m->row;
872
            $ar = self::factory($row, $this->col);
873
            for ($i = 0; $i < $this->row; ++$i) {
874
                for ($j = 0; $j < $this->col; ++$j) {
875
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j];
876
                }
877
                for ($j = 0; $j < $m->col; ++$j) {
878
                    $ar->data[($i + $m->row) * $m->col + $j] = $m->data[$i * $m->col + $j];
879
                }
880
            }
881
            return $ar;
882
        }
883
        self::_err('Error::Invalid size! or DataType!');
884
    }
885
886
    /**
887
     * 
888
     * @param int $cols
889
     * @return \Np\matrix
890
     */
891
    public function diminish_left(int $cols): matrix {
892
        $ar = self::factory($this->row, $cols);
893
        for ($i = 0; $i < $ar->row; ++$i) {
894
            for ($j = 0; $j < $ar->col; ++$j) {
895
                $ar->data[$i * $ar->col + $j] = $this->data[$i * $this->col + $j];
896
            }
897
        }
898
        return $ar;
899
    }
900
901
    /**
902
     * 
903
     * @param int $cols
904
     * @return \Np\matrix
905
     */
906
    public function diminish_right(int $cols): matrix {
907
        $ar = self::factory($this->row, $cols);
908
        for ($i = 0; $i < $ar->row; ++$i) {
909
            for ($j = 0; $j < $ar->col; ++$j) {
910
                $ar->data[$i * $ar->col + $j] = $this->data[$i * $this->col - $cols + $j];
911
            }
912
        }
913
        return $ar;
914
    }
915
916
    /**
917
     * Return the index of the maximum element in every row of the matrix.
918
     * @return \Np\vector int
919
     */
920
    public function argMax(): vector {
921
        $v = vector::factory($this->row, vector::INT);
922
        for ($i = 0; $i < $this->row; ++$i) {
923
            $v->data[$i] = blas::max($this->rowAsVector($i));
924
        }
925
        return $v;
926
    }
927
928
    /**
929
     * Return the index of the minimum element in every row of the matrix.
930
     * @return \Np\vector int
931
     */
932
    public function argMin(): vector {
933
        $v = vector::factory($this->row, vector::INT);
934
        for ($i = 0; $i < $this->row; ++$i) {
935
            $v->data[$i] = blas::min($this->rowAsVector($i));
936
        }
937
938
        return $v;
939
    }
940
941
    /**
942
     * Set given data in matrix
943
     * @param int|float|array $data
944
     * @param bool $dignoal
945
     * @return void
946
     */
947
    public function setData(int|float|array $data): void {
948
949
        if (is_array($data) && is_array($data[0])) {
950
            $f = $this->flattenArray($data);
951
            foreach ($f as $k => $v) {
952
                $this->data[$k] = $v;
953
            }
954
        } elseif (is_numeric($data)) {
955
            for ($i = 0; $i < $this->ndim; ++$i) {
956
                $this->data[$i] = $data;
957
            }
958
        } elseif (is_array($data) && !is_array($data[0])) {
959
            foreach ($data as $i => $v) {
960
                $this->data[$i] = $v;
961
            }
962
        }
963
    }
964
965
    /**
966
     * get the matrix data type
967
     * @return int
968
     */
969
    public function getDtype(): int {
970
        return $this->dtype;
971
    }
972
973
    /**
974
     * get the shape of matrix
975
     * @return object
976
     */
977
    public function getShape(): object {
978
        return (object) ['m' => $this->row, 'n' => $this->col];
979
    }
980
981
    /**
982
     * get the number of elements in the matrix.
983
     * @return int
984
     */
985
    public function getSize(): int {
986
        return $this->ndim;
987
    }
988
989
    /**
990
     * Is the matrix symmetric i.e. is it equal to its own transpose?
991
     *
992
     * @return bool
993
     */
994
    public function isSymmetric(): bool {
995
        if (!$this->isSquare()) {
996
            return false;
997
        }
998
        $ar = $this->transpose();
999
        for ($i = 0; $i < $ar->ndim; ++$i) {
1000
            if ($ar->data[$i] != $this->data[$i]) {
1001
                unset($ar);
1002
                return false;
1003
            }
1004
        }
1005
        unset($ar);
1006
        return true;
1007
    }
1008
1009
    /**
1010
     * is matrix squred
1011
     * @return bool
1012
     */
1013
    public function isSquare(): bool {
1014
        if ($this->row === $this->col) {
1015
            return true;
1016
        }
1017
        return false;
1018
    }
1019
1020
    /**
1021
     * 
1022
     * @param int|float $d
1023
     * @return bool
1024
     */
1025
    public static function is_zero($d): bool {
1026
        if (abs($d) < self::EPSILON) {
1027
            return true;
1028
        }
1029
        return false;
1030
    }
1031
1032
    /**
1033
     *  is row zero
1034
     * @param int $row
1035
     * @return bool
1036
     */
1037
    public function is_rowZero(int $row): bool {
1038
        for ($i = 0; $i < $this->col; ++$i) {
1039
            if ($this->data[$row * $this->col + $i] != 0) {
1040
                return false;
1041
            }
1042
        }
1043
        return true;
1044
    }
1045
1046
    /**
1047
     * 
1048
     * @return bool
1049
     */
1050
    public function has_ZeroRow(): bool {
1051
        for ($i = 0; $i < $this->row; ++$i) {
1052
            if ($this->is_rowZero($i)) {
1053
                return true;
1054
            }
1055
        }
1056
        return false;
1057
    }
1058
1059
    /**
1060
     * Return the elements of the matrix in a 2-d array.
1061
     * @return array
1062
     */
1063
    public function asArray(): array {
1064
        $ar = array_fill(0, $this->row, array_fill(0, $this->col, null));
1065
        for ($i = 0; $i < $this->row; ++$i) {
1066
            for ($j = 0; $j < $this->col; ++$j) {
1067
                $ar[$i][$j] = $this->data[$i * $this->col + $j];
1068
            }
1069
        }
1070
        return $ar;
1071
    }
1072
1073
    /**
1074
     * get a diagonal value from matrix
1075
     * @param int $i
1076
     * @return float
1077
     */
1078
    public function getDiagonalVal(int $i) {
1079
        if ($this->isSquare()) {
1080
            return $this->data[$i * $this->row + $i];
1081
        }
1082
    }
1083
1084
    /**
1085
     * Calculate the row echelon form of the matrix. 
1086
     * Return the reduced matrix.
1087
     *
1088
     * @return matrix|null
1089
     */
1090
    public function ref(): matrix|null {
1091
        return ref::factory($this);
1092
    }
1093
1094
    /**
1095
     * Return the lower triangular matrix of the Cholesky decomposition.
1096
     *
1097
     * @return matrix|null
1098
     */
1099
    public function cholesky(): matrix|null {
1100
        return cholesky::factory($this);
1101
    }
1102
1103
    /**
1104
     * FIXME--------------
1105
     * RREF
1106
     * The reduced row echelon form (RREF) of a matrix.
1107
     * @return \Np\matrix
1108
     */
1109
    public function rref(): matrix {
1110
        return rref::factory($this);
1111
    }
1112
1113
    /**
1114
     * Compute the singular value decomposition of a matrix and 
1115
     * return an object of the singular values and unitary matrices
1116
     *
1117
     * @return object (u,s,v)
1118
     */
1119
    public function svd(): svd {
1120
        return svd::factory($this);
1121
    }
1122
1123
    /**
1124
     * Compute the eigen decomposition of a general matrix.
1125
     * return the eigenvalues and eigenvectors as object
1126
     * 
1127
     * @param bool $symmetric
1128
     * @return eigen
1129
     */
1130
    public function eign(bool $symmetric = false): eigen {
1131
        return eigen::factory($this, $symmetric);
1132
    }
1133
1134
    /**
1135
     *  
1136
     * Compute the LU factorization of matrix.
1137
     * return lower, upper, and permutation matrices as object.
1138
     * 
1139
     * @return lu
1140
     */
1141
    public function lu(): lu {
1142
        return lu::factory($this);
1143
    }
1144
1145
    /**
1146
     * Return the L1 norm of the matrix.
1147
     * @return float
1148
     */
1149
    public function normL1(): float {
1150
        return lapack::lange('l', $this);
1151
    }
1152
1153
    /**
1154
     * Return the L2 norm of the matrix.
1155
     * @return float
1156
     */
1157
    public function normL2(): float {
1158
        return lapack::lange('f', $this);
1159
    }
1160
1161
    /**
1162
     * Return the L1 norm of the matrix.
1163
     * @return float
1164
     */
1165
    public function normINF(): float {
1166
        return lapack::lange('i', $this);
1167
    }
1168
1169
    /**
1170
     * Return the Frobenius norm of the matrix.
1171
     * @return float
1172
     */
1173
    public function normFrob(): float {
1174
        return $this->normL2();
1175
    }
1176
1177
    /**
1178
     * Compute the means of each row and return them in a vector.
1179
     *
1180
     * @return vector
1181
     */
1182
    public function mean(): vector {
1183
        return $this->sumRows()->divide($this->col);
1184
    }
1185
1186
    /**
1187
     * Compute the row variance of the matrix.
1188
     * 
1189
     * @param vector|null $mean
1190
     * @return vector
1191
     */
1192
    public function variance(vector|null $mean = null): vector {
1193
        if (isset($mean)) {
1194
            if (!$mean instanceof vector) {
0 ignored issues
show
introduced by
$mean is always a sub-type of Np\vector.
Loading history...
1195
                self::_invalidArgument('mean must be a vector!');
1196
            }
1197
            if ($this->row !== $mean->col) {
1198
                self::_err('Err:: given mean vector dimensionality mismatched!');
1199
            }
1200
        } else {
1201
            $mean = $this->mean();
1202
        }
1203
        return $this->subtractColumnVector($mean)->square()
1204
                        ->sumRows()->divide($this->row);
1205
    }
1206
1207
    /**
1208
     *  Return the median vector of this matrix.
1209
     * @return vector
1210
     */
1211
    public function median(): vector {
1212
        $mid = intdiv($this->col, 2);
1213
        $odd = $this->col % 2 === 1;
1214
        $vr = vector::factory($this->row);
1215
        for ($i = 0; $i < $this->row; ++$i) {
1216
            $a = $this->rowAsVector($i)->sort();
1217
            if ($odd) {
1218
                $median = $a->data[$mid];
1219
            } else {
1220
                $median = ($a->data[$mid - 1] + $a->data[$mid]) / 2.0;
1221
            }
1222
            $vr->data[$i] = $median;
1223
        }
1224
        unset($a);
1225
        return $vr;
1226
    }
1227
1228
    /**
1229
     * Compute the covariance matrix.
1230
     * 
1231
     * @param vector|null $mean
1232
     * @return matrix
1233
     */
1234
    public function covariance(vector|null $mean = null): matrix {
1235
        if (isset($mean)) {
1236
            if ($mean->col !== $this->row) {
1237
                self::_err('Err:: given mean vector dimensionality mismatched!');
1238
            }
1239
        } else {
1240
            $mean = $this->mean();
1241
        }
1242
1243
        $b = $this->subtractColumnVector($mean);
1244
1245
        return $b->dot($b->transpose())
1246
                        ->divideScalar($this->row);
1247
    }
1248
1249
    /**
1250
     * Square of matrix
1251
     * @return matrix
1252
     */
1253
    public function square(): matrix {
1254
        return $this->multiplyMatrix($this);
1255
    }
1256
1257
    /**
1258
     * 
1259
     * @param int|float|matrix|vector $d
1260
     * @return matrix
1261
     */
1262
    public function equal(int|float|matrix|vector $d): matrix {
1263
        if ($d instanceof self) {
1264
            return $this->equalMatrix($d);
1265
        }
1266
        if ($d instanceof vector) {
1267
            return $this->equalVector($d);
1268
        }
1269
        return $this->equalScalar($d);
1270
    }
1271
1272
    protected function equalMatrix(matrix $m): matrix {
1273
        if ($this->checkShape($this, $m)) {
1274
            $ar = self::factory($this->row, $this->col);
1275
            for ($i = 0; $i < $this->ndim; ++$i) {
1276
                $ar->data[$i] = $this->data[$i] == $m->data[$i] ? 1 : 0;
1277
            }
1278
            return $ar;
1279
        }
1280
    }
1281
1282
    protected function equalVector(vector $v): matrix {
1283
        if ($this->checkDimensions($v, $this)) {
1284
            $ar = self::factory($this->row, $this->col);
1285
            for ($i = 0; $i < $this->row; ++$i) {
1286
                for ($j = 0; $j < $this->col; ++$j) {
1287
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] == $v->data[$j] ? 1 : 0;
1288
                }
1289
            }
1290
            return $ar;
1291
        }
1292
    }
1293
1294
    protected function equalScalar(int|float $s): matrix {
1295
        $ar = self::factory($this->row, $this->col);
1296
        for ($i = 0; $i < $this->ndim; ++$i) {
1297
            $ar->data[$i] = $this->data[$i] == $s ? 1 : 0;
1298
        }
1299
        return $ar;
1300
    }
1301
1302
    /**
1303
     * 
1304
     * @param int|float|matrix|vector $d
1305
     * @return matrix
1306
     */
1307
    public function greater(int|float|matrix|vector $d): matrix {
1308
        if ($d instanceof self) {
1309
            return $this->greaterMatrix($d);
1310
        }
1311
        if ($d instanceof vector) {
1312
            return $this->greaterVector($d);
1313
        }
1314
        return $this->greaterScalar($d);
1315
    }
1316
1317
    protected function greaterMatrix(matrix $m): matrix {
1318
        if ($this->checkShape($this, $m)) {
1319
            $ar = self::factory($this->row, $this->col);
1320
            for ($i = 0; $i < $this->ndim; ++$i) {
1321
                $ar->data[$i] = $this->data[$i] > $m->data[$i] ? 1 : 0;
1322
            }
1323
            return $ar;
1324
        }
1325
    }
1326
1327
    protected function greaterVector(vector $v): matrix {
1328
        if ($this->checkDimensions($v, $this)) {
1329
            $ar = self::factory($this->row, $this->col);
1330
            for ($i = 0; $i < $this->row; ++$i) {
1331
                for ($j = 0; $j < $this->col; ++$j) {
1332
                    $ar->data[$i * $this->col + $j] = $this->data[$i * $this->col + $j] > $v->data[$j] ? 1 : 0;
1333
                }
1334
            }
1335
            return $ar;
1336
        }
1337
    }
1338
1339
    protected function greaterScalar(int|float $s): matrix {
1340
        $ar = self::factory($this->row, $this->col);
1341
        for ($i = 0; $i < $this->ndim; ++$i) {
1342
            $ar->data[$i] = $this->data[$i] > $s ? 1 : 0;
1343
        }
1344
        return $ar;
1345
    }
1346
1347
    /**
1348
     * 
1349
     * @param int|float|matrix $m
1350
     * @return matrix
1351
     */
1352
    public function less(int|float|matrix $m): matrix {
1353
        $ar = self::factory($this->row, $this->col);
1354
        if ($m instanceof self) {
1355
            if ($this->checkShape($this, $m)) {
1356
                for ($i = 0; $i < $this->ndim; ++$i) {
1357
                    $ar->data[$i] = $this->data[$i] < $m->data[$i] ? 1 : 0;
1358
                }
1359
                return $ar;
1360
            }
1361
        } else {
1362
            for ($i = 0; $i < $this->ndim; ++$i) {
1363
                $ar->data[$i] = $this->data[$i] < $m ? 1 : 0;
1364
            }
1365
            return $ar;
1366
        }
1367
    }
1368
1369
    /**
1370
     * print the matrix in consol
1371
     */
1372
    public function printMatrix() {
1373
        echo __CLASS__ . PHP_EOL;
1374
        for ($i = 0; $i < $this->row; ++$i) {
1375
            for ($j = 0; $j < $this->col; ++$j) {
1376
                printf('%lf  ', $this->data[$i * $this->col + $j]);
1377
            }
1378
            echo PHP_EOL;
1379
        }
1380
    }
1381
1382
    public function __toString() {
1383
        return (string) $this->printMatrix();
1384
    }
1385
1386
    private function flattenArray(array $ar) {
1387
        if (is_array($ar) && is_array($ar[0])) {
1388
            $a = [];
1389
            foreach ($ar as $y => $value) {
1390
                foreach ($value as $k => $v) {
1391
                    $a[] = $v;
1392
                }
1393
            }
1394
            return $a;
1395
        }
1396
    }
1397
1398
    /**
1399
     * 
1400
     * @param int $row
1401
     * @param int $col
1402
     * @param int $dtype
1403
     * @return $this
1404
     */
1405
    protected function __construct(public int $row, public int $col, int $dtype = self::DOUBLE) {
1406
        if ($this->row < 1 || $this->col < 1) {
1407
            self::_invalidArgument('* To create Numphp/Matrix row & col must be greater than 0!, Op Failed! * ');
1408
        }
1409
        parent::__construct($this->row * $this->col, $dtype);
1410
        return $this;
1411
    }
1412
}
1413