Skip to content

Commit

Permalink
Add a bunch of old multiwinner methods, quick and dirty port.
Browse files Browse the repository at this point in the history
They're not particularly good (either slow or disappointing performance
or both), but one of the Webster methods may be interesting if I can
figure out how it works, because it's not *that* bad.
  • Loading branch information
kristomu committed Sep 2, 2024
1 parent 182d211 commit 32ab1f4
Show file tree
Hide file tree
Showing 20 changed files with 4,547 additions and 6 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ add_library(qe_multiwinner_methods
src/multiwinner/qrange_stv.cc
src/multiwinner/randballots.cc
src/multiwinner/range_stv.cc
src/multiwinner/rusty/aux/dsc.cc
src/multiwinner/shuntsstv.cc
src/multiwinner/stv.cc
src/stats/multiwinner/mwstats.cc)
Expand Down
45 changes: 39 additions & 6 deletions src/main/multiwinner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
#include "multiwinner/exhaustive/lpv.h"
#include "multiwinner/exhaustive/psi.h"

#include "multiwinner/rusty/fc_kemeny.h"
#include "multiwinner/rusty/mono_webst_640.h"
#include "multiwinner/rusty/mono_webst_c37.h"
#include "multiwinner/rusty/mono_webst_f03.h"
#include "multiwinner/rusty/mw_kemeny2_34e.h"
#include "multiwinner/rusty/mw_kemeny_db0.h"

#include "multiwinner/auction.h"
#include "multiwinner/compat_qbuck.h"
#include "multiwinner/dhwl.h"
Expand Down Expand Up @@ -653,6 +660,36 @@ std::vector<multiwinner_stats> get_multiwinner_methods() {
e_methods.push_back(multiwinner_stats(std::make_shared<log_penalty>(
log_penalty_eval(1000))));

// Test some rusty methods.

// Nope
/*e_methods.push_back(multiwinner_stats(
std::make_shared<fc_kemeny>(true)));
e_methods.push_back(multiwinner_stats(
std::make_shared<fc_kemeny>(false)));*/

// Nope! (Times out and proportionality < 0.)
/*e_methods.push_back(multiwinner_stats(
std::make_shared<mw_kemeny2_34e>()));*/

// Too slow, has worse proportionality than birational with
// about the same utility VSE.
/*e_methods.push_back(multiwinner_stats(
std::make_shared<mw_kemeny>()));*/

// Slow but okay performance. May be something to investigate further,
// later, since it's much better than my recent attempt at
// reimplementing Set Webster.

/*
e_methods.push_back(multiwinner_stats(
std::make_shared<mono_webster_640>(MM_INVERTED, false, false)));
e_methods.push_back(multiwinner_stats(
std::make_shared<mono_webster_640>(MM_PLUSHALF, false, false)));
e_methods.push_back(multiwinner_stats(
std::make_shared<mono_webster_c37>(false, MMC_PLUSONE, true, false)));
*/

// QPQ mass test
// Disabled for now because QPQ needs a more extensive rework.
/*
Expand All @@ -678,11 +715,7 @@ std::vector<multiwinner_stats> get_multiwinner_methods() {
}
e_methods.push_back(multiwinner_stats(new QPQ(rc, true)));
}
// QPQ hack
multiwinner_stats qpqmetam("Best of QPQ(Meta, multiround)"), qpqmetas(
"Best of QPQ(Meta, sequential)");*/
}*/

return e_methods;
}
Expand Down Expand Up @@ -861,4 +894,4 @@ int main(int argc, char * * argv) {
method_utility[e_methods[counter].get_name()].get()) << endl;
}
}
}
}
4 changes: 4 additions & 0 deletions src/multiwinner/rusty/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This contains code directly copied from earlier simulators. The code is so
complex that I'm not going to try to clean it up. It's just for testing, so
that I can see which methods perform well, if any, and then focus my attention
on recreating them.
196 changes: 196 additions & 0 deletions src/multiwinner/rusty/aux/assignment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#include <iostream>
#include <vector>
#include <glpk.h>
#include <assert.h>

#include "tools/tools.h"
#include "common/ballots.h"

#include "qballot.h"

using namespace std;

// Solve the forced clustering problem for a single instance.

// BLUESKY: Points system MIP solver.
// Also should check overdetermined case, where clusters > voters

