Completed
Push — master ( 5df011...747e00 )
by Changwan
03:50
created

Matrix::__toString()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 0
dl 0
loc 15
ccs 11
cts 11
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Math\LinearAlgebra;
3
4
use InvalidArgumentException;
5
use Closure;
6
7
class Matrix
8
{
9
    /**
10
     * @param int $rowSize
11
     * @param int $colSize
12
     * @return static
13
     */
14 1
    public static function zeros($rowSize, $colSize)
15
    {
16 1
        return new static($rowSize, $colSize);
17
    }
18
19
    /** @var int */
20
    protected $rowSize;
21
22
    /** @var int */
23
    protected $colSize;
24
25
    /** @var array */
26
    protected $items = [];
27
28
    /**
29
     * Matrix constructor.
30
     * @param int $rowSize
31
     * @param int $colSize
32
     * @param array $items
33
     */
34 7
    public function __construct($rowSize, $colSize, array $items = [])
35
    {
36 7
        $this->rowSize = $rowSize;
37 7
        $this->colSize = $colSize;
38 7
        $this->items = $this->removeSparse($rowSize, $colSize, $items);
39 7
    }
40
41 7
    protected function removeSparse($rowSize, $colSize, array $items = [])
42
    {
43 7
        $cleanedItems = [];
44 7
        for ($rowIndex = 0; $rowIndex < $rowSize; $rowIndex++) {
45 7
            $row = [];
46 7
            for ($colIndex = 0; $colIndex < $colSize; $colIndex++) {
47 7
                if (isset($items[$rowIndex][$colIndex]) && $items[$rowIndex][$colIndex]) {
48 6
                    $row[$colIndex] = $items[$rowIndex][$colIndex];
49
                }
50
            }
51 7
            if (count($row)) {
52 6
                $cleanedItems[$rowIndex] = $row;
53
            }
54
        }
55 7
        return $cleanedItems;
56
    }
57
58 1
    public function __toString()
59
    {
60 1
        $result = "Matrix(\n";
61 1
        for ($rowIndex = 0; $rowIndex < $this->rowSize; $rowIndex++) {
62 1
            $cols = [];
63 1
            for ($colIndex = 0; $colIndex < $this->colSize; $colIndex++) {
64 1
                $cols[] = isset($this->items[$rowIndex][$colIndex]) ?
65 1
                    $this->items[$rowIndex][$colIndex] :
66 1
                    0;
67
            }
68 1
            $result .= '  ' . implode(', ', $cols) . "\n";
69
        }
70 1
        $result .= ')';
71 1
        return $result;
72
    }
73
74
    /**
75
     * @return int
76
     */
77
    public function getRowSize()
78
    {
79
        return $this->rowSize;
80
    }
81
82
    /**
83
     * @return int
84
     */
85
    public function getColSize()
86
    {
87
        return $this->colSize;
88
    }
89
90 1
    public function equal($matrix)
91
    {
92 1
        if (!($matrix instanceof Matrix)) {
93
            return false;
94
        }
95
        return $matrix->each(function ($item, $rowIndex, $colIndex) {
96 1
            return $this->items[$rowIndex][$colIndex] == $item;
97 1
        });
98
    }
99
100
    /**
101
     * @param int $index
102
     * @return \Wandu\Math\LinearAlgebra\Vector
103
     */
104 2
    public function getRowVector($index)
105
    {
106 2
        return new Vector($this->items[$index]);
107
    }
108
109 2
    public function getColVector($index)
110
    {
111 2
        $new = [];
112 2
        foreach ($this->items as $row) {
113 2
            $new[] = $row[$index];
114
        }
115 2
        return new Vector($new);
116
    }
117
118 2
    public function multiply($other)
119
    {
120 2
        if ($other instanceof Matrix) {
121 1
            return $this->multiplyWithMatrix($other);
122
        }
123 1
        if (is_numeric($other)) {
124 1
            return $this->multiplyWithScalar($other);
125
        }
126
        throw new InvalidArgumentException('unsupported type.');
127
    }
128
129
    /**
130
     * @param $other
131
     * @return \Wandu\Math\LinearAlgebra\Matrix
132
     */
133
    public function multiplyWithScalar($other)
134
    {
135 2
        return $this->map(function ($item) use ($other) {
136 2
            return $item * $other;
137 2
        });
138
    }
139
140
    /**
141
     * @return \Wandu\Math\LinearAlgebra\Matrix
142
     */
143 1
    public function transpose()
144
    {
145 1
        $newItems = array_pad([], $this->colSize, []);
146 1
        foreach ($this->items as $rowIndex => $row) {
147 1
            foreach ($row as $colIndex => $item) {
148 1
                $newItems[$colIndex][$rowIndex] = $item;
149
            }
150
        }
151 1
        return new static($this->colSize, $this->rowSize, $newItems);
152
    }
153
154
    /**
155
     * @param \Wandu\Math\LinearAlgebra\Matrix $other
156
     * @return \Wandu\Math\LinearAlgebra\Matrix
157
     */
158 1
    public function multiplyWithMatrix(Matrix $other)
159
    {
160 1
        if ($this->colSize !== $other->rowSize) {
161 1
            throw new InvalidArgumentException('cannot calculate, because of size.');
162
        }
163 1
        $newRowSize = $this->rowSize;
164 1
        $newColSize = $other->colSize;
165 1
        $newItems = [];
166 1
        for ($rowIndex = 0; $rowIndex < $newRowSize; $rowIndex++) {
167 1
            for ($colIndex = 0; $colIndex < $newColSize; $colIndex++) {
168 1
                $newItems[$rowIndex][$colIndex] = $this->getRowVector($rowIndex)->dot($other->getColVector($colIndex));
169
            }
170
        }
171 1
        return new static($this->rowSize, $other->colSize, $newItems);
172
    }
173
174
    /**
175
     * @param \Closure $handler
176
     * @return \Wandu\Math\LinearAlgebra\Matrix
177
     */
178 2
    public function map(Closure $handler)
179
    {
180 2
        $newItems = array_pad([], $this->rowSize, []);
181 2
        foreach ($this->items as $rowIndex => $row) {
182 2
            foreach ($row as $colIndex => $item) {
183 2
                $newItems[$rowIndex][$colIndex] = $handler->__invoke($item, $rowIndex, $colIndex);
184
            }
185
        }
186 2
        return new static($this->rowSize, $this->colSize, $newItems);
187
    }
188
189
    /**
190
     * @param \Closure $handler
191
     * @return bool
192
     */
193 1
    public function each(Closure $handler)
194
    {
195 1
        for ($rowIndex = 0; $rowIndex < $this->rowSize; $rowIndex++) {
196 1
            for ($colIndex = 0; $colIndex < $this->colSize; $colIndex++) {
197 1
                $item = isset($this->items[$rowIndex][$colIndex]) ?
198 1
                    $this->items[$rowIndex][$colIndex] :
199 1
                    0;
200 1
                if ($handler->__invoke($item, $rowIndex, $colIndex) === false) {
201
                    return false;
202
                }
203
            }
204
        }
205 1
        return true;
206
    }
207
}
208