ecclesia
Version:
Framework for political and electoral simulations
1 lines • 4.04 kB
Source Map (JSON)
{"version":3,"sources":["../src/election.ts","../src/utils.ts"],"sourcesContent":["import { Counter } from \"@gouvernathor/python/collections\";\nimport { type Collection } from \"@gouvernathor/python/collections/abc\";\nimport { type Ballots } from \"./election/ballots\";\nimport { type Voting } from \"./election/voting\";\nimport { type Attribution } from \"./election/attribution\";\nimport { createRandomObj, type RandomObjParam } from \"./utils\";\n\n/**\n * A function to go from a set of opinionated voters\n * to the elected representatives, the number of seats for each candidate.\n *\n * @param voters A pool of voters such as taken by the Voting functions.\n * @returns A multi-set (a Counter) of elected representatives as returned by an Attribution.\n */\nexport interface Election<Voter, Party> {\n (voters: Collection<Voter>, candidates: Collection<Party>): Counter<Party>;\n}\n\n\n/**\n * Implements the most basic elections : combining a voting method and an attribution method.\n */\nexport function standardElection<Voter, Party, B extends Ballots<Party>>(\n { votingMethod, attributionMethod }: {\n votingMethod: Voting<Voter, Party, B>,\n attributionMethod: Attribution<Party, B>,\n }\n): Election<Voter, Party> {\n return (pool: Collection<Voter>, candidates: Collection<Party>): Counter<Party> => {\n return attributionMethod(votingMethod(pool, candidates));\n };\n}\n\n/**\n * Implements a selection by lottery, directly among the population.\n * Adds the supplementary constraint that the voter type and the candidate type must be the same.\n *\n * The pool of candidates and the pool of citizens must be the same.\n * (Implementation detail : this is not enforced, and the pool of candidates is ignored.)\n * Returns elements from the pool picked without replacement,\n * so the pool must be at least nSeats in size.\n */\nexport function sortition<Citizen>(\n { nSeats, ...randomParam }: {\n nSeats: number,\n } & RandomObjParam\n): Election<Citizen, Citizen> {\n return (citizens: Collection<Citizen>): Counter<Citizen> => {\n const randomObj = createRandomObj(randomParam);\n return new Counter(randomObj.shuffled(citizens, nSeats));\n };\n}\n","import RNG from \"@gouvernathor/rng\";\n\nexport type RandomObjParam = {randomObj: RNG} | {randomSeed?: number|string};\n\nexport function createRandomObj(param?: RandomObjParam): RNG;\nexport function createRandomObj({ randomObj, randomSeed }:\n { randomObj?: RNG, randomSeed?: number | string } = {},\n): RNG {\n if (randomObj === undefined) {\n randomObj = new RNG(randomSeed);\n }\n return randomObj;\n}\n\n\n// https://stackoverflow.com/a/71700658\n\n/**\n * Mutable tuple of a single element type and a given length.\n *\n * Warning: due to limitations in TypeScript, when N is unknown/generic,\n * the typing system does not recognize that the type extends array.\n * Using methods such as map will require a (double) cast first to any then to T[].\n */\nexport type Tuple<\n T,\n N extends number,\n R extends T[] = [],\n> = R['length'] extends N ? R : Tuple<T, N, [T, ...R]>;\n\n/**\n * Immutable version of Tuple.\n *\n * Warning: due to limitations in TypeScript, when N is unknown/generic,\n * the typing system does not recognize that the type extends readonly array.\n * Using methods such as map will require a (double) cast first to any then to readonly T[].\n */\nexport type ReadonlyTuple<T, N extends number> = Readonly<Tuple<T, N>>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAwB;;;ACAxB,iBAAgB;AAKT,SAAS,gBAAgB,EAAE,WAAW,WAAW,IACA,CAAC,GAClD;AACH,MAAI,cAAc,QAAW;AACzB,gBAAY,IAAI,WAAAA,QAAI,UAAU;AAAA,EAClC;AACA,SAAO;AACX;;;ADUO,SAAS,iBACZ,EAAE,cAAc,kBAAkB,GAIZ;AACtB,SAAO,CAAC,MAAyB,eAAkD;AAC/E,WAAO,kBAAkB,aAAa,MAAM,UAAU,CAAC;AAAA,EAC3D;AACJ;AAWO,SAAS,UACZ,EAAE,QAAQ,GAAG,YAAY,GAGC;AAC1B,SAAO,CAAC,aAAoD;AACxD,UAAM,YAAY,gBAAgB,WAAW;AAC7C,WAAO,IAAI,2BAAQ,UAAU,SAAS,UAAU,MAAM,CAAC;AAAA,EAC3D;AACJ;","names":["RNG"]}