Pairwise::doPairwise()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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