Skip to content
Snippets Groups Projects
Commit 7f5a766e authored by Emmanuel Raviart's avatar Emmanuel Raviart
Browse files

WIP Migrate to calculation.svelte

parent 58f99566
Branches
Tags
1 merge request!273Passage à Svelte 5
import type { Evaluation } from "$lib/decompositions"
import type { ParametricReform } from "$lib/reforms"
import type { VariableValueByCalculationName } from "$lib/variables"
import { entityByKey } from "./entities"
import type { SituationWithAxes } from "./situations"
export type CalculationName = "amendment" | "bill" | "law" | "revaluation"
export const calculationNames: CalculationName[] = [
"law",
"revaluation",
"bill",
"amendment",
]
export interface RequestedCalculations {
budgetCalculationNames?: Set<CalculationName>
budgetVariableName?: string
situationIndexByCalculationName: RequestedSituationIndexByCalculationName
}
export type RequestedSituationIndexByCalculationName = Partial<{
[calculationName in CalculationName]: number | null // `null` means "every test cases"
}>
export let requestedCalculations = $state({
situationIndexByCalculationName: {},
}) as RequestedCalculations
function calculateTestCases({}: {
situationIndexByCalculationName: RequestedSituationIndexByCalculationName
}) {
const aggregatedSituation: SituationWithAxes = {}
const axesData: { situationIndex: number; variables: string[] } =
$axes.reduce(
(
result: { situationIndex?: number; variables: string[] },
parallelAxes,
) => {
for (const axis of parallelAxes) {
result.situationIndex = axis.situationIndex
if (result.variables.includes(axis.name)) {
continue
}
result.variables.push(axis.name)
}
return result
},
{ variables: [] },
)
const entities = Object.values(entityByKey)
if (
Object.values(situationIndexByCalculationName).some(
(situationIndex) => situationIndex === null,
)
) {
let personIndex = -1
// Some of the calculations are requested to be done for every situations.
// Aggregate every situations into a single one without calculated variables.
for (const [situationIndex, situation] of $testCases.entries()) {
const inputInstantsByVariableName =
$inputInstantsByVariableNameArray[situationIndex]
const situationPrefix = `Cas type n°${situationIndex + 1} | `
for (const entity of entities) {
let entitySituation = situation[entity.key_plural as string]
if (entitySituation === undefined) {
continue
}
let aggregatedEntitySituation =
aggregatedSituation[entity.key_plural as string]
if (aggregatedEntitySituation === undefined) {
aggregatedEntitySituation = aggregatedSituation[
entity.key_plural as string
] = {}
}
const reservedKeys = getPopulationReservedKeys(entity)
for (const [populationId, population] of Object.entries(
entitySituation,
).sort(([populationId1], [populationId2]) =>
populationId1.localeCompare(populationId2),
)) {
const transformedPopulation: PopulationWithoutId = {}
if (!entity.is_person) {
for (const role of (entity as GroupEntity).roles) {
const personsIdKey = getRolePersonsIdKey(role)
const personsId = population[personsIdKey] as string[] | undefined
if (personsId === undefined) {
continue
}
transformedPopulation[personsIdKey] = personsId.map(
(personId) => situationPrefix + personId,
)
}
} else {
personIndex++
}
for (const [variableName, variableValueByInstant] of Object.entries(
population,
)) {
if (
reservedKeys.has(variableName) ||
(entity.is_person &&
axesData.situationIndex === personIndex &&
axesData.variables.includes(variableName))
) {
continue
}
const inputVariableValueByInstant: {
[instant: string]: VariableValue | null
} = {}
const inputInstants =
inputInstantsByVariableName[variableName] ?? new Set<string>()
for (const [instant, variableValue] of Object.entries(
variableValueByInstant as {
[instant: string]: VariableValue | null
},
)) {
if (!inputInstants.has(instant)) {
// Ignore calculated value.
continue
}
inputVariableValueByInstant[instant] = variableValue
}
if (Object.keys(inputVariableValueByInstant).length > 0) {
transformedPopulation[variableName] = inputVariableValueByInstant
}
}
aggregatedEntitySituation[situationPrefix + populationId] =
transformedPopulation
}
}
}
if ($axes.length > 0) {
aggregatedSituation.axes = $axes
}
}
const message = {
period: $year.toString(),
}
const newCalculationByName: CalculationByName = {}
const lawSituationIndex = situationIndexByCalculationName.law
if (lawSituationIndex !== undefined) {
const calculation: Calculation = (newCalculationByName.law = {
running: true,
})
let situation: SituationWithAxes
if (lawSituationIndex === null) {
situation = aggregatedSituation
} else {
calculation.situationIndex = lawSituationIndex
situation = cleanSituation($testCases[lawSituationIndex], $axes)
}
calculation.input = {
...message,
situation,
variables: [
...summaryCalculatedVariablesName,
...otherCalculatedVariablesName,
...nonVirtualVariablesName,
],
}
sendTestCasesSimulation("law", calculation.input) // Don't wait for result.
}
const revaluationSituationIndex = situationIndexByCalculationName.revaluation
if (
revaluationSituationIndex !== undefined &&
$revaluationName !== undefined
) {
const calculation: Calculation = (newCalculationByName.revaluation = {
running: true,
})
let situation: SituationWithAxes
if (revaluationSituationIndex === null) {
situation = aggregatedSituation
} else {
calculation.situationIndex = revaluationSituationIndex
situation = cleanSituation($testCases[revaluationSituationIndex], $axes)
}
calculation.input = {
...message,
reform: $revaluationName,
situation,
variables: [
...summaryCalculatedVariablesName,
...otherCalculatedVariablesName,
...(nonVirtualVariablesNameByReformName[$revaluationName] ??
nonVirtualVariablesName),
],
}
sendTestCasesSimulation("revaluation", calculation.input) // Don't wait for result.
}
const billSituationIndex = situationIndexByCalculationName.bill
if (billSituationIndex !== undefined && $billActive) {
const calculation: Calculation = (newCalculationByName.bill = {
running: true,
})
let situation: SituationWithAxes
if (billSituationIndex === null) {
situation = aggregatedSituation
} else {
calculation.situationIndex = billSituationIndex
situation = cleanSituation($testCases[billSituationIndex], $axes)
}
calculation.input = {
...message,
reform: $billName,
situation,
variables: [
...summaryCalculatedVariablesName,
...otherCalculatedVariablesName,
...(nonVirtualVariablesNameByReformName[$billName] ??
nonVirtualVariablesName),
],
}
sendTestCasesSimulation("bill", calculation.input) // Don't wait for result.
}
const amendmentSituationIndex = situationIndexByCalculationName.amendment
if (amendmentSituationIndex !== undefined) {
if (Object.keys($parametricReform).length === 0) {
// Remove amendment evaluations from decompositions.
$evaluationByNameArray = $evaluationByNameArray.map(
(evaluationByName, situationIndex): EvaluationByName => {
const updatedEvaluationByName = Object.fromEntries(
Object.entries(evaluationByName).map(
([variableName, evaluation]) => {
const calculationEvaluationByName = {
...evaluation.calculationEvaluationByName,
}
delete calculationEvaluationByName["amendment"]
return [
variableName,
{ ...evaluation, calculationEvaluationByName },
]
},
),
)
return updateEvaluations(
$decompositionByName,
updatedEvaluationByName,
$testCases[situationIndex].slider?.vectorIndex ?? 0,
$vectorLength,
waterfalls,
)
},
)
// Remove amendment values.
$valuesByCalculationNameByVariableNameArray =
$valuesByCalculationNameByVariableNameArray.map(
(valuesByCalculationNameByVariableName) =>
Object.fromEntries(
Object.entries(valuesByCalculationNameByVariableName).map(
([variableName, valuesByCalculationName]) => {
const updatedValuesByCalculationName = {
...valuesByCalculationName,
}
delete updatedValuesByCalculationName["amendment"]
return [variableName, updatedValuesByCalculationName]
},
),
),
)
} else {
const calculation: Calculation = (newCalculationByName.amendment = {
running: true,
})
let situation: SituationWithAxes
if (amendmentSituationIndex === null) {
situation = aggregatedSituation
} else {
calculation.situationIndex = amendmentSituationIndex
situation = cleanSituation($testCases[amendmentSituationIndex], $axes)
}
calculation.input = {
...message,
parametric_reform: $parametricReform,
reform: $billName ?? $revaluationName, // Will be removed when $billName and $revaluationName are undefined.
situation,
variables: [
...summaryCalculatedVariablesName,
...otherCalculatedVariablesName,
...(nonVirtualVariablesNameByReformName[$billName as string] ??
nonVirtualVariablesNameByReformName[$revaluationName as string] ??
nonVirtualVariablesName),
],
}
sendTestCasesSimulation("amendment", calculation.input) // Don't wait for result.
}
}
$calculationByName = newCalculationByName
}
export function isNullVariableValueByCalculationName(
variableValueByCalculationName: VariableValueByCalculationName,
): boolean {
return Object.values(variableValueByCalculationName).every(
(variableValue) => variableValue === undefined || variableValue === 0,
)
}
export function requestAllBudgetCalculations(variableName: string): void {
if (
variableName !== requestedCalculations.budgetVariableName ||
requestedCalculations.budgetCalculationNames === undefined ||
requestedCalculations.budgetCalculationNames.size < calculationNames.length
) {
requestedCalculations.budgetCalculationNames = new Set(calculationNames)
requestedCalculations.budgetVariableName = variableName
}
}
export function requestAllTestCasesCalculations(
requestedSituationIndex: number | null,
): void {
if (
calculationNames.some((calculationName) => {
const situationIndex =
requestedCalculations.situationIndexByCalculationName[calculationName]
return (
situationIndex !== null && situationIndex !== requestedSituationIndex
)
})
) {
calculateTestCases(
Object.fromEntries(
calculationNames.map((calculationName) => {
const situationIndex =
requestedCalculations.situationIndexByCalculationName[
calculationName
]
return [
calculationName,
situationIndex === null ? null : requestedSituationIndex,
]
}),
),
)
}
}
export function requestBudgetCalculation(
requestedCalculations: RequestedCalculations,
variableName: string,
calculationName: CalculationName,
): RequestedCalculations {
const budgetCalculationNames =
variableName === requestedCalculations.budgetVariableName
? (requestedCalculations.budgetCalculationNames ??
new Set<CalculationName>())
: new Set<CalculationName>()
if (!budgetCalculationNames.has(calculationName)) {
requestedCalculations = {
...requestedCalculations,
budgetCalculationNames: budgetCalculationNames.add(calculationName),
budgetVariableName: variableName,
}
}
return requestedCalculations
}
export function requestTestCasesCalculation(
requestedCalculations: RequestedCalculations,
calculationName: CalculationName,
requestedSituationIndex: number | null,
): RequestedCalculations {
const situationIndex =
requestedCalculations.situationIndexByCalculationName[calculationName]
if (situationIndex !== null && situationIndex !== requestedSituationIndex) {
requestedCalculations = {
...requestedCalculations,
situationIndexByCalculationName: {
...requestedCalculations.situationIndexByCalculationName,
[calculationName]: requestedSituationIndex,
},
}
}
return requestedCalculations
}
export function variableValueByCalculationNameFromEvaluation(
evaluation: Evaluation | undefined | null,
revaluationName: string | undefined | null,
billName: string | undefined | null,
parametricReform: ParametricReform,
): VariableValueByCalculationName {
return {
amendment:
Object.keys(parametricReform).length === 0
? undefined
: Math.abs(
evaluation?.calculationEvaluationByName["amendment"]
?.deltaAtVectorIndex ?? 0,
),
bill:
billName == null
? undefined
: Math.abs(
evaluation?.calculationEvaluationByName["bill"]
?.deltaAtVectorIndex ?? 0,
),
law: Math.abs(
evaluation?.calculationEvaluationByName["law"]?.deltaAtVectorIndex ?? 0,
),
revaluation:
revaluationName == null
? undefined
: Math.abs(
evaluation?.calculationEvaluationByName["revaluation"]
?.deltaAtVectorIndex ?? 0,
),
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment