From 49bb554f9e765788e0a8e57112f97b1d6563f970 Mon Sep 17 00:00:00 2001 From: Kristofer Munsterhjelm Date: Sat, 21 Sep 2024 19:25:14 +0200 Subject: [PATCH] Reorganize multiwinner directory structure; extract out PR measures. --- CMakeLists.txt | 38 +-- src/main/multiwinner.cc | 226 +----------------- src/main/multiwinner_spatial.cc | 60 ++--- src/multiwinner/methods/all.h | 18 ++ src/multiwinner/{ => methods}/auction.cc | 0 src/multiwinner/{ => methods}/auction.h | 0 .../{ => methods}/celect/README.md | 0 .../{ => methods}/celect/ballot_struct.cc | 0 .../{ => methods}/celect/ballot_struct.h | 0 .../{ => methods}/celect/cm_cfprm.cc | 0 .../{ => methods}/celect/cm_cfprm.h | 0 .../{ => methods}/celect/cm_cpo_stv.cc | 0 .../{ => methods}/celect/cm_cpo_stv.h | 0 .../{ => methods}/celect/comparison.h | 0 src/multiwinner/{ => methods}/compat_qbuck.cc | 0 src/multiwinner/{ => methods}/compat_qbuck.h | 0 src/multiwinner/{ => methods}/cpo_stv.h | 0 src/multiwinner/{ => methods}/dhwl.cc | 0 src/multiwinner/{ => methods}/dhwl.h | 0 src/multiwinner/{ => methods}/dhwl_mat.cc | 0 src/multiwinner/{ => methods}/dhwl_mat.h | 0 .../{ => methods}/exhaustive/birational.h | 0 .../{ => methods}/exhaustive/harmonic.h | 0 .../{ => methods}/exhaustive/isoelastic.h | 0 .../{ => methods}/exhaustive/lpv.h | 0 .../{ => methods}/exhaustive/method.h | 2 +- .../{ => methods}/exhaustive/optima.h | 0 .../{ => methods}/exhaustive/psi.h | 0 .../{ => methods}/exhaustive/quota_helper.h | 0 .../{ => methods}/exhaustive/scored_method.cc | 0 .../{ => methods}/exhaustive/scored_method.h | 0 .../exhaustive/set_webster_helper.h | 0 src/multiwinner/{ => methods}/meek_stv.cc | 0 src/multiwinner/{ => methods}/meek_stv.h | 0 src/multiwinner/{ => methods}/methods.cc | 0 src/multiwinner/{ => methods}/methods.h | 0 src/multiwinner/{ => methods}/prbucklin.cc | 0 src/multiwinner/{ => methods}/prbucklin.h | 0 src/multiwinner/{ => methods}/psc.cc | 0 src/multiwinner/{ => methods}/psc.h | 0 src/multiwinner/{ => methods}/qbuck.cc | 0 src/multiwinner/{ => methods}/qbuck.h | 0 src/multiwinner/{ => methods}/qpq.cc | 0 src/multiwinner/{ => methods}/qpq.h | 0 src/multiwinner/{ => methods}/qrange_stv.cc | 0 src/multiwinner/{ => methods}/qrange_stv.h | 0 src/multiwinner/{ => methods}/quotas.cc | 0 src/multiwinner/{ => methods}/quotas.h | 0 src/multiwinner/{ => methods}/randballots.cc | 0 src/multiwinner/{ => methods}/randballots.h | 0 src/multiwinner/{ => methods}/range_stv.cc | 0 src/multiwinner/{ => methods}/range_stv.h | 0 src/multiwinner/{ => methods}/rusty/README.md | 0 .../rusty/auxiliary/assignment.h | 0 .../rusty/auxiliary/assignment_double.h | 0 .../rusty/auxiliary/cassignment.h | 0 .../{ => methods}/rusty/auxiliary/dsc.cc | 0 .../{ => methods}/rusty/auxiliary/dsc.h | 0 .../rusty/auxiliary/greedy_cluster.h | 0 .../{ => methods}/rusty/auxiliary/qballot.h | 0 .../{ => methods}/rusty/choose_set.h | 0 .../{ => methods}/rusty/fc_kemeny.h | 2 +- .../{ => methods}/rusty/mono_webst_640.h | 2 +- .../{ => methods}/rusty/mono_webst_c37.h | 2 +- .../{ => methods}/rusty/mono_webst_f03.h | 2 +- .../{ => methods}/rusty/mw_kemeny2_34e.h | 2 +- .../{ => methods}/rusty/mw_kemeny_db0.h | 2 +- .../{ => methods}/rusty/set_functs.h | 4 +- .../{ => methods}/rusty/setwise/coalition.h | 0 src/multiwinner/{ => methods}/set_webster.h | 2 +- src/multiwinner/{ => methods}/shuntsstv.cc | 0 src/multiwinner/{ => methods}/shuntsstv.h | 0 src/multiwinner/{ => methods}/stv.cc | 0 src/multiwinner/{ => methods}/stv.h | 0 src/multiwinner/pr_measures/clustering.cc | 93 +++++++ src/multiwinner/pr_measures/clustering.h | 38 +++ src/multiwinner/pr_measures/measure.h | 18 ++ src/multiwinner/pr_measures/normal_fit.cc | 79 ++++++ src/multiwinner/pr_measures/normal_fit.h | 29 +++ src/stats/multiwinner/mwstats.h | 2 +- 80 files changed, 346 insertions(+), 275 deletions(-) create mode 100644 src/multiwinner/methods/all.h rename src/multiwinner/{ => methods}/auction.cc (100%) rename src/multiwinner/{ => methods}/auction.h (100%) rename src/multiwinner/{ => methods}/celect/README.md (100%) rename src/multiwinner/{ => methods}/celect/ballot_struct.cc (100%) rename src/multiwinner/{ => methods}/celect/ballot_struct.h (100%) rename src/multiwinner/{ => methods}/celect/cm_cfprm.cc (100%) rename src/multiwinner/{ => methods}/celect/cm_cfprm.h (100%) rename src/multiwinner/{ => methods}/celect/cm_cpo_stv.cc (100%) rename src/multiwinner/{ => methods}/celect/cm_cpo_stv.h (100%) rename src/multiwinner/{ => methods}/celect/comparison.h (100%) rename src/multiwinner/{ => methods}/compat_qbuck.cc (100%) rename src/multiwinner/{ => methods}/compat_qbuck.h (100%) rename src/multiwinner/{ => methods}/cpo_stv.h (100%) rename src/multiwinner/{ => methods}/dhwl.cc (100%) rename src/multiwinner/{ => methods}/dhwl.h (100%) rename src/multiwinner/{ => methods}/dhwl_mat.cc (100%) rename src/multiwinner/{ => methods}/dhwl_mat.h (100%) rename src/multiwinner/{ => methods}/exhaustive/birational.h (100%) rename src/multiwinner/{ => methods}/exhaustive/harmonic.h (100%) rename src/multiwinner/{ => methods}/exhaustive/isoelastic.h (100%) rename src/multiwinner/{ => methods}/exhaustive/lpv.h (100%) rename src/multiwinner/{ => methods}/exhaustive/method.h (98%) rename src/multiwinner/{ => methods}/exhaustive/optima.h (100%) rename src/multiwinner/{ => methods}/exhaustive/psi.h (100%) rename src/multiwinner/{ => methods}/exhaustive/quota_helper.h (100%) rename src/multiwinner/{ => methods}/exhaustive/scored_method.cc (100%) rename src/multiwinner/{ => methods}/exhaustive/scored_method.h (100%) rename src/multiwinner/{ => methods}/exhaustive/set_webster_helper.h (100%) rename src/multiwinner/{ => methods}/meek_stv.cc (100%) rename src/multiwinner/{ => methods}/meek_stv.h (100%) rename src/multiwinner/{ => methods}/methods.cc (100%) rename src/multiwinner/{ => methods}/methods.h (100%) rename src/multiwinner/{ => methods}/prbucklin.cc (100%) rename src/multiwinner/{ => methods}/prbucklin.h (100%) rename src/multiwinner/{ => methods}/psc.cc (100%) rename src/multiwinner/{ => methods}/psc.h (100%) rename src/multiwinner/{ => methods}/qbuck.cc (100%) rename src/multiwinner/{ => methods}/qbuck.h (100%) rename src/multiwinner/{ => methods}/qpq.cc (100%) rename src/multiwinner/{ => methods}/qpq.h (100%) rename src/multiwinner/{ => methods}/qrange_stv.cc (100%) rename src/multiwinner/{ => methods}/qrange_stv.h (100%) rename src/multiwinner/{ => methods}/quotas.cc (100%) rename src/multiwinner/{ => methods}/quotas.h (100%) rename src/multiwinner/{ => methods}/randballots.cc (100%) rename src/multiwinner/{ => methods}/randballots.h (100%) rename src/multiwinner/{ => methods}/range_stv.cc (100%) rename src/multiwinner/{ => methods}/range_stv.h (100%) rename src/multiwinner/{ => methods}/rusty/README.md (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/assignment.h (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/assignment_double.h (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/cassignment.h (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/dsc.cc (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/dsc.h (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/greedy_cluster.h (100%) rename src/multiwinner/{ => methods}/rusty/auxiliary/qballot.h (100%) rename src/multiwinner/{ => methods}/rusty/choose_set.h (100%) rename src/multiwinner/{ => methods}/rusty/fc_kemeny.h (99%) rename src/multiwinner/{ => methods}/rusty/mono_webst_640.h (99%) rename src/multiwinner/{ => methods}/rusty/mono_webst_c37.h (99%) rename src/multiwinner/{ => methods}/rusty/mono_webst_f03.h (99%) rename src/multiwinner/{ => methods}/rusty/mw_kemeny2_34e.h (99%) rename src/multiwinner/{ => methods}/rusty/mw_kemeny_db0.h (99%) rename src/multiwinner/{ => methods}/rusty/set_functs.h (98%) rename src/multiwinner/{ => methods}/rusty/setwise/coalition.h (100%) rename src/multiwinner/{ => methods}/set_webster.h (98%) rename src/multiwinner/{ => methods}/shuntsstv.cc (100%) rename src/multiwinner/{ => methods}/shuntsstv.h (100%) rename src/multiwinner/{ => methods}/stv.cc (100%) rename src/multiwinner/{ => methods}/stv.h (100%) create mode 100644 src/multiwinner/pr_measures/clustering.cc create mode 100644 src/multiwinner/pr_measures/clustering.h create mode 100644 src/multiwinner/pr_measures/measure.h create mode 100644 src/multiwinner/pr_measures/normal_fit.cc create mode 100644 src/multiwinner/pr_measures/normal_fit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e91ef0..f395217 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,25 +189,27 @@ add_library(qe_singlewinner_methods target_link_libraries(qe_singlewinner_methods ${GLPK_LIBRARIES}) add_library(qe_multiwinner_methods - src/multiwinner/auction.cc - src/multiwinner/exhaustive/scored_method.cc src/multiwinner/helper/errors.cc - src/multiwinner/compat_qbuck.cc - src/multiwinner/dhwl.cc - src/multiwinner/dhwl_mat.cc - src/multiwinner/meek_stv.cc - src/multiwinner/methods.cc - src/multiwinner/prbucklin.cc - src/multiwinner/psc.cc - src/multiwinner/quotas.cc - src/multiwinner/qbuck.cc - src/multiwinner/qpq.cc - src/multiwinner/qrange_stv.cc - src/multiwinner/randballots.cc - src/multiwinner/range_stv.cc - src/multiwinner/rusty/auxiliary/dsc.cc - src/multiwinner/shuntsstv.cc - src/multiwinner/stv.cc + src/multiwinner/methods/auction.cc + src/multiwinner/methods/exhaustive/scored_method.cc + src/multiwinner/methods/compat_qbuck.cc + src/multiwinner/methods/dhwl.cc + src/multiwinner/methods/dhwl_mat.cc + src/multiwinner/methods/meek_stv.cc + src/multiwinner/methods/methods.cc + src/multiwinner/methods/prbucklin.cc + src/multiwinner/methods/psc.cc + src/multiwinner/methods/quotas.cc + src/multiwinner/methods/qbuck.cc + src/multiwinner/methods/qpq.cc + src/multiwinner/methods/qrange_stv.cc + src/multiwinner/methods/randballots.cc + src/multiwinner/methods/range_stv.cc + src/multiwinner/methods/rusty/auxiliary/dsc.cc + src/multiwinner/methods/shuntsstv.cc + src/multiwinner/methods/stv.cc + src/multiwinner/pr_measures/clustering.cc + src/multiwinner/pr_measures/normal_fit.cc src/stats/multiwinner/convex_hull.cc src/stats/multiwinner/mwstats.cc) diff --git a/src/main/multiwinner.cc b/src/main/multiwinner.cc index 54de033..ba54e7e 100644 --- a/src/main/multiwinner.cc +++ b/src/main/multiwinner.cc @@ -1,226 +1,15 @@ // More multiwinner hacks/clustering tests. -#include "multiwinner/methods.h" -#include "multiwinner/qpq.h" - +#include "multiwinner/methods/all.h" #include "generator/spatial/all.h" + #include "random/random.h" #include "tools/tools.h" #include "multiwinner/helper/errors.h" -// TODO: Make error type parametric, or just inherit the function/ -// template it or something. - -class proportionality_measure { - public: - virtual void prepare(const positions_election & p_e) = 0; - virtual double get_error(const std::list & outcome) = 0; -}; - -// Clustering-based proportionality measure - -class cluster_proportionality : public proportionality_measure { - private: - size_t num_clusters; - std::vector > clusters; - std::vector cluster_for_candidate; - - // Fraction of voters covered by each cluster. - std::vector cluster_voter_proportions; - - // ... and fractions of winning candidates. - std::vector cluster_winner_proportions; - - size_t get_optimum_cluster(const std::vector & point, - const std::vector > & centers) const; - - public: - void set_num_clusters(size_t num_clusters_in) { - num_clusters = num_clusters_in; - clusters.resize(num_clusters); - cluster_voter_proportions.resize(num_clusters); - cluster_winner_proportions.resize(num_clusters); - - } - cluster_proportionality(size_t num_clusters_in) { - set_num_clusters(num_clusters_in); - } - - void prepare(const positions_election & p_e); - double get_error(const std::list & outcome); -}; - -size_t cluster_proportionality::get_optimum_cluster( - const std::vector & point, - const std::vector > & centers) const { - - size_t record_cluster = 0; - double record_distance = -1; - bool set_record = false; - - for (size_t cluster_idx = 0; cluster_idx < centers.size(); - ++cluster_idx) { - - double current_distance = lp_distance(2, point, - centers[cluster_idx]); - - if (!set_record || current_distance < record_distance) { - set_record = true; - record_cluster = cluster_idx; - record_distance = current_distance; - } - } - - return record_cluster; -} - -void cluster_proportionality::prepare(const positions_election & p_e) { - - size_t num_voters = p_e.voters_pos.size(), - num_candidates = p_e.candidates_pos.size(); - - // Pick the k first voter coordinates as the cluster centers. - if (num_voters < num_clusters) { - throw std::invalid_argument("Clustering proportionality:" - " too few voters - need to be more than the number of clusters."); - } - - clusters = std::vector >( - p_e.voters_pos.begin(), p_e.voters_pos.begin()+num_clusters); - - std::fill(cluster_voter_proportions.begin(), - cluster_voter_proportions.end(), 0); - - for (size_t voter = 0; voter < num_voters; ++voter) { - size_t opt = get_optimum_cluster( - p_e.voters_pos[voter], clusters); - cluster_voter_proportions[opt] += 1.0/num_voters; - } - - cluster_for_candidate = std::vector(num_candidates, 0); - - for (size_t cand = 0; cand < num_candidates; ++cand) { - cluster_for_candidate[cand] = get_optimum_cluster( - p_e.candidates_pos[cand], clusters); - } -} - -double cluster_proportionality::get_error( - const std::list & outcome) { - - size_t num_seats = outcome.size(); - - std::fill(cluster_winner_proportions.begin(), - cluster_winner_proportions.end(), 0); - - for (size_t winner: outcome) { - cluster_winner_proportions[cluster_for_candidate[winner]]++; - } - - for (double & cluster_prop: cluster_winner_proportions) { - cluster_prop /= (double)num_seats; - } - - return sli(cluster_winner_proportions, - cluster_voter_proportions); -} - -// Check the error between a normal distribution fitted to the winners -// and the normal reference distribution. - -class normal_proportionality : public proportionality_measure { - private: - gaussian_generator reference; - std::vector > candidate_positions; - rng rnd; - - public: - // TODO, use a different seed - normal_proportionality(gaussian_generator ref_in) : rnd(1) { - reference = ref_in; - } - - void prepare(const positions_election & p_e); - double get_error(const std::list & outcome); -}; - -void normal_proportionality::prepare(const positions_election & p_e) { - candidate_positions = p_e.candidates_pos; -} - -double normal_proportionality::get_error( - const std::list & outcome) { - - size_t num_seats = outcome.size(); - - // Standard deviation is undefined if we have only one winner. - if (num_seats < 2) { - throw std::invalid_argument("normal_proportionality: " - "Need at least two winners"); - } - - size_t dim, dims = reference.get_num_dimensions(); - - std::vector mu_estimate(dims, 0), sigma_estimate(dims, 0); - - // Get means first. - for (size_t winner: outcome) { - for (dim = 0; dim < dims; ++dim) { - mu_estimate[dim] += candidate_positions[winner][dim]; - } - for (dim = 0; dim < dims; ++dim) { - mu_estimate[dim] /= (double)num_seats; - } - } - - // Get standard deviations. - for (size_t winner: outcome) { - for (dim = 0; dim < dims; ++dim) { - sigma_estimate[dim] += square( - candidate_positions[winner][dim] - mu_estimate[dim]); - } - for (dim = 0; dim < dims; ++dim) { - // Setting this to 1 makes it large-biased, because a bunch of - // candidates clustered around the center gives a more accurate mean - // than if they're dispersed. - sigma_estimate[dim] = sqrt(sigma_estimate[dim] / (double)num_seats); - } - } - - /*std::cout << "mu: "; - std::copy(mu_estimate.begin(), mu_estimate.end(), std::ostream_iterator(std::cout, " ")); - std::cout << "\n"; - std::cout << "sigma: "; - std::copy(sigma_estimate.begin(), sigma_estimate.end(), - std::ostream_iterator(std::cout, " ")); - std::cout << std::endl;*/ - - gaussian_generator estimated; - estimated.set_params(dims, false); - estimated.set_center(mu_estimate); - estimated.set_dispersion(sigma_estimate); - - // Pick random points from the reference distribution and - // get the pdf from both. Use Sainte-Laguë index-like measure. - - // TODO: KL divergence? Closed form integral instead of this - // slow Monte Carlo stuff? - - size_t iters = 500; - double error_sum = 0; - - for (size_t i = 0; i < iters; ++i) { - std::vector q = reference.rnd_vector(dims, rnd); - - double observed = estimated.pdf(q), - expected = reference.pdf(q); - - error_sum += square(observed-expected)/expected; - } - - return error_sum / (double)iters; -} +#include "multiwinner/pr_measures/clustering.h" +#include "multiwinner/pr_measures/normal_fit.h" // normsum, etc. @@ -236,6 +25,8 @@ int main() { size_t num_clusters = 2; // say + size_t maxiters = 5000; + std::cout << gauss.pdf(std::vector(5, 0.1)) << "\n"; cluster_proportionality test(num_clusters); @@ -244,7 +35,9 @@ int main() { for (double delta = 0.1; delta <= 1; delta += 0.1) { double error = 0; - for (int i = 0; i < 5000; ++i) { + for (int i = 0; i < maxiters; ++i) { + + std::cerr << i << "/" << maxiters << " \r" << std::flush; positions_election p_e = gauss.generate_election_result( num_voters, num_candidates, false, rnd); @@ -260,6 +53,7 @@ int main() { error += ntest.get_error(qpq_council); } + std::cerr << "\n"; std::cout << delta << "\t" << error << std::endl; } } \ No newline at end of file diff --git a/src/main/multiwinner_spatial.cc b/src/main/multiwinner_spatial.cc index 098603a..9fbcf75 100644 --- a/src/main/multiwinner_spatial.cc +++ b/src/main/multiwinner_spatial.cc @@ -19,36 +19,36 @@ #include "multiwinner/helper/errors.cc" -#include "multiwinner/methods.h" -#include "multiwinner/exhaustive/birational.h" -#include "multiwinner/exhaustive/harmonic.h" -#include "multiwinner/exhaustive/isoelastic.h" -#include "multiwinner/exhaustive/lpv.h" -#include "multiwinner/exhaustive/psi.h" -#include "multiwinner/exhaustive/quota_helper.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" -#include "multiwinner/meek_stv.h" -#include "multiwinner/prbucklin.h" -#include "multiwinner/psc.h" -#include "multiwinner/qbuck.h" -#include "multiwinner/set_webster.h" -#include "multiwinner/shuntsstv.h" -#include "multiwinner/stv.h" - -#include "multiwinner/randballots.h" -#include "multiwinner/qpq.h" -#include "multiwinner/qrange_stv.h" -#include "multiwinner/range_stv.h" +#include "multiwinner/methods/methods.h" +#include "multiwinner/methods/exhaustive/birational.h" +#include "multiwinner/methods/exhaustive/harmonic.h" +#include "multiwinner/methods/exhaustive/isoelastic.h" +#include "multiwinner/methods/exhaustive/lpv.h" +#include "multiwinner/methods/exhaustive/psi.h" +#include "multiwinner/methods/exhaustive/quota_helper.h" + +#include "multiwinner/methods/rusty/fc_kemeny.h" +#include "multiwinner/methods/rusty/mono_webst_640.h" +#include "multiwinner/methods/rusty/mono_webst_c37.h" +#include "multiwinner/methods/rusty/mono_webst_f03.h" +#include "multiwinner/methods/rusty/mw_kemeny2_34e.h" +#include "multiwinner/methods/rusty/mw_kemeny_db0.h" + +#include "multiwinner/methods/auction.h" +#include "multiwinner/methods/compat_qbuck.h" +#include "multiwinner/methods/dhwl.h" +#include "multiwinner/methods/meek_stv.h" +#include "multiwinner/methods/prbucklin.h" +#include "multiwinner/methods/psc.h" +#include "multiwinner/methods/qbuck.h" +#include "multiwinner/methods/set_webster.h" +#include "multiwinner/methods/shuntsstv.h" +#include "multiwinner/methods/stv.h" + +#include "multiwinner/methods/randballots.h" +#include "multiwinner/methods/qpq.h" +#include "multiwinner/methods/qrange_stv.h" +#include "multiwinner/methods/range_stv.h" #include "hack/msvc_random.h" diff --git a/src/multiwinner/methods/all.h b/src/multiwinner/methods/all.h new file mode 100644 index 0000000..ec38aa4 --- /dev/null +++ b/src/multiwinner/methods/all.h @@ -0,0 +1,18 @@ +#include "auction.h" +#include "compat_qbuck.h" +#include "cpo_stv.h" +#include "dhwl.h" +#include "dhwl_mat.h" +#include "meek_stv.h" +#include "methods.h" +#include "prbucklin.h" +#include "psc.h" +#include "qbuck.h" +#include "qpq.h" +#include "qrange_stv.h" +#include "quotas.h" +#include "randballots.h" +#include "range_stv.h" +#include "set_webster.h" +#include "shuntsstv.h" +#include "stv.h" \ No newline at end of file diff --git a/src/multiwinner/auction.cc b/src/multiwinner/methods/auction.cc similarity index 100% rename from src/multiwinner/auction.cc rename to src/multiwinner/methods/auction.cc diff --git a/src/multiwinner/auction.h b/src/multiwinner/methods/auction.h similarity index 100% rename from src/multiwinner/auction.h rename to src/multiwinner/methods/auction.h diff --git a/src/multiwinner/celect/README.md b/src/multiwinner/methods/celect/README.md similarity index 100% rename from src/multiwinner/celect/README.md rename to src/multiwinner/methods/celect/README.md diff --git a/src/multiwinner/celect/ballot_struct.cc b/src/multiwinner/methods/celect/ballot_struct.cc similarity index 100% rename from src/multiwinner/celect/ballot_struct.cc rename to src/multiwinner/methods/celect/ballot_struct.cc diff --git a/src/multiwinner/celect/ballot_struct.h b/src/multiwinner/methods/celect/ballot_struct.h similarity index 100% rename from src/multiwinner/celect/ballot_struct.h rename to src/multiwinner/methods/celect/ballot_struct.h diff --git a/src/multiwinner/celect/cm_cfprm.cc b/src/multiwinner/methods/celect/cm_cfprm.cc similarity index 100% rename from src/multiwinner/celect/cm_cfprm.cc rename to src/multiwinner/methods/celect/cm_cfprm.cc diff --git a/src/multiwinner/celect/cm_cfprm.h b/src/multiwinner/methods/celect/cm_cfprm.h similarity index 100% rename from src/multiwinner/celect/cm_cfprm.h rename to src/multiwinner/methods/celect/cm_cfprm.h diff --git a/src/multiwinner/celect/cm_cpo_stv.cc b/src/multiwinner/methods/celect/cm_cpo_stv.cc similarity index 100% rename from src/multiwinner/celect/cm_cpo_stv.cc rename to src/multiwinner/methods/celect/cm_cpo_stv.cc diff --git a/src/multiwinner/celect/cm_cpo_stv.h b/src/multiwinner/methods/celect/cm_cpo_stv.h similarity index 100% rename from src/multiwinner/celect/cm_cpo_stv.h rename to src/multiwinner/methods/celect/cm_cpo_stv.h diff --git a/src/multiwinner/celect/comparison.h b/src/multiwinner/methods/celect/comparison.h similarity index 100% rename from src/multiwinner/celect/comparison.h rename to src/multiwinner/methods/celect/comparison.h diff --git a/src/multiwinner/compat_qbuck.cc b/src/multiwinner/methods/compat_qbuck.cc similarity index 100% rename from src/multiwinner/compat_qbuck.cc rename to src/multiwinner/methods/compat_qbuck.cc diff --git a/src/multiwinner/compat_qbuck.h b/src/multiwinner/methods/compat_qbuck.h similarity index 100% rename from src/multiwinner/compat_qbuck.h rename to src/multiwinner/methods/compat_qbuck.h diff --git a/src/multiwinner/cpo_stv.h b/src/multiwinner/methods/cpo_stv.h similarity index 100% rename from src/multiwinner/cpo_stv.h rename to src/multiwinner/methods/cpo_stv.h diff --git a/src/multiwinner/dhwl.cc b/src/multiwinner/methods/dhwl.cc similarity index 100% rename from src/multiwinner/dhwl.cc rename to src/multiwinner/methods/dhwl.cc diff --git a/src/multiwinner/dhwl.h b/src/multiwinner/methods/dhwl.h similarity index 100% rename from src/multiwinner/dhwl.h rename to src/multiwinner/methods/dhwl.h diff --git a/src/multiwinner/dhwl_mat.cc b/src/multiwinner/methods/dhwl_mat.cc similarity index 100% rename from src/multiwinner/dhwl_mat.cc rename to src/multiwinner/methods/dhwl_mat.cc diff --git a/src/multiwinner/dhwl_mat.h b/src/multiwinner/methods/dhwl_mat.h similarity index 100% rename from src/multiwinner/dhwl_mat.h rename to src/multiwinner/methods/dhwl_mat.h diff --git a/src/multiwinner/exhaustive/birational.h b/src/multiwinner/methods/exhaustive/birational.h similarity index 100% rename from src/multiwinner/exhaustive/birational.h rename to src/multiwinner/methods/exhaustive/birational.h diff --git a/src/multiwinner/exhaustive/harmonic.h b/src/multiwinner/methods/exhaustive/harmonic.h similarity index 100% rename from src/multiwinner/exhaustive/harmonic.h rename to src/multiwinner/methods/exhaustive/harmonic.h diff --git a/src/multiwinner/exhaustive/isoelastic.h b/src/multiwinner/methods/exhaustive/isoelastic.h similarity index 100% rename from src/multiwinner/exhaustive/isoelastic.h rename to src/multiwinner/methods/exhaustive/isoelastic.h diff --git a/src/multiwinner/exhaustive/lpv.h b/src/multiwinner/methods/exhaustive/lpv.h similarity index 100% rename from src/multiwinner/exhaustive/lpv.h rename to src/multiwinner/methods/exhaustive/lpv.h diff --git a/src/multiwinner/exhaustive/method.h b/src/multiwinner/methods/exhaustive/method.h similarity index 98% rename from src/multiwinner/exhaustive/method.h rename to src/multiwinner/methods/exhaustive/method.h index ced02c8..ca6e056 100644 --- a/src/multiwinner/exhaustive/method.h +++ b/src/multiwinner/methods/exhaustive/method.h @@ -11,7 +11,7 @@ #include "lib/combinations/combinations.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "optima.h" namespace combo { diff --git a/src/multiwinner/exhaustive/optima.h b/src/multiwinner/methods/exhaustive/optima.h similarity index 100% rename from src/multiwinner/exhaustive/optima.h rename to src/multiwinner/methods/exhaustive/optima.h diff --git a/src/multiwinner/exhaustive/psi.h b/src/multiwinner/methods/exhaustive/psi.h similarity index 100% rename from src/multiwinner/exhaustive/psi.h rename to src/multiwinner/methods/exhaustive/psi.h diff --git a/src/multiwinner/exhaustive/quota_helper.h b/src/multiwinner/methods/exhaustive/quota_helper.h similarity index 100% rename from src/multiwinner/exhaustive/quota_helper.h rename to src/multiwinner/methods/exhaustive/quota_helper.h diff --git a/src/multiwinner/exhaustive/scored_method.cc b/src/multiwinner/methods/exhaustive/scored_method.cc similarity index 100% rename from src/multiwinner/exhaustive/scored_method.cc rename to src/multiwinner/methods/exhaustive/scored_method.cc diff --git a/src/multiwinner/exhaustive/scored_method.h b/src/multiwinner/methods/exhaustive/scored_method.h similarity index 100% rename from src/multiwinner/exhaustive/scored_method.h rename to src/multiwinner/methods/exhaustive/scored_method.h diff --git a/src/multiwinner/exhaustive/set_webster_helper.h b/src/multiwinner/methods/exhaustive/set_webster_helper.h similarity index 100% rename from src/multiwinner/exhaustive/set_webster_helper.h rename to src/multiwinner/methods/exhaustive/set_webster_helper.h diff --git a/src/multiwinner/meek_stv.cc b/src/multiwinner/methods/meek_stv.cc similarity index 100% rename from src/multiwinner/meek_stv.cc rename to src/multiwinner/methods/meek_stv.cc diff --git a/src/multiwinner/meek_stv.h b/src/multiwinner/methods/meek_stv.h similarity index 100% rename from src/multiwinner/meek_stv.h rename to src/multiwinner/methods/meek_stv.h diff --git a/src/multiwinner/methods.cc b/src/multiwinner/methods/methods.cc similarity index 100% rename from src/multiwinner/methods.cc rename to src/multiwinner/methods/methods.cc diff --git a/src/multiwinner/methods.h b/src/multiwinner/methods/methods.h similarity index 100% rename from src/multiwinner/methods.h rename to src/multiwinner/methods/methods.h diff --git a/src/multiwinner/prbucklin.cc b/src/multiwinner/methods/prbucklin.cc similarity index 100% rename from src/multiwinner/prbucklin.cc rename to src/multiwinner/methods/prbucklin.cc diff --git a/src/multiwinner/prbucklin.h b/src/multiwinner/methods/prbucklin.h similarity index 100% rename from src/multiwinner/prbucklin.h rename to src/multiwinner/methods/prbucklin.h diff --git a/src/multiwinner/psc.cc b/src/multiwinner/methods/psc.cc similarity index 100% rename from src/multiwinner/psc.cc rename to src/multiwinner/methods/psc.cc diff --git a/src/multiwinner/psc.h b/src/multiwinner/methods/psc.h similarity index 100% rename from src/multiwinner/psc.h rename to src/multiwinner/methods/psc.h diff --git a/src/multiwinner/qbuck.cc b/src/multiwinner/methods/qbuck.cc similarity index 100% rename from src/multiwinner/qbuck.cc rename to src/multiwinner/methods/qbuck.cc diff --git a/src/multiwinner/qbuck.h b/src/multiwinner/methods/qbuck.h similarity index 100% rename from src/multiwinner/qbuck.h rename to src/multiwinner/methods/qbuck.h diff --git a/src/multiwinner/qpq.cc b/src/multiwinner/methods/qpq.cc similarity index 100% rename from src/multiwinner/qpq.cc rename to src/multiwinner/methods/qpq.cc diff --git a/src/multiwinner/qpq.h b/src/multiwinner/methods/qpq.h similarity index 100% rename from src/multiwinner/qpq.h rename to src/multiwinner/methods/qpq.h diff --git a/src/multiwinner/qrange_stv.cc b/src/multiwinner/methods/qrange_stv.cc similarity index 100% rename from src/multiwinner/qrange_stv.cc rename to src/multiwinner/methods/qrange_stv.cc diff --git a/src/multiwinner/qrange_stv.h b/src/multiwinner/methods/qrange_stv.h similarity index 100% rename from src/multiwinner/qrange_stv.h rename to src/multiwinner/methods/qrange_stv.h diff --git a/src/multiwinner/quotas.cc b/src/multiwinner/methods/quotas.cc similarity index 100% rename from src/multiwinner/quotas.cc rename to src/multiwinner/methods/quotas.cc diff --git a/src/multiwinner/quotas.h b/src/multiwinner/methods/quotas.h similarity index 100% rename from src/multiwinner/quotas.h rename to src/multiwinner/methods/quotas.h diff --git a/src/multiwinner/randballots.cc b/src/multiwinner/methods/randballots.cc similarity index 100% rename from src/multiwinner/randballots.cc rename to src/multiwinner/methods/randballots.cc diff --git a/src/multiwinner/randballots.h b/src/multiwinner/methods/randballots.h similarity index 100% rename from src/multiwinner/randballots.h rename to src/multiwinner/methods/randballots.h diff --git a/src/multiwinner/range_stv.cc b/src/multiwinner/methods/range_stv.cc similarity index 100% rename from src/multiwinner/range_stv.cc rename to src/multiwinner/methods/range_stv.cc diff --git a/src/multiwinner/range_stv.h b/src/multiwinner/methods/range_stv.h similarity index 100% rename from src/multiwinner/range_stv.h rename to src/multiwinner/methods/range_stv.h diff --git a/src/multiwinner/rusty/README.md b/src/multiwinner/methods/rusty/README.md similarity index 100% rename from src/multiwinner/rusty/README.md rename to src/multiwinner/methods/rusty/README.md diff --git a/src/multiwinner/rusty/auxiliary/assignment.h b/src/multiwinner/methods/rusty/auxiliary/assignment.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/assignment.h rename to src/multiwinner/methods/rusty/auxiliary/assignment.h diff --git a/src/multiwinner/rusty/auxiliary/assignment_double.h b/src/multiwinner/methods/rusty/auxiliary/assignment_double.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/assignment_double.h rename to src/multiwinner/methods/rusty/auxiliary/assignment_double.h diff --git a/src/multiwinner/rusty/auxiliary/cassignment.h b/src/multiwinner/methods/rusty/auxiliary/cassignment.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/cassignment.h rename to src/multiwinner/methods/rusty/auxiliary/cassignment.h diff --git a/src/multiwinner/rusty/auxiliary/dsc.cc b/src/multiwinner/methods/rusty/auxiliary/dsc.cc similarity index 100% rename from src/multiwinner/rusty/auxiliary/dsc.cc rename to src/multiwinner/methods/rusty/auxiliary/dsc.cc diff --git a/src/multiwinner/rusty/auxiliary/dsc.h b/src/multiwinner/methods/rusty/auxiliary/dsc.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/dsc.h rename to src/multiwinner/methods/rusty/auxiliary/dsc.h diff --git a/src/multiwinner/rusty/auxiliary/greedy_cluster.h b/src/multiwinner/methods/rusty/auxiliary/greedy_cluster.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/greedy_cluster.h rename to src/multiwinner/methods/rusty/auxiliary/greedy_cluster.h diff --git a/src/multiwinner/rusty/auxiliary/qballot.h b/src/multiwinner/methods/rusty/auxiliary/qballot.h similarity index 100% rename from src/multiwinner/rusty/auxiliary/qballot.h rename to src/multiwinner/methods/rusty/auxiliary/qballot.h diff --git a/src/multiwinner/rusty/choose_set.h b/src/multiwinner/methods/rusty/choose_set.h similarity index 100% rename from src/multiwinner/rusty/choose_set.h rename to src/multiwinner/methods/rusty/choose_set.h diff --git a/src/multiwinner/rusty/fc_kemeny.h b/src/multiwinner/methods/rusty/fc_kemeny.h similarity index 99% rename from src/multiwinner/rusty/fc_kemeny.h rename to src/multiwinner/methods/rusty/fc_kemeny.h index af937fd..9013719 100644 --- a/src/multiwinner/rusty/fc_kemeny.h +++ b/src/multiwinner/methods/rusty/fc_kemeny.h @@ -12,7 +12,7 @@ #include "auxiliary/greedy_cluster.h" #include "auxiliary/assignment.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include "auxiliary/qballot.h" diff --git a/src/multiwinner/rusty/mono_webst_640.h b/src/multiwinner/methods/rusty/mono_webst_640.h similarity index 99% rename from src/multiwinner/rusty/mono_webst_640.h rename to src/multiwinner/methods/rusty/mono_webst_640.h index 045d7ac..a7c47f6 100644 --- a/src/multiwinner/rusty/mono_webst_640.h +++ b/src/multiwinner/methods/rusty/mono_webst_640.h @@ -13,7 +13,7 @@ #include #include "auxiliary/dsc.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include "setwise/coalition.h" #include "tools/tools.h" diff --git a/src/multiwinner/rusty/mono_webst_c37.h b/src/multiwinner/methods/rusty/mono_webst_c37.h similarity index 99% rename from src/multiwinner/rusty/mono_webst_c37.h rename to src/multiwinner/methods/rusty/mono_webst_c37.h index 412138a..a983554 100644 --- a/src/multiwinner/rusty/mono_webst_c37.h +++ b/src/multiwinner/methods/rusty/mono_webst_c37.h @@ -13,7 +13,7 @@ #include #include "auxiliary/dsc.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include "setwise/coalition.h" #include "tools/tools.h" diff --git a/src/multiwinner/rusty/mono_webst_f03.h b/src/multiwinner/methods/rusty/mono_webst_f03.h similarity index 99% rename from src/multiwinner/rusty/mono_webst_f03.h rename to src/multiwinner/methods/rusty/mono_webst_f03.h index f82b3ac..d0132fe 100644 --- a/src/multiwinner/rusty/mono_webst_f03.h +++ b/src/multiwinner/methods/rusty/mono_webst_f03.h @@ -13,7 +13,7 @@ #include #include "auxiliary/dsc.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include "setwise/coalition.h" #include "tools/tools.h" diff --git a/src/multiwinner/rusty/mw_kemeny2_34e.h b/src/multiwinner/methods/rusty/mw_kemeny2_34e.h similarity index 99% rename from src/multiwinner/rusty/mw_kemeny2_34e.h rename to src/multiwinner/methods/rusty/mw_kemeny2_34e.h index c576186..3da2629 100644 --- a/src/multiwinner/rusty/mw_kemeny2_34e.h +++ b/src/multiwinner/methods/rusty/mw_kemeny2_34e.h @@ -10,7 +10,7 @@ // Ranks are struct vectors of ints, easier that way. -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include diff --git a/src/multiwinner/rusty/mw_kemeny_db0.h b/src/multiwinner/methods/rusty/mw_kemeny_db0.h similarity index 99% rename from src/multiwinner/rusty/mw_kemeny_db0.h rename to src/multiwinner/methods/rusty/mw_kemeny_db0.h index b043ead..a47a298 100644 --- a/src/multiwinner/rusty/mw_kemeny_db0.h +++ b/src/multiwinner/methods/rusty/mw_kemeny_db0.h @@ -10,7 +10,7 @@ // Ranks are struct vectors of ints, easier that way. -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" #include "auxiliary/qballot.h" diff --git a/src/multiwinner/rusty/set_functs.h b/src/multiwinner/methods/rusty/set_functs.h similarity index 98% rename from src/multiwinner/rusty/set_functs.h rename to src/multiwinner/methods/rusty/set_functs.h index 54e51e0..5f35cad 100644 --- a/src/multiwinner/rusty/set_functs.h +++ b/src/multiwinner/methods/rusty/set_functs.h @@ -13,9 +13,9 @@ #include #include "auxiliary/dsc.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include "tools/ballot_tools.h" -#include "multiwinner/rusty/setwise/coalition.h" +#include "setwise/coalition.h" #include "tools/tools.h" using namespace std; diff --git a/src/multiwinner/rusty/setwise/coalition.h b/src/multiwinner/methods/rusty/setwise/coalition.h similarity index 100% rename from src/multiwinner/rusty/setwise/coalition.h rename to src/multiwinner/methods/rusty/setwise/coalition.h diff --git a/src/multiwinner/set_webster.h b/src/multiwinner/methods/set_webster.h similarity index 98% rename from src/multiwinner/set_webster.h rename to src/multiwinner/methods/set_webster.h index d012bce..e9ef0eb 100644 --- a/src/multiwinner/set_webster.h +++ b/src/multiwinner/methods/set_webster.h @@ -15,7 +15,7 @@ #include "coalitions/coalitions.h" -#include "multiwinner/exhaustive/set_webster_helper.h" +#include "exhaustive/set_webster_helper.h" class set_webster : public multiwinner_method { private: diff --git a/src/multiwinner/shuntsstv.cc b/src/multiwinner/methods/shuntsstv.cc similarity index 100% rename from src/multiwinner/shuntsstv.cc rename to src/multiwinner/methods/shuntsstv.cc diff --git a/src/multiwinner/shuntsstv.h b/src/multiwinner/methods/shuntsstv.h similarity index 100% rename from src/multiwinner/shuntsstv.h rename to src/multiwinner/methods/shuntsstv.h diff --git a/src/multiwinner/stv.cc b/src/multiwinner/methods/stv.cc similarity index 100% rename from src/multiwinner/stv.cc rename to src/multiwinner/methods/stv.cc diff --git a/src/multiwinner/stv.h b/src/multiwinner/methods/stv.h similarity index 100% rename from src/multiwinner/stv.h rename to src/multiwinner/methods/stv.h diff --git a/src/multiwinner/pr_measures/clustering.cc b/src/multiwinner/pr_measures/clustering.cc new file mode 100644 index 0000000..d498bdd --- /dev/null +++ b/src/multiwinner/pr_measures/clustering.cc @@ -0,0 +1,93 @@ +#include "clustering.h" + +#include "tools/tools.h" +#include "multiwinner/helper/errors.h" + +// Given a point and a number of cluster centers, determine what +// center is closest to the point. Ties are broken arbitrarily +// but consistently (in practice, first cluster wins). + +size_t cluster_proportionality::get_optimum_cluster( + const std::vector & point, + const std::vector > & centers) const { + + size_t record_cluster = 0; + double record_distance = -1; + bool set_record = false; + + for (size_t cluster_idx = 0; cluster_idx < centers.size(); + ++cluster_idx) { + + double current_distance = lp_distance(2, point, + centers[cluster_idx]); + + if (!set_record || current_distance < record_distance) { + set_record = true; + record_cluster = cluster_idx; + record_distance = current_distance; + } + } + + return record_cluster; +} + +// Choose cluster centers, then determine which cluster each candidate and voter +// belongs to. Use the voter-cluster assignments to determine the fraction of +// voters in each cluster, and the candidate-cluster assignments as a cache +// so that calculating the error is relatively fast. + +void cluster_proportionality::prepare(const positions_election & p_e) { + + size_t num_voters = p_e.voters_pos.size(), + num_candidates = p_e.candidates_pos.size(); + + // Pick the k first voter coordinates as the cluster centers. + if (num_voters < num_clusters) { + throw std::invalid_argument("Clustering proportionality:" + " too few voters - need to be more than the number of clusters."); + } + + clusters = std::vector >( + p_e.voters_pos.begin(), p_e.voters_pos.begin()+num_clusters); + + std::fill(cluster_voter_proportions.begin(), + cluster_voter_proportions.end(), 0); + + for (size_t voter = 0; voter < num_voters; ++voter) { + size_t opt = get_optimum_cluster( + p_e.voters_pos[voter], clusters); + cluster_voter_proportions[opt] += 1.0/num_voters; + } + + cluster_for_candidate = std::vector(num_candidates, 0); + + for (size_t cand = 0; cand < num_candidates; ++cand) { + cluster_for_candidate[cand] = get_optimum_cluster( + p_e.candidates_pos[cand], clusters); + } +} + +// Calculate the proportion of winners belonging to each cluster and then +// match this against the proportion of voters using the Sainte-Laguë index. +// TODO: Think of how to use different error measures: inheritance, +// composition or templating? + +double cluster_proportionality::get_error( + const std::list & outcome) { + + size_t num_seats = outcome.size(); + + std::fill(cluster_winner_proportions.begin(), + cluster_winner_proportions.end(), 0); + + for (size_t winner: outcome) { + cluster_winner_proportions[cluster_for_candidate[winner]]++; + } + + for (double & cluster_prop: cluster_winner_proportions) { + cluster_prop /= (double)num_seats; + } + + return sli(cluster_winner_proportions, + cluster_voter_proportions); +} diff --git a/src/multiwinner/pr_measures/clustering.h b/src/multiwinner/pr_measures/clustering.h new file mode 100644 index 0000000..fdbd38a --- /dev/null +++ b/src/multiwinner/pr_measures/clustering.h @@ -0,0 +1,38 @@ +#include + +#include "measure.h" + +// Clustering-based proportionality measure. This groups candidates and voters +// into clusters based on proximity, and then checks the proportion of winners +// in each cluster against the proportion of voters. + +class cluster_proportionality : public proportionality_measure { + private: + size_t num_clusters; + std::vector > clusters; + std::vector cluster_for_candidate; + + // Fraction of voters covered by each cluster. + std::vector cluster_voter_proportions; + + // ... and fractions of winning candidates. + std::vector cluster_winner_proportions; + + size_t get_optimum_cluster(const std::vector & point, + const std::vector > & centers) const; + + public: + void set_num_clusters(size_t num_clusters_in) { + num_clusters = num_clusters_in; + clusters.resize(num_clusters); + cluster_voter_proportions.resize(num_clusters); + cluster_winner_proportions.resize(num_clusters); + + } + cluster_proportionality(size_t num_clusters_in) { + set_num_clusters(num_clusters_in); + } + + void prepare(const positions_election & p_e); + double get_error(const std::list & outcome); +}; \ No newline at end of file diff --git a/src/multiwinner/pr_measures/measure.h b/src/multiwinner/pr_measures/measure.h new file mode 100644 index 0000000..f0d08b2 --- /dev/null +++ b/src/multiwinner/pr_measures/measure.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "generator/spatial/spatial.h" + +// This ABC defines a way to measure proportionality of winners. +// Classes that implement proportionality measures first gather some +// information on the candidates and voters based on a spatial model +// as implemented by a generator; that's the prepare method. Then it +// turns an outcome (a list of winners) into an error measure, where +// lower is better. + +class proportionality_measure { + public: + virtual void prepare(const positions_election & p_e) = 0; + virtual double get_error(const std::list & outcome) = 0; +}; \ No newline at end of file diff --git a/src/multiwinner/pr_measures/normal_fit.cc b/src/multiwinner/pr_measures/normal_fit.cc new file mode 100644 index 0000000..6bfaab3 --- /dev/null +++ b/src/multiwinner/pr_measures/normal_fit.cc @@ -0,0 +1,79 @@ +#include "normal_fit.h" +#include "multiwinner/helper/errors.h" + +void normal_proportionality::prepare(const positions_election & p_e) { + candidate_positions = p_e.candidates_pos; +} + +double normal_proportionality::get_error( + const std::list & outcome) { + + size_t num_seats = outcome.size(); + + // Standard deviation is undefined if we have only one winner. + if (num_seats < 2) { + throw std::invalid_argument("normal_proportionality: " + "Need at least two winners"); + } + + size_t dim, dims = reference.get_num_dimensions(); + + std::vector mu_estimate(dims, 0), sigma_estimate(dims, 0); + + // Get means first. + for (size_t winner: outcome) { + for (dim = 0; dim < dims; ++dim) { + mu_estimate[dim] += candidate_positions[winner][dim]; + } + for (dim = 0; dim < dims; ++dim) { + mu_estimate[dim] /= (double)num_seats; + } + } + + // Get standard deviations. + for (size_t winner: outcome) { + for (dim = 0; dim < dims; ++dim) { + sigma_estimate[dim] += square( + candidate_positions[winner][dim] - mu_estimate[dim]); + } + for (dim = 0; dim < dims; ++dim) { + // Setting this to 1 makes it large-biased, because a bunch of + // candidates clustered around the center gives a more accurate mean + // than if they're dispersed. + sigma_estimate[dim] = sqrt(sigma_estimate[dim] / (double)num_seats); + } + } + + /*std::cout << "mu: "; + std::copy(mu_estimate.begin(), mu_estimate.end(), std::ostream_iterator(std::cout, " ")); + std::cout << "\n"; + std::cout << "sigma: "; + std::copy(sigma_estimate.begin(), sigma_estimate.end(), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl;*/ + + gaussian_generator estimated; + estimated.set_params(dims, false); + estimated.set_center(mu_estimate); + estimated.set_dispersion(sigma_estimate); + + // Pick random points from the reference distribution and + // get the pdf from both. Use Sainte-Laguë index-like measure. + + // TODO: KL divergence? Closed form integral instead of this + // slow Monte Carlo stuff? + + size_t iters = 500; + double error_sum = 0; + + for (size_t i = 0; i < iters; ++i) { + std::vector q = reference.rnd_vector(dims, rnd); + + double observed = estimated.pdf(q), + expected = reference.pdf(q); + + error_sum += square(observed-expected)/expected; + } + + return error_sum / (double)iters; +} diff --git a/src/multiwinner/pr_measures/normal_fit.h b/src/multiwinner/pr_measures/normal_fit.h new file mode 100644 index 0000000..780c2d3 --- /dev/null +++ b/src/multiwinner/pr_measures/normal_fit.h @@ -0,0 +1,29 @@ +#include "generator/spatial/gaussian.h" +#include "random/random.h" +#include + +#include "measure.h" + +// Proportionality measure for normal spatial models. This tries to fit a +// normal distribution given the winners' coordinates as sampled points. + +// It then does Monte-Carlo integration to check the Sainte-Laguë measure +// between the fitted distribution and the actual distribution; a better +// fit indicates that the returned winners are representative of the +// distribution. + +class normal_proportionality : public proportionality_measure { + private: + gaussian_generator reference; + std::vector > candidate_positions; + rng rnd; + + public: + // TODO, use a different seed + normal_proportionality(gaussian_generator ref_in) : rnd(1) { + reference = ref_in; + } + + void prepare(const positions_election & p_e); + double get_error(const std::list & outcome); +}; \ No newline at end of file diff --git a/src/stats/multiwinner/mwstats.h b/src/stats/multiwinner/mwstats.h index 7ff48b3..55b5853 100644 --- a/src/stats/multiwinner/mwstats.h +++ b/src/stats/multiwinner/mwstats.h @@ -1,7 +1,7 @@ #pragma once #include "tools/tools.h" -#include "multiwinner/methods.h" +#include "multiwinner/methods/methods.h" #include