ecclesia
Version:
Framework for political and electoral simulations
72 lines • 3.19 kB
JavaScript
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