Completed
Branch dev-2.0 (210bc7)
by Boudry
06:33
created

Pairwise::rewind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
    Condorcet PHP - Election manager and results calculator.
4
    Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
5
6
    By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
7
    https://github.com/julien-boudry/Condorcet
8
*/
9
declare(strict_types=1);
10
11
12
namespace CondorcetPHP\Condorcet\Algo;
13
14
use CondorcetPHP\Condorcet\CondorcetVersion;
15
use CondorcetPHP\Condorcet\Election;
16
use CondorcetPHP\Condorcet\Vote;
17
use CondorcetPHP\Condorcet\Timer\Chrono as Timer_Chrono;
18
19
class Pairwise implements \ArrayAccess, \Iterator
20
{
21
    use CondorcetVersion;
22
23
    // Implement ArrayAccess
24
    public function offsetSet($offset, $value) : void {}
25
26
    public function offsetExists($offset) : bool {
27
        return isset($this->_Pairwise[$offset]);
28
    }
29
30
    public function offsetUnset($offset) : void {}
31
32 38
    public function offsetGet($offset) : ?array {
33 38
        return $this->_Pairwise[$offset] ?? null;
34
    }
35
36
37
    // Implement Iterator
38
    private $valid = true;
39
40 92
    public function rewind() : void {
41 92
        reset($this->_Pairwise);
42 92
        $this->valid = true;
43 92
    }
44
45 92
    public function current() : array {
46 92
        return $this->_Pairwise[$this->key()];
47
    }
48
49 92
    public function key() : ?int {
50 92
        return key($this->_Pairwise);
51
    }
52
53 92
    public function next() : void {
54 92
        if (next($this->_Pairwise) === false) :
55 70
            $this->valid = false;
56
        endif;
57 92
    }
58
59 92
    public function valid() : bool {
60 92
        return $this->valid;
61
    }   
62
63
64
    // Pairwise
65
66
    protected $_Election;
67
    protected $_Pairwise_Model;
68
    protected $_Pairwise;
69
70 95
    public function __construct (Election $link)
71
    {
72 95
        $this->setElection($link);
73 95
        $this->formatNewpairwise();
74 95
        $this->doPairwise();
75 95
    }
76
77 1
    public function __clone ()
78
    {
79 1
        $this->_Election = null;
80 1
    }
81
82 95
    public function setElection (Election $election) : void
83
    {
84 95
        $this->_Election = $election;
85 95
    }
86
87 6
    public function addNewVote (int $key) : void
88
    {
89 6
        new Timer_Chrono ( $this->_Election->getTimerManager(), 'Add Vote To Pairwise' );
90
91 6
        $this->computeOneVote($this->_Pairwise,$this->_Election->getVotesManager()[$key]);
92 6
    }
93
94 4
    public function removeVote (int $key) : void
95
    {
96 4
        new Timer_Chrono ( $this->_Election->getTimerManager(), 'Remove Vote To Pairwise' );
97
98 4
        $diff = $this->_Pairwise_Model;
99
100 4
        $this->computeOneVote($diff,$this->_Election->getVotesManager()[$key]);
101
102 4
        foreach ($diff as $candidate_key => $candidate_details) :
103 4
            foreach ($candidate_details as $type => $opponent) :
104 4
                foreach ($opponent as $opponent_key => $score) :
105 4
                    $this->_Pairwise[$candidate_key][$type][$opponent_key] -= $score;
106
                endforeach;
107
            endforeach;
108
        endforeach;
109 4
    }
110
111 2
    public function getExplicitPairwise () : array
112
    {
113 2
        $explicit_pairwise = [];
114
115 2
        foreach ($this->_Pairwise as $candidate_key => $candidate_value) :
116
117 2
            $candidate_name = $this->_Election->getCandidateObjectFromKey($candidate_key)->getName();
118
119 2
            foreach ($candidate_value as $mode => $mode_value) :
120
121 2
                foreach ($mode_value as $candidate_list_key => $candidate_list_value) :
122 2
                    $explicit_pairwise[$candidate_name][$mode][$this->_Election->getCandidateObjectFromKey($candidate_list_key)->getName()] = $candidate_list_value;
123
                endforeach;
124
125
            endforeach;
126
127
        endforeach;
128
129 2
        return $explicit_pairwise;
130
    }
131
132 95
    protected function formatNewpairwise () : void
133
    {
134 95
        $this->_Pairwise_Model = [];
135
136 95
        foreach ( $this->_Election->getCandidatesList() as $candidate_key => $candidate_id ) :
137
138 95
            $this->_Pairwise_Model[$candidate_key] = [ 'win' => [], 'null' => [], 'lose' => [] ];
139
140 95
            foreach ( $this->_Election->getCandidatesList() as $candidate_key_r => $candidate_id_r ) :
141
142 95
                if ($candidate_key_r !== $candidate_key) :
143 95
                    $this->_Pairwise_Model[$candidate_key]['win'][$candidate_key_r]   = 0;
144 95
                    $this->_Pairwise_Model[$candidate_key]['null'][$candidate_key_r]  = 0;
145 95
                    $this->_Pairwise_Model[$candidate_key]['lose'][$candidate_key_r]  = 0;
146
                endif;
147
148
            endforeach;
149
150
        endforeach;
151 95
    }
152
153 95
    protected function doPairwise () : void
154
    {
155
        // Chrono
156 95
        new Timer_Chrono ( $this->_Election->getTimerManager(), 'Do Pairwise' );
157
158 95
        $this->_Pairwise = $this->_Pairwise_Model;
159
160 95
        foreach ( $this->_Election->getVotesManager()->getVotesValidUnderConstraintGenerator() as $vote_id => $oneVote ) :
161 95
            $this->computeOneVote($this->_Pairwise, $oneVote);
162
        endforeach;
163 95
    }
164
165 95
    protected function computeOneVote (array &$pairwise, Vote $oneVote) : void
166
    {
167 95
        $vote_ranking = $oneVote->getContextualRanking($this->_Election);
168
169 95
        $voteWeight = $this->_Election->isVoteWeightIsAllowed() ? $oneVote->getWeight() : 1;
170
171 95
        $vote_candidate_list = [];
172
173 95
        foreach ($vote_ranking as $rank) :
174 95
            foreach ($rank as $oneCandidate) :
175 95
                $vote_candidate_list[] = $oneCandidate;
176
            endforeach;
177
        endforeach;
178
179 95
        $done_Candidates = [];
180
181 95
        foreach ($vote_ranking as $candidates_in_rank) :
182
183 95
            $candidates_in_rank_keys = [];
184
185 95
            foreach ($candidates_in_rank as $candidate) :
186 95
                $candidates_in_rank_keys[] = $this->_Election->getCandidateKey($candidate);
187
            endforeach;
188
189 95
            foreach ($candidates_in_rank as $candidate) :
190
191 95
                $candidate_key = $this->_Election->getCandidateKey($candidate);
192
193
                // Process
194 95
                foreach ( $vote_candidate_list as $g_Candidate ) :
195
196 95
                    $g_candidate_key = $this->_Election->getCandidateKey($g_Candidate);
197
198 95
                    if ($candidate_key === $g_candidate_key) :
199 95
                        continue;
200
                    endif;
201
202
                    // Win & Lose
203 95
                    if (    !in_array($g_candidate_key, $done_Candidates, true) && 
204 95
                            !in_array($g_candidate_key, $candidates_in_rank_keys, true) ) :
205
206 94
                        $pairwise[$candidate_key]['win'][$g_candidate_key] += $voteWeight;
207 94
                        $pairwise[$g_candidate_key]['lose'][$candidate_key] += $voteWeight;
208
209 94
                        $done_Candidates[] = $candidate_key;
210
211
                    // Null
212 95
                    elseif (in_array($g_candidate_key, $candidates_in_rank_keys, true)) :
213 95
                        $pairwise[$candidate_key]['null'][$g_candidate_key] += $voteWeight;
214
                    endif;
215
216
                endforeach;
217
218
            endforeach;
219
220
        endforeach;
221 95
    }
222
223
}
224