import { Collection } from "@gouvernathor/python/collections/abc";
import { type RandomObjParam } from "../utils";
import { DisagreementFunction } from "./voting-to-ballot";
import { Order, Scores, Simple } from "./tally";
export type { DisagreementFunction };
export interface Voting<Voter, Party, Tally> {
    (voters: Collection<Voter>, candidates: Collection<Party>): Tally;
}
/**
 * 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.
 */
export declare function toShuffledVote<Voter, Party, Tally>({ voting, ...rest }: {
    voting: Voting<Voter, Party, Tally>;
} & RandomObjParam): Voting<Voter, Party, Tally>;
/**
 * 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.
 */
export 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.
 */
export 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.
 */
export declare function cardinalVote<Voter, Party>({ nGrades, disagree }: {
    nGrades: number;
    disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Scores<Party>>;
/**
 * Alternative implementation of CardinalVote.
 */
export 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.
 */
export declare function approvalVote<Voter, Party>({ disagree }: {
    disagree: DisagreementFunction<Voter, Party>;
}): Voting<Voter, Party, Simple<Party>>;
