Passed
Push — master ( 291666...ef8eea )
by Boudry
03:25
created

Pairwise   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 97.37%

Importance

Changes 0
Metric Value
dl 0
loc 180
rs 9.6
c 0
b 0
f 0
ccs 74
cts 76
cp 0.9737
wmc 35
lcom 1
cbo 2

15 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetSet() 0 1 1
A offsetExists() 0 3 1
A offsetUnset() 0 1 1
A offsetGet() 0 3 1
A rewind() 0 4 1
A current() 0 3 1
A key() 0 3 1
A next() 0 5 2
A valid() 0 3 1
A __construct() 0 5 1
A __clone() 0 4 1
A setElection() 0 4 1
A getExplicitPairwise() 0 20 4
C doPairwise() 0 73 14
A formatNewpairwise() 0 18 4
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 Condorcet\Algo;
13
14
use Condorcet\CondorcetVersion;
15
use Condorcet\Election;
16
use Condorcet\Timer\Chrono as Timer_Chrono;
17
18
class Pairwise implements \ArrayAccess, \Iterator
19
{
20
    use CondorcetVersion;
21
22
    // Implement ArrayAccess
23
    public function offsetSet($offset, $value) : void {}
24
25
    public function offsetExists($offset) : bool {
26
        return isset($this->_Pairwise[$offset]);
27
    }
28
29
    public function offsetUnset($offset) : void {}
30
31 37
    public function offsetGet($offset) : ?array {
32 37
        return $this->_Pairwise[$offset] ?? null;
33
    }
34
35
36
    // Implement Iterator
37
    private $valid = true;
38
39 90
    public function rewind() : void {
40 90
        reset($this->_Pairwise);
41 90
        $this->valid = true;
42 90
    }
43
44 90
    public function current() : array {
45 90
        return $this->_Pairwise[$this->key()];
46
    }
47
48 90
    public function key() : ?int {
49 90
        return key($this->_Pairwise);
50
    }
51
52 90
    public function next() : void {
53 90
        if (next($this->_Pairwise) === false) :
54 68
            $this->valid = false;
55
        endif;
56 90
    }
57
58 90
    public function valid() : bool {
59 90
        return $this->valid;
60
    }   
61
62
63
    // Pairwise
64
65
    protected $_Election;
66
    protected $_Pairwise = [];
67
68 93
    public function __construct (Election &$link)
69
    {
70 93
        $this->setElection($link);
71 93
        $this->doPairwise();
72 93
    }
73
74 1
    public function __clone ()
75
    {
76 1
        $this->_Election = null;
77 1
    }
78
79 93
    public function setElection (Election $election) : void
80
    {
81 93
        $this->_Election = $election;
82 93
    }
83
84 4
    public function getExplicitPairwise () : array
85
    {
86 4
        $explicit_pairwise = [];
87
88 4
        foreach ($this->_Pairwise as $candidate_key => $candidate_value) :
89
90 4
            $candidate_name = $this->_Election->getCandidateId($candidate_key, true);
91
            
92 4
            foreach ($candidate_value as $mode => $mode_value) :
93
94 4
                foreach ($mode_value as $candidate_list_key => $candidate_list_value) :
95 4
                    $explicit_pairwise[$candidate_name][$mode][$this->_Election->getCandidateId($candidate_list_key, true)] = $candidate_list_value;
96
                endforeach;
97
98
            endforeach;
99
100
        endforeach;
101
102 4
        return $explicit_pairwise;
103
    }
104
105 93
    protected function doPairwise () : void
106
    {
107
        // Chrono
108 93
        new Timer_Chrono ( $this->_Election->getTimerManager(), 'Do Pairwise' );
109
110 93
        $this->formatNewpairwise();
111
112
        // Win && Null
113 93
        foreach ( $this->_Election->getVotesManager() as $vote_id => $oneVote ) :
114
115
            // Ignore vote who don't respect election constraints
116 93
            if(!$this->_Election->testIfVoteIsValidUnderElectionConstraints($oneVote)) :
117 1
                continue;
118
            endif;
119
120 93
            $vote_ranking = $oneVote->getContextualRanking($this->_Election);
121
122 93
            $voteWeight = ($this->_Election->isVoteWeightIsAllowed()) ? $oneVote->getWeight() : 1;
123
124
            $vote_candidate_list = (function (array $r) : array { $list = [];
125 93
                    foreach ($r as $rank) :
126 93
                        foreach ($rank as $oneCandidate) :
127 93
                            $list[] = $oneCandidate;
128
                        endforeach;
129
                    endforeach;
130
131 93
                    return $list;})($vote_ranking);
132
133 93
            $done_Candidates = [];
134
135 93
            foreach ($vote_ranking as $candidates_in_rank) :
136
137 93
                $candidates_in_rank_keys = [];
138
139 93
                foreach ($candidates_in_rank as $candidate) :
140 93
                    $candidates_in_rank_keys[] = $this->_Election->getCandidateKey($candidate);
141
                endforeach;
142
143 93
                foreach ($candidates_in_rank as $candidate) :
144
145 93
                    $candidate_key = $this->_Election->getCandidateKey($candidate);
146
147
                    // Process
148 93
                    foreach ( $vote_candidate_list as $g_Candidate ) :
149
150 93
                        $g_candidate_key = $this->_Election->getCandidateKey($g_Candidate);
151
152 93
                        if ($candidate_key === $g_candidate_key) :
153 93
                            continue;
154
                        endif;
155
156
                        // Win & Lose
157 93
                        if (    !in_array($g_candidate_key, $done_Candidates, true) && 
158 93
                                !in_array($g_candidate_key, $candidates_in_rank_keys, true) ) :
159
160 92
                            $this->_Pairwise[$candidate_key]['win'][$g_candidate_key] += $voteWeight;
161 92
                            $this->_Pairwise[$g_candidate_key]['lose'][$candidate_key] += $voteWeight;
162
163 92
                            $done_Candidates[] = $candidate_key;
164
165
                        // Null
166 93
                        elseif (in_array($g_candidate_key, $candidates_in_rank_keys, true)) :
167 93
                            $this->_Pairwise[$candidate_key]['null'][$g_candidate_key] += $voteWeight;
168
                        endif;
169
170
                    endforeach;
171
172
                endforeach;
173
174
            endforeach;
175
176
        endforeach;
177 93
    }
178
179 93
    protected function formatNewpairwise () : void
180
    {
181 93
        foreach ( $this->_Election->getCandidatesList(false) as $candidate_key => $candidate_id ) :
182
183 93
            $this->_Pairwise[$candidate_key] = [ 'win' => [], 'null' => [], 'lose' => [] ];
184
185 93
            foreach ( $this->_Election->getCandidatesList(false) as $candidate_key_r => $candidate_id_r ) :
186
187 93
                if ($candidate_key_r !== $candidate_key) :
188 93
                    $this->_Pairwise[$candidate_key]['win'][$candidate_key_r]   = 0;
189 93
                    $this->_Pairwise[$candidate_key]['null'][$candidate_key_r]  = 0;
190 93
                    $this->_Pairwise[$candidate_key]['lose'][$candidate_key_r]  = 0;
191
                endif;
192
193
            endforeach;
194
195
        endforeach;
196 93
    }
197
}
198