UNPKG

ecclesia

Version:

Framework for political and electoral simulations

85 lines (83 loc) 3.17 kB
import { defaultMetric } from "./chunk-UWP5NKUP.js"; // src/election/attribution/proportionalBase.ts import { Counter } from "@gouvernathor/python/collections"; function proportionalFromRankIndexFunction({ nSeats, rankIndexFunction }) { const attrib = (votes, rest = {}) => { const allVotes = votes.total; const fractions = new Map([...votes.entries()].map(([party, v]) => [party, v / allVotes])); const rankIndexValues = new Map([...fractions.entries()].map(([party, f]) => [party, rankIndexFunction(f, 0)])); const parties = [...votes.keys()].sort((a, b) => rankIndexValues.get(a) - rankIndexValues.get(b)); const seats = new Counter(); s: for (let sn = 0; sn < nSeats; sn++) { const winner = parties.pop(); seats.increment(winner); rankIndexValues.set(winner, rankIndexFunction(fractions.get(winner), seats.get(winner))); for (let pn = 0; pn < parties.length; pn++) { if (rankIndexValues.get(parties[pn]) >= rankIndexValues.get(winner)) { parties.splice(pn, 0, winner); continue s; } } parties.push(winner); } return seats; }; attrib.nSeats = nSeats; return attrib; } function boundedRankIndexMethod({ minNSeats, maxNSeats, rankIndexFunction, metric = defaultMetric }) { const attrib = (votes, rest = {}) => { const allVotes = votes.total; const fractions = new Map([...votes.entries()].map(([party, v]) => [party, v / allVotes])); const rankIndexValues = new Map([...fractions.entries()].map(([party, f]) => [party, rankIndexFunction(f, 0)])); const parties = [...votes.keys()].sort((a, b) => rankIndexValues.get(a) - rankIndexValues.get(b)); const seats = new Counter(); let bestSeats = seats.pos; let bestSeatsMetric = Infinity; s: for (let sn = 1; sn <= maxNSeats; sn++) { const winner = parties.pop(); seats.increment(winner); if (sn >= minNSeats) { const newMetric = metric({ votes, seats }); if (newMetric < bestSeatsMetric) { bestSeats = seats.pos; bestSeatsMetric = newMetric; } } rankIndexValues.set(winner, rankIndexFunction(fractions.get(winner), seats.get(winner))); for (let pn = 0; pn < parties.length; pn++) { if (rankIndexValues.get(parties[pn]) >= rankIndexValues.get(winner)) { parties.splice(pn, 0, winner); continue s; } } parties.push(winner); } return bestSeats; }; attrib.minNSeats = minNSeats; attrib.maxNSeats = maxNSeats; return attrib; } function stationaryDivisorFunction(r) { return (k) => k + r; } function rankIndexFunctionFromDivisorFunction(divisorFunction) { return (t, a) => t / divisorFunction(a); } function proportionalFromDivisorFunction({ nSeats, divisorFunction }) { return proportionalFromRankIndexFunction({ nSeats, rankIndexFunction: rankIndexFunctionFromDivisorFunction(divisorFunction) }); } export { proportionalFromRankIndexFunction, boundedRankIndexMethod, stationaryDivisorFunction, rankIndexFunctionFromDivisorFunction, proportionalFromDivisorFunction }; //# sourceMappingURL=chunk-PFWVE4EX.js.map