class assignment {

private:
glp_smcp params;
glp_prob * lp;

double num_voters;
int num_ballots, num_clusters;

void initialize(double n, int u, int k, const
vector<q_ballot> & voters);

public:
assignment(double n, int u, int k, const vector<q_ballot> &
voters);

~assignment();

void set_constraint(int ballot_num, int cluster_num,
double value) const;

double calc_minimum() const;
int get_status() const;
bool success() const;

double get_unknown(int index) const;
};

// n: number of voters
// u: number of unique ballots
// k: number of clusters
void assignment::initialize(double n, int u, int k,
const vector<q_ballot> & voters) {
assert(n > 0);
assert(u <= n && u > 0);
assert(k > 0);

if (lp != NULL) {
glp_delete_prob(lp);
lp = NULL;
}

// Set parameters so we don't get a lot of messages
glp_init_smcp(&params);
params.msg_lev = GLP_MSG_OFF;

// Create problem.
lp = glp_create_prob();
assert(lp != NULL);
glp_set_prob_name(lp, "clustering");
glp_set_obj_dir(lp, GLP_MIN); // Minimum distance

// Rows = alias variables (p = x1 + x3.. 0 < p < 100)
// Columns = terms (x1...xn)
glp_add_rows(lp, u + k);

int counter = 0;

// Set power constraints: sum of allocated ballot weights
// must equal number of voters who voted this way.
// Might be more resistant to vote management if we do
// 0 <= a <= U_0 (? seems to have no effect)
string name;
vector<q_ballot>::const_iterator pos = voters.begin();
for (counter = 0; counter < u; ++counter) {
assert(pos != voters.end());
name = "pow_" + itos(counter);
glp_set_row_name(lp, counter + 1, name.c_str());
glp_set_row_bnds(lp, counter + 1, GLP_FX, pos->strength,
pos->strength);
++pos;
}

// Set proportionality constraints: each cluster must have
// just as many allocated to it, so that no cluster is favored.
double fair_share = n/(double)k;

for (counter = 0; counter < k; ++counter) {
name = "prop_" + itos(counter);
glp_set_row_name(lp, counter + u + 1, name.c_str());
glp_set_row_bnds(lp, counter + u + 1, GLP_FX, fair_share,
fair_share);
}

// Add columns (variables we want to find out)
glp_add_cols(lp, u * k);

// Set "must be >= 0" constraints
for (counter = 0; counter < u * k; ++counter) {
name = "x_" + itos(counter);
glp_set_col_name(lp, counter + 1, name.c_str());
glp_set_col_bnds(lp, counter + 1, GLP_LO, 0, 0);
}

// Row (constraint #) indices in ia, column indices (var #) in ja,
// multipliers (always 1) in ar.

//int ia[u*k], ja[u*k];
//double ar[u*k];

int ia[u*k*2], ja[u*k*2];
double ar[u*k*2];

// Now actually link the constraints to the right variables.
// First the ballot power constraints (includes a single row)...
int sec, lincount = 1, constraint_num = 1;

for (counter = 0; counter < u * k; counter += k) {
for (sec = counter; sec < counter + k; ++sec) {
ia[lincount] = constraint_num;
ja[lincount] = sec + 1;
ar[lincount] = 1; // no multiples!
++lincount;
}
++constraint_num;
}

// Then the proportionality constraints (includes a single column)...
for (counter = 0; counter < k; ++counter) {
for (sec = counter; sec < u * k; sec += k) {
ia[lincount] = constraint_num;
ja[lincount] = sec + 1;
ar[lincount] = 1;
++lincount;
}
++constraint_num;
}

glp_load_matrix(lp, lincount-1, ia, ja, ar);

// And we're all set to receive the distances.
return;
}

assignment::assignment(double n, int u, int k,
const vector<q_ballot> & voters) {

num_voters = n;
num_clusters = k;
num_ballots = u;
lp = NULL;

initialize(n, u, k, voters);
}

assignment::~assignment() {
if (lp != NULL) {
glp_delete_prob(lp);
}
}


void assignment::set_constraint(int ballot_num, int cluster_num,
double value) const {
assert(ballot_num < num_ballots);
assert(cluster_num < num_clusters);

glp_set_obj_coef(lp, (ballot_num * num_clusters) + cluster_num + 1,
value);
}

double assignment::calc_minimum() const {

glp_simplex(lp, &params);
return (glp_get_obj_val(lp));
}

int assignment::get_status() const {
return (glp_get_status(lp));
}

bool assignment::success() const {
return (get_status() == GLP_OPT);
}

double assignment::get_unknown(int index) const {

return (glp_get_col_prim(lp, index+1));
}
Loading

0 comments on commit 32ab1f4

Please sign in to comment.