-
Notifications
You must be signed in to change notification settings - Fork 0
/
ElectionData.h
295 lines (265 loc) · 12.5 KB
/
ElectionData.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#pragma once
#include "tinyxml2.h"
#include "json.h"
#include <array>
#include <unordered_map>
#include <numeric>
#include <unordered_map>
#include <vector>
namespace Results {
struct Booth {
struct Candidate {
int affiliationId = -1;
int candidateId = -1;
int fpVotes = 0;
};
std::string name;
int officialId = -1;
std::array<int, 2> tcpVote = { 0, 0 };
std::array<int, 2> newTcpVote = { 0, 0 };
std::array<int, 2> tcpAffiliationId = { -1, -1 }; // independent = 0
std::array<int, 2> tcpCandidateId = { -1, -1 };
std::vector<Candidate> oldFpCandidates;
std::vector<Candidate> fpCandidates;
bool newResultsZero = false;
float percentVote(int whichCandidate) const { return float(tcpVote[whichCandidate]) / float(tcpVote[0] + tcpVote[1]) * 100.0f; }
bool hasOldResults() const { return tcpVote[0] + tcpVote[1]; }
bool hasNewResults() const { return newResultsZero || (newTcpVote[0] + newTcpVote[1]); }
bool hasOldAndNewResults() const { return hasOldResults() && hasNewResults(); }
bool hasValidPreferenceData() const {
// sometimes Fp and Tcp votes for a booth are not properly synchronised, this makes sure they're about the same
return hasNewResults() && totalNewFpVotes() &&
abs(totalNewTcpVotes() - totalNewFpVotes()) < std::min(10, totalNewTcpVotes() / 50 - 1);
}
int totalOldTcpVotes() const { return tcpVote[0] + tcpVote[1]; }
int totalNewTcpVotes() const { return newTcpVote[0] + newTcpVote[1]; }
int totalOldFpVotes() const { return std::accumulate(oldFpCandidates.begin(), oldFpCandidates.end(), 0, [](int val, Candidate c) {return val + c.fpVotes; }); }
int totalNewFpVotes() const { return std::accumulate(fpCandidates.begin(), fpCandidates.end(), 0, [](int val, Candidate c) {return val + c.fpVotes; }); }
bool isPPVC() const { return name.find("PPVC") != std::string::npos; }
// raw Swing in proportion terms (not percentage)
float rawSwing(int candidate = 0) const {
if (!(totalNewTcpVotes() && totalOldTcpVotes())) return 0.0f;
return float(newTcpVote[candidate]) / float(totalNewTcpVotes()) - float(tcpVote[candidate]) / float(totalOldTcpVotes());
}
struct Coords {
float latitude = 0.0f; float longitude = 0.0f;
};
Coords coords;
};
struct Candidate {
int affiliationId = 0;
std::string name;
};
struct Affiliation {
std::string shortCode;
};
struct Seat {
struct Candidate {
int candidateId = 0;
int affiliationId = 0; // independent = 0
int ordinaryVotes = 0;
int absentVotes = 0;
int provisionalVotes = 0;
int prepollVotes = 0;
int postalVotes = 0;
int declarationVotes() const { return absentVotes + provisionalVotes + prepollVotes + postalVotes; }
int totalVotes() const { return ordinaryVotes + declarationVotes(); }
};
std::string name;
int officialId = -1;
int enrolment = 0;
bool classic2pp = true;
std::array<Candidate, 2> finalCandidates;
std::vector<Candidate> fpCandidates;
std::vector<Candidate> oldFpCandidates;
std::vector<int> booths; // stores official booth id
Candidate const& leadingCandidate() const { return finalCandidates[0].totalVotes() > finalCandidates[1].totalVotes() ? finalCandidates[0] : finalCandidates[1]; }
Candidate const& trailingCandidate() const { return finalCandidates[1].totalVotes() > finalCandidates[0].totalVotes() ? finalCandidates[0] : finalCandidates[1]; }
int ordinaryVotes() const { return finalCandidates[0].ordinaryVotes + finalCandidates[1].ordinaryVotes; }
int declarationVotes() const { return finalCandidates[0].declarationVotes() + finalCandidates[1].declarationVotes(); }
int absentVotes() const { return finalCandidates[0].absentVotes + finalCandidates[1].absentVotes; }
int provisionalVotes() const { return finalCandidates[0].provisionalVotes + finalCandidates[1].provisionalVotes; }
int prepollVotes() const { return finalCandidates[0].prepollVotes + finalCandidates[1].prepollVotes; }
int postalVotes() const { return finalCandidates[0].postalVotes + finalCandidates[1].postalVotes; }
int total2cpVotes() const { return finalCandidates[0].totalVotes() + finalCandidates[1].totalVotes(); }
float ordinaryVotePercent() const { return float(ordinaryVotes()) / float(total2cpVotes()) * 100.0f; }
float declarationVotePercent() const { return float(declarationVotes()) / float(total2cpVotes()) * 100.0f; }
float absentVotePercent() const { return float(absentVotes()) / float(total2cpVotes()) * 100.0f; }
float provisionalVotePercent() const { return float(provisionalVotes()) / float(total2cpVotes()) * 100.0f; }
float prepollVotePercent() const { return float(prepollVotes()) / float(total2cpVotes()) * 100.0f; }
float postalVotePercent() const { return float(postalVotes()) / float(total2cpVotes()) * 100.0f; }
int totalFpVotes() const { return std::accumulate(fpCandidates.begin(), fpCandidates.end(), 0, [](int val, Candidate c) {return val + c.totalVotes(); }); }
};
typedef std::unordered_map<int, Booth> BoothMap;
typedef std::unordered_map<int, Seat> SeatMap;
}
namespace Results2 {
enum class VoteType {
Invalid,
Ordinary,
Absent,
Provisional,
PrePoll,
Postal,
Early,
IVote
};
inline std::string voteTypeName(VoteType v) {
static const auto nameMap = std::unordered_map<VoteType, std::string>{ {VoteType::Absent, "Absent"},
{VoteType::Invalid, "Invalid"}, {VoteType::Ordinary, "Ordinary"}, {VoteType::Postal, "Postal"},
{VoteType::PrePoll, "PrePoll"}, {VoteType::Provisional, "Provisional"}, {VoteType::Early, "Early"},
{VoteType::IVote, "iVote"} };
return nameMap.at(v);
}
struct Party {
int32_t id;
std::string name;
std::string shortCode;
};
struct Candidate {
constexpr static int Independent = -1;
int32_t id;
std::string name;
int32_t party = Independent;
};
struct Coalition {
int32_t id;
std::string name;
std::string shortCode;
};
struct Booth {
enum class Type {
Normal,
Ppvc,
Remote,
Prison,
Hospital,
Other,
Invalid
};
int32_t id;
std::string name;
Type type = Type::Normal;
int32_t parentSeat;
std::unordered_map<int32_t, int32_t> fpVotes; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> tcpVotes; // map affiliation id -> vote count
std::unordered_map<int32_t, int32_t> tppVotes; // map affiliation id -> vote count
std::unordered_map<int32_t, float> fpPercent; // as percentage
std::unordered_map<int32_t, float> fpSwing; // as percentage
std::unordered_map<int32_t, float> fpTransformedSwing;
std::unordered_map<int32_t, float> tcpPercent; // as percentage
std::unordered_map<int32_t, float> tcpSwing; // as percentage
std::unordered_map<int32_t, float> tcpEstimate; // as percentage, for booths with fp but no tcp
std::unordered_map<int32_t, float> tcpEstimateSwing; // as percentage, for booths with fp but no tcp
std::unordered_map<int32_t, float> tppEstimate; // as percentage
std::unordered_map<int32_t, float> tppSwing; // as percentage (either =tcp or an estimate)
int totalVotesFp() const {
return std::accumulate(fpVotes.begin(), fpVotes.end(), 0,
[](int acc, decltype(fpVotes)::value_type v) {return acc + v.second; });
}
int totalVotesTcp() const {
return std::accumulate(tcpVotes.begin(), tcpVotes.end(), 0,
[](int acc, decltype(tcpVotes)::value_type v) {return acc + v.second; });
}
int totalVotesTpp() const {
return std::accumulate(tppVotes.begin(), tppVotes.end(), 0,
[](int acc, decltype(tppVotes)::value_type v) {return acc + v.second; });
}
};
struct Seat {
int32_t id;
std::string name;
int32_t enrolment;
std::vector<int32_t> booths;
std::unordered_map<int32_t, std::unordered_map<VoteType, int>> fpVotes; // map candidate id -> (vote type -> vote count)
std::unordered_map<int32_t, std::unordered_map<VoteType, int>> tcpVotes; // map party id -> (vote type -> vote count)
std::unordered_map<int32_t, std::unordered_map<VoteType, int>> tppVotes; // map party id -> vote count
float fpProgress; // as percentage
float tcpProgress; // as percentage
float fpSwingProgress; // as percentage
float tcpSwingProgress; // as percentage
std::unordered_map<int32_t, float> fpPercent; // total booth as percentage
std::unordered_map<int32_t, float> fpSwing; // as percentage
std::unordered_map<int32_t, float> fpTransformedSwing; // as percentage
std::unordered_map<int32_t, float> tcpPercent; // as percentage
std::unordered_map<int32_t, float> tcpSwing; // as percentage
std::unordered_map<int32_t, float> tppPercent; // as percentage
std::unordered_map<int32_t, float> tppSwing; // as percentage
float tcpSwingBasis = 0.0f; // indicates how much & how reliable data for the tcp swing in this seat is
float tppSwingBasis = 0.0f; // indicates how much & how reliable data for the tpp swing in this seat is
bool isTpp = true;
int totalVotesFp(VoteType exclude = VoteType::Invalid) const {
return std::accumulate(fpVotes.begin(), fpVotes.end(), 0,
[&](int acc, decltype(fpVotes)::value_type val) {return acc +
std::accumulate(val.second.begin(), val.second.end(), 0,
[&](int acc, decltype(val.second)::value_type val2) {return val2.first != exclude ? acc + val2.second : acc; }
); }
);
}
int totalVotesFpCandidate(int candidate) const {
return std::accumulate(fpVotes.at(candidate).begin(), fpVotes.at(candidate).end(), 0,
[&](int acc, std::unordered_map<VoteType, int>::value_type val2) {return acc + val2.second; }
);
}
int totalVotesTcp(std::vector<VoteType> const& exclude) const {
return std::accumulate(tcpVotes.begin(), tcpVotes.end(), 0,
[&](int acc, decltype(tcpVotes)::value_type val) {return acc +
std::accumulate(val.second.begin(), val.second.end(), 0,
[&](int acc, decltype(val.second)::value_type val2) {
return std::find(exclude.begin(), exclude.end(), val2.first) == exclude.end() ?
acc + val2.second : acc;
}
); }
);
}
int totalVotesTcpParty(int party) const {
return std::accumulate(tcpVotes.at(party).begin(), tcpVotes.at(party).end(), 0,
[&](int acc, std::unordered_map<VoteType, int>::value_type val2) {return acc + val2.second; }
);
}
// The below are obsolete, kept around for file compatibility purposes but not longer used
std::unordered_map<int32_t, int32_t> ordinaryVotesFp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> absentVotesFp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> provisionalVotesFp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> prepollVotesFp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> postalVotesFp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> ordinaryVotesTcp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> absentVotesTcp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> provisionalVotesTcp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> prepollVotesTcp; // map candidate id -> vote count
std::unordered_map<int32_t, int32_t> postalVotesTcp; // map candidate id -> vote count
};
struct Election {
typedef int32_t Id;
std::string name;
Id id = 0;
std::unordered_map<int32_t, Party> parties; // map affiliation id -> affiliation info
std::unordered_map<int32_t, Candidate> candidates; // map candidate id -> candidate info
std::unordered_map<int32_t, Coalition> coalitions; // map coalition id -> coalition info
std::unordered_map<int32_t, Booth> booths; // map booth id -> booth info
std::unordered_map<int32_t, Seat> seats; // map seat id -> seat info
enum class Format {
AEC,
VEC,
NSWEC
};
Election() {parties.insert({-1, {-1, "Independent", "IND"}});}
static Election createAec(tinyxml2::XMLDocument const& xml);
static Election createVec(
nlohmann::json const& results,
tinyxml2::XMLDocument const& input_candidates,
tinyxml2::XMLDocument const& input_booths
);
static Election createVec(
tinyxml2::XMLDocument const& input_candidates,
tinyxml2::XMLDocument const& input_booths
);
static Election createNswec(nlohmann::json const& results, tinyxml2::XMLDocument const& xml);
void update(tinyxml2::XMLDocument const& xml, Format format = Format::AEC);
void update2022VicPrev(nlohmann::json const& results, tinyxml2::XMLDocument const& input_candidates,
tinyxml2::XMLDocument const& input_booths);
void preload2022Vic(tinyxml2::XMLDocument const& input_candidates,
tinyxml2::XMLDocument const& input_booths, bool includeSeatBooths = false);
void preloadNswec(nlohmann::json const& results, tinyxml2::XMLDocument const& zeros, bool includeSeatBooths = false);
};
}