UNPKG

ecclesia

Version:

Framework for political and electoral simulations

72 lines 3.19 kB
import { range, sum } from "@gouvernathor/python"; import * as math from "@gouvernathor/python/math"; import { createRandomObj } from "../utils"; /** * Converts a normal distribution to an uniform distribution. * * (This function is on its own so that the code can be checked by stats people.) * * @param x generated from a normal distribution * @param mu mean value of the normal distribution * @param sigma standard deviation of the normal distribution * @returns a value following an uniform distribution between 0 and 1, * such that the higher the value of x, the higher the return value. */ function normalToUniform(x, mu, sigma) { return 0.5 * (1 + math.erf((x - mu) / (sigma * Math.SQRT2))); } /** * @param opinMax maximum possible opinion value * @param factors ponderation for each opinion's importance in the alignment * @returns an aligner function to turns the opinions array * into a one-dimensional alignment value. */ function getAligner(opinMax, factors) { const rang = range(-opinMax, opinMax + 1); // standard deviation of one opinion taken on its own const oneSigma = Math.sqrt(sum(rang.map(i => i ** 2)) / rang.length); // using Lyapunov's central limit theorem const sigma = math.hypot(...factors.map(f => f * oneSigma)); return (opinions) => { const scapro = sum(opinions.map((opinion, i) => opinion * factors[i])); return normalToUniform(scapro, 0, sigma); }; } /** * @returns factors such that the return value of the aligner function * is between 0 and 1, and is increasing with each separate opinion, * with opinions having a decreasing importance. */ function getDefaultAlignmentFactors(nOpinions) { return Array.from({ length: nOpinions }, (_, i) => 1 - i / nOpinions); } /** * This holds the parameters for the opinions arrays : their length, * their range of values, and how to align them to one dimension. * * It can be seen as a metaclass for the opinions arrays, except that * they are real arrays instead of a custom type, so this is a normal class. * * There should generally be only one instance of this class per system, * and all opinions arrays should share the same parameters - * at least the same length and value range - even for opinions of different kinds, * for instance parties, citizens, and bills. * In any case, disagreement should not pe supported between subclasses * of different nOpinions or opinMax values. * * Other than being a repository for the meta parameters, * this class provides : * - a balanced single-dimensional alignment for all opinions arrays * - a random generator for the opinions arrays */ export class OpinionsArrayManager { constructor({ nOpinions, opinMax, opinionAlignmentFactors = getDefaultAlignmentFactors(nOpinions) }) { this.nOpinions = nOpinions; this.opinMax = opinMax; this.opinionAlignmentFactors = opinionAlignmentFactors; this.aligner = getAligner(opinMax, opinionAlignmentFactors); this.generator = (randomParam) => createRandomObj(randomParam) .choices(range(-opinMax, opinMax + 1), { k: nOpinions }); } } //# sourceMappingURL=opinionsArray.js.map