Skip to content

Commit 565ba77

Browse files
committed
Add François Durand's Super Condorcet Winner concept as a set.
The concept is from DURAND, François. Why Instant-Runoff Voting Is So Resilient to Coalitional Manipulation: Phase Transitions in the Perturbed Culture. In: Proc. of the 24th International Conference on Autonomous Agents and Multiagent Systems. 2025. p. 658-666. https://www.ifaamas.org/Proceedings/aamas2025/pdfs/p658.pdf
1 parent 983f8d1 commit 565ba77

File tree

6 files changed

+113
-3
lines changed

6 files changed

+113
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ add_library(qe_singlewinner_methods
181181
src/singlewinner/sets/mdd.cc
182182
src/singlewinner/sets/mutual_majority.cc
183183
src/singlewinner/sets/partition.cc
184+
src/singlewinner/sets/scw.cc
184185
src/singlewinner/sets/topological.cc
185186
src/singlewinner/stats/cardinal.cc
186187
src/singlewinner/stats/mode.cc

src/singlewinner/get_methods.cc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ std::vector<std::shared_ptr<pairwise_method> > get_pairwise_sets() {
138138
return pw_sets;
139139
}
140140

141-
std::vector<std::shared_ptr<election_method> > get_sets() {
141+
std::vector<std::shared_ptr<election_method> > get_sets(
142+
bool include_experimental) {
143+
142144
std::vector<std::shared_ptr<election_method> > sets;
143145

144146
for (std::shared_ptr<election_method> em_set: get_pairwise_sets()) {
@@ -148,6 +150,11 @@ std::vector<std::shared_ptr<election_method> > get_sets() {
148150
sets.push_back(std::make_shared<mutual_majority_set>());
149151
sets.push_back(std::make_shared<dmt_set>());
150152
sets.push_back(std::make_shared<inner_burial_set>());
153+
sets.push_back(std::make_shared<super_condorcet_set>());
154+
155+
if (include_experimental) {
156+
sets.push_back(std::make_shared<idisqualif_set>());
157+
}
151158

152159
return sets;
153160
}
@@ -165,7 +172,8 @@ std::vector<std::shared_ptr<election_method> > get_singlewinner_methods(
165172

166173
std::vector<std::shared_ptr<positional> > positional_methods =
167174
get_positional_methods(truncate);
168-
std::vector<std::shared_ptr<election_method> > sets = get_sets();
175+
std::vector<std::shared_ptr<election_method> > sets = get_sets(
176+
include_experimental);
169177

170178
// We have to do it in this clumsy manner because of possible bugs in
171179
// handling methods with some candidates excluded.
@@ -230,6 +238,8 @@ std::vector<std::shared_ptr<election_method> > get_singlewinner_methods(
230238

231239
all_methods.push_back(std::make_shared<donated_contingent_vote>());
232240

241+
all_methods.push_back(std::make_shared<hash_random_cand>());
242+
233243
if (include_experimental) {
234244

235245
for (int p = 0; p <= CM_LAST; ++p) {

src/singlewinner/get_methods.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ std::vector<std::shared_ptr<positional> > get_positional_methods(
1111
bool truncate);
1212

1313
std::vector<std::shared_ptr<pairwise_method> > get_pairwise_sets();
14-
std::vector<std::shared_ptr<election_method> > get_sets();
14+
std::vector<std::shared_ptr<election_method> > get_sets(
15+
bool include_experimental);
1516

1617
// This function could stand being split into two or more: one for
1718
// comma and slash combinations, and one for loser elimination and

src/singlewinner/sets/all.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "mutual_majority.h"
1616
#include "partition.h"
1717
#include "topological.h"
18+
#include "scw.h"
1819

1920
#include "debug/venzke_landau.h"
2021

src/singlewinner/sets/scw.cc

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
#include "singlewinner/dmt/resistant/subelections.h"
3+
#include "scw.h"
4+
5+
#include <iostream>
6+
7+
std::pair<ordering, bool> super_condorcet_set::elect_inner(
8+
const election_t & papers,
9+
const std::vector<bool> & hopefuls,
10+
int num_candidates, cache_map * cache,
11+
bool winner_only) const {
12+
13+
size_t numcands = hopefuls.size();
14+
15+
subelections se;
16+
se.count_subelections(papers, hopefuls, true);
17+
18+
disqual_tensor level_disqualifications =
19+
se.get_level_disqualifications(hopefuls, true);
20+
21+
size_t super_cw_idx = 0;
22+
bool found_super_condorcet = false;
23+
24+
std::vector<size_t> copeland_counts(numcands, 0);
25+
26+
for (size_t i = 0;
27+
i < numcands && !found_super_condorcet; ++i) {
28+
bool is_super_cw = true;
29+
30+
for (size_t j = 0;
31+
j < numcands /*&& is_super_cw*/; ++j) {
32+
33+
if (!hopefuls[i]) {
34+
continue;
35+
}
36+
if (!hopefuls[j]) {
37+
continue;
38+
}
39+
if (i == j) {
40+
continue;
41+
}
42+
43+
if (!level_disqualifications[numcands][i][j]) {
44+
is_super_cw = false;
45+
} else {
46+
++copeland_counts[i];
47+
}
48+
}
49+
50+
if (is_super_cw) {
51+
found_super_condorcet = true;
52+
super_cw_idx = i;
53+
}
54+
}
55+
56+
ordering output;
57+
58+
for (size_t cand = 0; cand < numcands; ++cand) {
59+
if (!hopefuls[cand]) {
60+
continue;
61+
}
62+
63+
if (found_super_condorcet && super_cw_idx == cand) {
64+
output.insert(candscore(cand, 1));
65+
} else {
66+
output.insert(candscore(cand, 0));
67+
}
68+
}
69+
70+
return std::pair<ordering, bool>(output, false);
71+
}

src/singlewinner/sets/scw.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Francois Durand's "Super Condorcet winner": the candidate
2+
// (if any) who, in resistant set terms, disqualifies everybody
3+
// else directly.
4+
5+
// I could build on this if necessary.
6+
7+
// Hold on... can this even work? Suppose A~>B, A~>C. Couldn't B>A
8+
// voters possibly break A~>C? Say they bury C: BAC -> BCA. This
9+
// breaks A~>C and now A is no longer the Super CW...
10+
11+
#pragma once
12+
13+
#include "../method.h"
14+
15+
class super_condorcet_set : public election_method {
16+
public:
17+
std::pair<ordering, bool> elect_inner(
18+
const election_t & papers,
19+
const std::vector<bool> & hopefuls,
20+
int num_candidates, cache_map * cache,
21+
bool winner_only) const;
22+
23+
std::string name() const {
24+
return "Super Condorcet";
25+
}
26+
};

0 commit comments

Comments
 (0)