ecclesia
Version:
Framework for political and electoral simulations
84 lines (81 loc) • 3.79 kB
text/typescript
import { Collection } from '@gouvernathor/python/collections/abc';
import { RandomObjParam } from '../utils.cjs';
import { Ballots, Simple, Order, Scores } from './ballots.cjs';
import '@gouvernathor/rng';
import '@gouvernathor/python/collections';
interface DisagreementFunction<T, U> {
(t: T, u: U): number;
}
interface Voting<Voter, Party, B extends Ballots<Party>> {
(voters: Collection<Voter>, candidates: Collection<Party>): B;
}
/**
* Turns a voting method into one in which the candidates are shuffled randomly
* before being given to the actual voting method passed to this function.
*
* If a RNG instance is passed (through options), it will be used directly,
* without reseeding, at each call of the voting method.
*
* If a seed is passed, the random object is reseeded
* with the same seed at each call of the voting method,
* making the resulting function return the same values for the same parameters
* (assuming the passed base voting method does).
* If you want the generator to be seeded only once with a given seed, and reused afterwards,
* seed it yourself and pass it as a random object to this function.
*/
declare function toShuffledVote<Voter, Party, B extends Ballots<Party>>({ voting, ...rest }: {
voting: Voting<Voter, Party, B>;
} & RandomObjParam): Voting<Voter, Party, B>;
/**
* The most basic and widespread voting system : each voter casts one ballot for
* one of the available candidates, or (not implemented here) for none of them.
*/
declare function singleVote<Voter, Party>({ disagree }: {
disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Simple<Party>>;
/**
* Each voter ranks all, or (not implemented here) some, of the candidates.
*/
declare function orderingVote<Voter, Party>({ disagree }: {
disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Order<Party>>;
/**
* Each voter gives a note (or grade) to each candidate.
* The number of grades must be provided to the constructor.
*
* This one is not as straightforward as the two previous ones, even setting
* strategic voting aside.
* What is to be considered to be the range of grades to cover ?
* From nazis to angels, or from the worst present candidate to the best ?
* The answer lies only in the minds of the voters.
* The latter is more akin to OrderingVote, so I made the former the default,
* but it causes issues for lower grades so ApprovalVote uses the latter.
*
* In this implementation, each voter gives a grade to each party
* proportional to the raw disagreement. This may yield situations
* where every party is graded 0, especially with low ngrades values.
*/
declare function cardinalVote<Voter, Party>({ nGrades, disagree }: {
nGrades: number;
disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Scores<Party>>;
/**
* Alternative implementation of CardinalVote.
*/
declare function balancedCardinalVote<Voter, Party>({ nGrades, disagree }: {
nGrades: number;
disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Scores<Party>>;
/**
* Each voter approves or disapproves each of the candidates
*
* Technically a special case of grading vote where grades are 0 and 1,
* but it makes it open to additional attribution methods
* (proportional ones for example).
* That's why the format it returns is not the same as with the cardinal vote.
* If you want a scores-like attribution, use balancedCardinalVote({ nGrades: 2 }) instead.
*/
declare function approvalVote<Voter, Party>({ disagree }: {
disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Simple<Party>>;
export { type DisagreementFunction, type Voting, approvalVote, balancedCardinalVote, cardinalVote, orderingVote, singleVote, toShuffledVote };