Source: compute/voteCasters/plurality/castPluralityIntervals1D.js

/** @module */

import { normCDF } from '@paretoman/votekit-utilities'
import * as types from '@paretoman/votekit-types'
/**
 * Sum area under voter distributions to tally the votes.
 * @returns {types.typesVotesForGeom.votesForGeomPlurality}
 */
export default function castPluralityIntervals1D(voterGeom, geometry) {
    const { canPoints, canBorders } = geometry
    const intervals = canBorders.voronoiIntervals1D

    const sum = (voterGeom.densityProfile === 'gaussian') ? sumGaussian : sumBlock

    // return sum for each candidate
    const n = canPoints.length
    const countByCan = Array(n)
    let totalVotes = 0
    for (let i = 0; i < n; i++) {
        const voteCount = sum(voterGeom, intervals[i])
        countByCan[i] = voteCount
        totalVotes += voteCount
    }
    return { countByCan, totalVotes }
}

export function sumBlock(voterGeom, interval) {
    const { lower, upper } = interval
    const { x, w, densityMax } = voterGeom
    const r = 0.5 * w
    const lower2 = x - r
    const upper2 = x + r
    const lower3 = Math.max(lower, lower2)
    const upper3 = Math.min(upper, upper2)
    const sum = Math.max(0, upper3 - lower3) * densityMax
    return sum
}

export function sumGaussian(voterGeom, interval) {
    const { lower, upper } = interval
    const { x, w, densityMax } = voterGeom
    const center = x
    const sigma = w / Math.sqrt(2 * Math.PI) // w = sigma * sqrt(2*pi)
    // evaluate integral of gaussian on interval
    const sum = w * (normCDF(upper, center, sigma) - normCDF(lower, center, sigma)) * densityMax

    return sum
}