Row   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Test Coverage

Coverage 92.65%

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 224
ccs 63
cts 68
cp 0.9265
rs 10
c 0
b 0
f 0
wmc 22

15 Methods

Rating   Name   Duplication   Size   Complexity  
A createFromRow() 0 5 1
A getCoefficientForSymbol() 0 6 2
A remove() 0 3 1
A solveForSymbols() 0 4 1
A getConstant() 0 3 1
A insertSymbol() 0 11 3
A solveForSymbol() 0 12 2
A setCells() 0 3 1
A add() 0 3 1
A insertRow() 0 7 2
A substitute() 0 6 2
A getCells() 0 3 1
A __construct() 0 4 1
A setConstant() 0 3 1
A reverseSign() 0 10 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Ctefan\Kiwi;
5
6
/**
7
 * An internal tableau row class used by the constraint solver.
8
 */
9
class Row
10
{
11
    /**
12
     * @var float
13
     */
14
    protected $constant;
15
16
    /**
17
     * @var \SplObjectStorage<Symbol, float>
18
     */
19
    protected $cells = [];
20
21
    /**
22
     * Row constructor.
23
     *
24
     * @param float $constant
25
     */
26 21
    public function __construct(float $constant = 0.0)
27
    {
28 21
        $this->constant = $constant;
29 21
        $this->cells = new \SplObjectStorage();
30 21
    }
31
32
    /**
33
     * Create a Row from another Row.
34
     *
35
     * @param self $otherRow
36
     * @return Row
37
     */
38 17
    static public function createFromRow(self $otherRow): self
39
    {
40 17
        $row = new self($otherRow->getConstant());
41 17
        $row->setCells($otherRow->getCells());
42 17
        return $row;
43
    }
44
45
    /**
46
     * Add a constant value to the row constant.
47
     *
48
     * The new value of the constant is returned.
49
     *
50
     * @param float $value
51
     * @return float
52
     */
53
    public function add(float $value): float
54
    {
55
        return $this->constant += $value;
56
    }
57
58
    /**
59
     * Insert a symbol into the row with a given coefficient.
60
     *
61
     * If the symbol already exists in the row, the coefficient will be added to the existing coefficient.
62
     * If the resulting coefficient is zero, the symbol will be removed from the row.
63
     *
64
     * @param Symbol $symbol
65
     * @param float $coefficient
66
     */
67 21
    public function insertSymbol(Symbol $symbol, float $coefficient = 1.0): void
68
    {
69 21
        if (true === $this->cells->contains($symbol)) {
70 9
            $existingCoefficient = $this->cells->offsetGet($symbol);
71 9
            $coefficient += $existingCoefficient;
72
        }
73
74 21
        if (true === Util::isNearZero($coefficient)) {
75 9
            $this->cells->offsetUnset($symbol);
76
        } else {
77 21
            $this->cells->attach($symbol, $coefficient);
78
        }
79 21
    }
80
81
    /**
82
     * Insert a row into this row with a given coefficient.
83
     *
84
     * The constant and the cells of the other row will be multiplied by the coefficient and added to this row.
85
     * Any cell with a resulting coefficient of zero will be removed from the row.
86
     *
87
     * @param self $row
88
     * @param float $coefficient
89
     */
90 19
    public function insertRow(self $row, float $coefficient = 1.0): void
91
    {
92 19
        $this->constant += $row->getConstant() * $coefficient;
93
94 19
        foreach ($row->getCells() as $symbol) {
95 19
            $_coefficient = $row->getCells()->offsetGet($symbol) * $coefficient;
96 19
            $this->insertSymbol($symbol, $_coefficient);
97
        }
98 19
    }
99
100
    /**
101
     * Remove the given symbol from the row.
102
     *
103
     * @param Symbol $symbol
104
     */
105 17
    public function remove(Symbol $symbol): void
106
    {
107 17
        $this->cells->offsetUnset($symbol);
108 17
    }
109
110
    /**
111
     * Reverse the sign of the constant and all cells in the row.
112
     */
113 16
    public function reverseSign(): void
114
    {
115 16
        $this->constant = -$this->constant;
116
117 16
        $newCells = new \SplObjectStorage();
118 16
        foreach ($this->cells as $symbol) {
119 16
            $value = -$this->cells->offsetGet($symbol);
120 16
            $newCells->attach($symbol, $value);
121
        }
122 16
        $this->cells = $newCells;
123 16
    }
124
125
    /**
126
     * Solve the row for the given symbol.
127
     *
128
     * This method assumes the row is of the form a * x + b * y + c = 0
129
     * and (assuming solve for x) will modify the row to represent the right hand side of x = -b/a * y - c / a.
130
     * The target symbol will be removed from the row, and the constant and other cells
131
     * will be multiplied by the negative inverse of the target coefficient.
132
     * The given symbol must exist in the row.
133
     *
134
     * @param Symbol $symbol
135
     */
136 21
    public function solveForSymbol(Symbol $symbol): void
137
    {
138 21
        $coefficient = -1.0 / $this->cells->offsetGet($symbol);
139 21
        $this->cells->offsetUnset($symbol);
140 21
        $this->constant *= $coefficient;
141
142 21
        $newCells = new \SplObjectStorage();
143 21
        foreach ($this->cells as $symbol) {
144 21
            $value = $this->cells->offsetGet($symbol) * $coefficient;
145 21
            $newCells->attach($symbol, $value);
146
        }
147 21
        $this->cells = $newCells;
148 21
    }
149
150
    /**
151
     * Solve the row for the given symbols.
152
     *
153
     * This method assumes the row is of the form x = b * y + c and will solve the row such that y = x / b - c / b.
154
     * The rhs symbol will be removed from the row, the lhs added,
155
     * and the result divided by the negative inverse of the rhs coefficient.
156
     * The lhs symbol must not exist in the row, and the rhs symbol must exist in the row.
157
     *
158
     * @param Symbol $lhs
159
     * @param Symbol $rhs
160
     */
161 17
    public function solveForSymbols(Symbol $lhs, Symbol $rhs): void
162
    {
163 17
        $this->insertSymbol($lhs, -1.0);
164 17
        $this->solveForSymbol($rhs);
165 17
    }
166
167
    /**
168
     * Get the coefficient for the given symbol.
169
     *
170
     * If the symbol does not exist in the row, zero will be returned.
171
     *
172
     * @param Symbol $symbol
173
     * @return float
174
     */
175 11
    public function getCoefficientForSymbol(Symbol $symbol): float
176
    {
177 11
        if (true === $this->cells->contains($symbol)) {
178 11
            return $this->cells->offsetGet($symbol);
179
        } else {
180 1
            return 0.0;
181
        }
182
    }
183
184
    /**
185
     * Substitute a symbol with the data from another row.
186
     *
187
     * Given a row of the form a * x + b and a substitution of the form x = 3 * y + c the row will be updated
188
     * to reflect the expression 3 * a * y + a * c + b.
189
     * If the symbol does not exist in the row, this is a no-op.
190
     *
191
     * @param Symbol $symbol
192
     * @param Row $row
193
     */
194 21
    public function substitute(Symbol $symbol, Row $row): void
195
    {
196 21
        if (true === $this->cells->contains($symbol)) {
197 15
            $coefficient = $this->cells->offsetGet($symbol);
198 15
            $this->cells->offsetUnset($symbol);
199 15
            $this->insertRow($row, $coefficient);
200
        }
201 21
    }
202
203
    /**
204
     * @return float
205
     */
206 21
    public function getConstant(): float
207
    {
208 21
        return $this->constant;
209
    }
210
211
    /**
212
     * @param float $constant
213
     */
214
    public function setConstant(float $constant): void
215
    {
216
        $this->constant = $constant;
217
    }
218
219
    /**
220
     * @return \SplObjectStorage
221
     */
222 21
    public function getCells(): \SplObjectStorage
223
    {
224 21
        return $this->cells;
225
    }
226
227
    /**
228
     * @param \SplObjectStorage $cells
229
     */
230 17
    public function setCells(\SplObjectStorage $cells): void
231
    {
232 17
        $this->cells = $cells;
233
    }
234
}