ecclesia
Version:
Framework for political and electoral simulations
124 lines (121 loc) • 4.97 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/election/attribution/proportionalBase.ts
var proportionalBase_exports = {};
__export(proportionalBase_exports, {
boundedRankIndexMethod: () => boundedRankIndexMethod,
proportionalFromDivisorFunction: () => proportionalFromDivisorFunction,
proportionalFromRankIndexFunction: () => proportionalFromRankIndexFunction,
rankIndexFunctionFromDivisorFunction: () => rankIndexFunctionFromDivisorFunction,
stationaryDivisorFunction: () => stationaryDivisorFunction
});
module.exports = __toCommonJS(proportionalBase_exports);
var import_collections = require("@gouvernathor/python/collections");
// src/election/attribution/metrics.ts
function defaultMetric({ votes, seats }) {
const allVotes = votes.total;
const allSeats = seats.total;
let suum = 0;
for (const party of seats.keys()) {
const partyVotes = votes.get(party);
const partySeats = seats.get(party);
suum += Math.abs(allSeats * partyVotes / allVotes - partySeats);
}
return suum / seats.size;
}
// src/election/attribution/proportionalBase.ts
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 import_collections.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 import_collections.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)
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
boundedRankIndexMethod,
proportionalFromDivisorFunction,
proportionalFromRankIndexFunction,
rankIndexFunctionFromDivisorFunction,
stationaryDivisorFunction
});
//# sourceMappingURL=proportionalBase.cjs.map