Equalshares

A Ruby implementation of the equalshares.net compute tool for participatory budgeting. It parses pabulib .pb files and computes winning projects using the Method of Equal Shares and related rules.

This started as a faithful port of the vanilla-JavaScript equalshares-compute-tool (parser + Method of Equal Shares) and was then extended for parity with pabutools, the academic reference implementation. Every rule and satisfaction measure is cross-checked against pabutools (see Tests).

Highlights:

  • Rules: Method of Equal Shares (mes), Phragmén's sequential rule (phragmen), greedy utilitarian welfare (greedy), maximin support (maximin).
  • Ballots: approval, cardinal (scoring / cumulative), and ordinal (via Borda).
  • Satisfaction measures: cost (the equalshares.net default), cardinality, effort.
  • Exact or fast: exact rational arithmetic (fractions) or floating point (floats).
  • No runtime dependencies; the maximin rule is solved with a pure-Ruby max-flow instead of an LP solver.

Installation

Install from git (or build the gem locally):

gem install equalshares

or add to a Gemfile:

gem "equalshares"

Command line

# Compute winners with exact arithmetic
equalshares path/to/instance.pb --completion add1 --accuracy fractions

# Choose the rule and satisfaction measure
equalshares instance.pb --rule phragmen
equalshares instance.pb --rule greedy --satisfaction cardinality
equalshares instance.pb --rule maximin

# Output formats and tie-breaking
equalshares instance.pb --format csv
equalshares instance.pb --format json
equalshares instance.pb --tie-breaking maxVotes,minCost --comparison satisfaction --progress

Options: --rule (mes/phragmen/greedy/maximin), --completion (none/utilitarian/add1/add1u/…), --accuracy (floats/fractions), --satisfaction (cost/cardinality/effort), --tie-breaking (comma-separated maxVotes,minCost,maxCost), --add1-options (exhaustive,integral), --comparison (none/satisfaction/exclusionRatio), --increment N, --format (human/csv/json), --progress.

Library

require "equalshares"

instance = Equalshares::Pabulib.parse_file("instance.pb")
params   = Equalshares::Params.new(completion: "add1u", accuracy: "fractions")

result = Equalshares::Compute.equal_shares(instance, params)
result[:winners]        # => ["24", "41", ...] winning project IDs
result[:notes][:stats]  # => total_cost, avg_approved_projects, utility_distribution, ...

# Other rules
Equalshares::Phragmen.sequential(instance, params)
Equalshares::Greedy.utilitarian_welfare(instance, Equalshares::Params.new(satisfaction: "cardinality"))
Equalshares::Maximin.support(instance)

# Serialise back to .pb
Equalshares::Pabulib.write_file(instance, "out.pb")

Satisfaction measures

By default MES uses cost satisfaction (the equalshares.net rule). cardinality (each funded approved project counts as 1) and effort (cost divided by approver count) are also supported and match pabutools' Cost_Sat, Cardinality_Sat and Effort_Sat.

Ballot types

scoring / cumulative instances carry per-voter scores (a points column); ordinal instances carry rankings, converted to per-voter Borda scores (ballot length − rank − 1). In all cases instance.cardinal? is true and the utilities feed the general MES (Equalshares::MesGeneral), verified against pabutools' Additive_Cardinal_Sat and Additive_Borda_Sat.

Tie-breaking

params.tie_breaking is a priority list of: the criteria "maxVotes", "minCost", "maxCost"; a total order { lexico: [ids...] } that ranks tied projects by their position in the list (matches pabutools' lexicographic tie-breaking — the recommended form); or a bare Array, which reproduces the equalshares.net tool's explicit-list behaviour but does not respect the list ordering.

Tests

bundle install
bundle exec rake test

The suite cross-checks the implementation against the original JavaScript tool and against pabutools. The pabutools reference fixtures under test/fixtures/ are committed, so the tests run without pabutools installed (the pabutools cross-checks skip if their reference JSON is absent). To regenerate a reference, install pabutools (pip install pabutools) and run the corresponding test/fixtures/generate_*.py script.

License

MIT. The Method of Equal Shares algorithm and pabulib parser are ports of the MIT-licensed equalshares-compute-tool by Dominik Peters. See LICENSE.txt.