✨ Déplacement des Variations
parent
6b2d4b8dd3
commit
ab0b64da12
|
@ -1,9 +1,7 @@
|
|||
import { desugarScale } from 'Engine/mecanisms/barème'
|
||||
import { decompose, devariateExplanation } from 'Engine/mecanisms/utils'
|
||||
import { decompose } from 'Engine/mecanisms/utils'
|
||||
import {
|
||||
add,
|
||||
any,
|
||||
aperture,
|
||||
curry,
|
||||
equals,
|
||||
evolve,
|
||||
|
@ -12,9 +10,7 @@ import {
|
|||
head,
|
||||
is,
|
||||
isEmpty,
|
||||
isNil,
|
||||
keys,
|
||||
last,
|
||||
map,
|
||||
max,
|
||||
mergeWith,
|
||||
|
@ -23,11 +19,7 @@ import {
|
|||
pipe,
|
||||
pluck,
|
||||
prop,
|
||||
propEq,
|
||||
reduce,
|
||||
reduced,
|
||||
reject,
|
||||
sort,
|
||||
subtract,
|
||||
toPairs
|
||||
} from 'ramda'
|
||||
|
@ -48,100 +40,15 @@ import {
|
|||
rewriteNode
|
||||
} from './evaluation'
|
||||
import Allègement from './mecanismViews/Allègement'
|
||||
import Barème from './mecanismViews/Barème'
|
||||
import BarèmeContinu from './mecanismViews/BarèmeContinu'
|
||||
import { Node, SimpleRuleLink } from './mecanismViews/common'
|
||||
import InversionNumérique from './mecanismViews/InversionNumérique'
|
||||
import Product from './mecanismViews/Product'
|
||||
import Somme from './mecanismViews/Somme'
|
||||
import Variations from './mecanismViews/Variations'
|
||||
import { disambiguateRuleReference, findRuleByDottedName } from './rules'
|
||||
import { anyNull, val } from './traverse-common-functions'
|
||||
import uniroot from './uniroot'
|
||||
import { inferUnit } from 'Engine/units'
|
||||
|
||||
/* @devariate = true => This function will produce variations of a same mecanism (e.g. product) that share some common properties */
|
||||
export let mecanismVariations = (recurse, k, v, devariate) => {
|
||||
let explanation = devariate
|
||||
? devariateExplanation(recurse, k, v)
|
||||
: v.map(({ si, alors, sinon }) =>
|
||||
sinon !== undefined
|
||||
? { consequence: recurse(sinon), condition: undefined }
|
||||
: { consequence: recurse(alors), condition: recurse(si) }
|
||||
)
|
||||
|
||||
let evaluate = (cache, situationGate, parsedRules, node) => {
|
||||
let evaluateVariationProp = prop =>
|
||||
prop === undefined
|
||||
? undefined
|
||||
: evaluateNode(cache, situationGate, parsedRules, prop),
|
||||
// mark the satisfied variation if any in the explanation
|
||||
[, resolvedExplanation] = reduce(
|
||||
([resolved, result], variation) => {
|
||||
if (resolved) return [true, [...result, variation]]
|
||||
|
||||
// evaluate the condition
|
||||
let evaluatedCondition = evaluateVariationProp(variation.condition)
|
||||
|
||||
if (evaluatedCondition == undefined) {
|
||||
// We've reached the eventual defaut case
|
||||
let evaluatedVariation = {
|
||||
consequence: evaluateVariationProp(variation.consequence),
|
||||
satisfied: true
|
||||
}
|
||||
return [true, [...result, evaluatedVariation]]
|
||||
}
|
||||
|
||||
if (evaluatedCondition.nodeValue === null)
|
||||
// one case has missing variables => we can't go further
|
||||
return [true, [...result, { condition: evaluatedCondition }]]
|
||||
|
||||
if (evaluatedCondition.nodeValue === true) {
|
||||
let evaluatedVariation = {
|
||||
condition: evaluatedCondition,
|
||||
consequence: evaluateVariationProp(variation.consequence),
|
||||
satisfied: true
|
||||
}
|
||||
return [true, [...result, evaluatedVariation]]
|
||||
}
|
||||
return [false, [...result, variation]]
|
||||
},
|
||||
[false, []]
|
||||
)(node.explanation),
|
||||
satisfiedVariation = resolvedExplanation.find(v => v.satisfied),
|
||||
nodeValue = satisfiedVariation
|
||||
? satisfiedVariation.consequence.nodeValue
|
||||
: null
|
||||
|
||||
let leftMissing = mergeAllMissing(
|
||||
reject(isNil, pluck('condition', resolvedExplanation))
|
||||
),
|
||||
candidateVariations = filter(
|
||||
node => !node.condition || node.condition.nodeValue !== false,
|
||||
resolvedExplanation
|
||||
),
|
||||
rightMissing = mergeAllMissing(
|
||||
reject(isNil, pluck('consequence', candidateVariations))
|
||||
),
|
||||
missingVariables = satisfiedVariation
|
||||
? collectNodeMissing(satisfiedVariation.consequence)
|
||||
: mergeMissing(bonus(leftMissing), rightMissing)
|
||||
|
||||
return rewriteNode(node, nodeValue, resolvedExplanation, missingVariables)
|
||||
}
|
||||
|
||||
// TODO - find an appropriate representation
|
||||
|
||||
return {
|
||||
explanation,
|
||||
evaluate,
|
||||
jsx: Variations,
|
||||
category: 'mecanism',
|
||||
name: 'variations',
|
||||
type: 'numeric',
|
||||
unit: inferUnit('+', explanation.map(r => r.consequence.unit))
|
||||
}
|
||||
}
|
||||
import variations from 'Engine/mecanisms/variations'
|
||||
|
||||
export let mecanismOneOf = (recurse, k, v) => {
|
||||
if (!is(Array, v)) throw new Error('should be array')
|
||||
|
@ -576,7 +483,7 @@ export let mecanismProduct = (recurse, k, v) => {
|
|||
return decompose(recurse, k, v)
|
||||
}
|
||||
if (v.variations) {
|
||||
return mecanismVariations(recurse, k, v, true)
|
||||
return variations(recurse, k, v, true)
|
||||
}
|
||||
|
||||
let objectShape = {
|
||||
|
@ -621,62 +528,6 @@ export let mecanismProduct = (recurse, k, v) => {
|
|||
}
|
||||
}
|
||||
|
||||
export let mecanismContinuousScale = (recurse, k, v) => {
|
||||
let objectShape = {
|
||||
assiette: false,
|
||||
multiplicateur: defaultNode(1)
|
||||
}
|
||||
|
||||
let returnRate = v['retourne seulement le taux'] === 'oui'
|
||||
let effect = ({ assiette, multiplicateur, points }) => {
|
||||
if (anyNull([assiette, multiplicateur])) return null
|
||||
//We'll build a linear function given the two constraints that must be respected
|
||||
let result = pipe(
|
||||
toPairs,
|
||||
// we don't rely on the sorting of objects
|
||||
sort(([k1], [k2]) => k1 - k2),
|
||||
points => [...points, [Infinity, last(points)[1]]],
|
||||
aperture(2),
|
||||
reduce((_, [[lowerLimit, lowerRate], [upperLimit, upperRate]]) => {
|
||||
let x1 = val(multiplicateur) * lowerLimit,
|
||||
x2 = val(multiplicateur) * upperLimit,
|
||||
y1 = val(assiette) * val(recurse(lowerRate)),
|
||||
y2 = val(assiette) * val(recurse(upperRate))
|
||||
if (val(assiette) > x1 && val(assiette) <= x2) {
|
||||
// Outside of these 2 limits, it's a linear function a * x + b
|
||||
let a = (y2 - y1) / (x2 - x1),
|
||||
b = y1 - x1 * a,
|
||||
nodeValue = a * val(assiette) + b,
|
||||
taux = nodeValue / val(assiette)
|
||||
return reduced({
|
||||
nodeValue: returnRate ? taux : nodeValue,
|
||||
additionalExplanation: {
|
||||
seuil: val(assiette) / val(multiplicateur),
|
||||
taux
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 0)
|
||||
)(points)
|
||||
|
||||
return result
|
||||
}
|
||||
let explanation = {
|
||||
...parseObject(recurse, objectShape, v),
|
||||
points: v.points,
|
||||
returnRate
|
||||
},
|
||||
evaluate = evaluateObject(objectShape, effect)
|
||||
return {
|
||||
evaluate,
|
||||
jsx: BarèmeContinu,
|
||||
explanation,
|
||||
category: 'mecanism',
|
||||
name: 'barème continu',
|
||||
type: 'numeric'
|
||||
}
|
||||
}
|
||||
|
||||
export let mecanismMax = (recurse, k, v) => {
|
||||
let explanation = v.map(recurse)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defaultNode, evaluateObject } from 'Engine/evaluation'
|
||||
import Barème from 'Engine/mecanismViews/Barème'
|
||||
import { mecanismVariations } from 'Engine/mecanisms'
|
||||
import variations from 'Engine/mecanisms/variations'
|
||||
import { decompose } from 'Engine/mecanisms/utils'
|
||||
import { val } from 'Engine/traverse-common-functions'
|
||||
import { inferUnit, parseUnit } from 'Engine/units'
|
||||
|
@ -21,7 +21,7 @@ export default (recurse, k, v) => {
|
|||
return decompose(recurse, k, v)
|
||||
}
|
||||
if (v.variations) {
|
||||
return mecanismVariations(recurse, k, v, true)
|
||||
return variations(recurse, k, v, true)
|
||||
}
|
||||
let tranches = desugarScale(recurse)(v['tranches']),
|
||||
objectShape = {
|
||||
|
@ -52,8 +52,6 @@ export default (recurse, k, v) => {
|
|||
},
|
||||
evaluate = evaluateObject(objectShape, effect)
|
||||
|
||||
console.log('explanation', explanation)
|
||||
|
||||
return {
|
||||
evaluate,
|
||||
jsx: Barème('linéaire'),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { defaultNode, E, rewriteNode } from 'Engine/evaluation'
|
||||
import { mecanismVariations } from 'Engine/mecanisms'
|
||||
import variations from 'Engine/mecanisms/variations'
|
||||
import { decompose } from 'Engine/mecanisms/utils'
|
||||
import Barème from 'Engine/mecanismViews/Barème'
|
||||
import { val } from 'Engine/traverse-common-functions'
|
||||
|
@ -39,7 +39,7 @@ export default (recurse, k, v) => {
|
|||
return decompose(recurse, k, v)
|
||||
}
|
||||
if (v.variations) {
|
||||
return mecanismVariations(recurse, k, v, true)
|
||||
return variations(recurse, k, v, true)
|
||||
}
|
||||
|
||||
let { assiette, multiplicateur } = v,
|
||||
|
|
|
@ -34,17 +34,3 @@ export let decompose = (recurse, k, v) => {
|
|||
}
|
||||
}
|
||||
|
||||
export let devariateExplanation = (recurse, mecanismKey, v) => {
|
||||
let fixedProps = dissoc('variations')(v),
|
||||
explanation = v.variations.map(({ si, alors, sinon }) => ({
|
||||
consequence: recurse({
|
||||
[mecanismKey]: {
|
||||
...fixedProps,
|
||||
...(sinon || alors)
|
||||
}
|
||||
}),
|
||||
condition: sinon ? undefined : recurse(si)
|
||||
}))
|
||||
|
||||
return explanation
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
import { inferUnit } from 'Engine/units'
|
||||
import {
|
||||
bonus,
|
||||
collectNodeMissing,
|
||||
evaluateNode,
|
||||
mergeAllMissing,
|
||||
mergeMissing,
|
||||
rewriteNode
|
||||
} from 'Engine/evaluation'
|
||||
import { reject, pluck, isNil, filter, dissoc, reduce } from 'ramda'
|
||||
import Variations from 'Engine/mecanismViews/Variations'
|
||||
|
||||
/* @devariate = true => This function will produce variations of a same mecanism (e.g. product) that share some common properties */
|
||||
export default (recurse, k, v, devariate) => {
|
||||
let explanation = devariate
|
||||
? devariateExplanation(recurse, k, v)
|
||||
: v.map(({ si, alors, sinon }) =>
|
||||
sinon !== undefined
|
||||
? { consequence: recurse(sinon), condition: undefined }
|
||||
: { consequence: recurse(alors), condition: recurse(si) }
|
||||
)
|
||||
|
||||
let evaluate = (cache, situationGate, parsedRules, node) => {
|
||||
let evaluateVariationProp = prop =>
|
||||
prop === undefined
|
||||
? undefined
|
||||
: evaluateNode(cache, situationGate, parsedRules, prop),
|
||||
// mark the satisfied variation if any in the explanation
|
||||
[, resolvedExplanation] = reduce(
|
||||
([resolved, result], variation) => {
|
||||
if (resolved) return [true, [...result, variation]]
|
||||
|
||||
// evaluate the condition
|
||||
let evaluatedCondition = evaluateVariationProp(variation.condition)
|
||||
|
||||
if (evaluatedCondition == undefined) {
|
||||
// We've reached the eventual defaut case
|
||||
let evaluatedVariation = {
|
||||
consequence: evaluateVariationProp(variation.consequence),
|
||||
satisfied: true
|
||||
}
|
||||
return [true, [...result, evaluatedVariation]]
|
||||
}
|
||||
|
||||
if (evaluatedCondition.nodeValue === null)
|
||||
// one case has missing variables => we can't go further
|
||||
return [true, [...result, { condition: evaluatedCondition }]]
|
||||
|
||||
if (evaluatedCondition.nodeValue === true) {
|
||||
let evaluatedVariation = {
|
||||
condition: evaluatedCondition,
|
||||
consequence: evaluateVariationProp(variation.consequence),
|
||||
satisfied: true
|
||||
}
|
||||
return [true, [...result, evaluatedVariation]]
|
||||
}
|
||||
return [false, [...result, variation]]
|
||||
},
|
||||
[false, []]
|
||||
)(node.explanation),
|
||||
satisfiedVariation = resolvedExplanation.find(v => v.satisfied),
|
||||
nodeValue = satisfiedVariation
|
||||
? satisfiedVariation.consequence.nodeValue
|
||||
: null
|
||||
|
||||
let leftMissing = mergeAllMissing(
|
||||
reject(isNil, pluck('condition', resolvedExplanation))
|
||||
),
|
||||
candidateVariations = filter(
|
||||
node => !node.condition || node.condition.nodeValue !== false,
|
||||
resolvedExplanation
|
||||
),
|
||||
rightMissing = mergeAllMissing(
|
||||
reject(isNil, pluck('consequence', candidateVariations))
|
||||
),
|
||||
missingVariables = satisfiedVariation
|
||||
? collectNodeMissing(satisfiedVariation.consequence)
|
||||
: mergeMissing(bonus(leftMissing), rightMissing)
|
||||
|
||||
return rewriteNode(node, nodeValue, resolvedExplanation, missingVariables)
|
||||
}
|
||||
|
||||
// TODO - find an appropriate representation
|
||||
|
||||
return {
|
||||
explanation,
|
||||
evaluate,
|
||||
jsx: Variations,
|
||||
category: 'mecanism',
|
||||
name: 'variations',
|
||||
type: 'numeric',
|
||||
unit: inferUnit('+', explanation.map(r => r.consequence.unit))
|
||||
}
|
||||
}
|
||||
|
||||
export let devariateExplanation = (recurse, mecanismKey, v) => {
|
||||
let fixedProps = dissoc('variations')(v),
|
||||
explanation = v.variations.map(({ si, alors, sinon }) => ({
|
||||
consequence: recurse({
|
||||
[mecanismKey]: {
|
||||
...fixedProps,
|
||||
...(sinon || alors)
|
||||
}
|
||||
}),
|
||||
condition: sinon ? undefined : recurse(si)
|
||||
}))
|
||||
|
||||
return explanation
|
||||
}
|
|
@ -2,10 +2,12 @@
|
|||
// In a specific file
|
||||
// TODO import them automatically
|
||||
// TODO convert the legacy functions to new files
|
||||
import barème from 'Engine/mecanisms/barème.js'
|
||||
import barèmeContinu from 'Engine/mecanisms/barème-continu.js'
|
||||
import barèmeLinéaire from 'Engine/mecanisms/barème-linéaire.js'
|
||||
import barème from 'Engine/mecanisms/barème'
|
||||
import barèmeContinu from 'Engine/mecanisms/barème-continu'
|
||||
import barèmeLinéaire from 'Engine/mecanisms/barème-linéaire'
|
||||
import variations from 'Engine/mecanisms/variations'
|
||||
import { Parser } from 'nearley'
|
||||
|
||||
import {
|
||||
add,
|
||||
curry,
|
||||
|
@ -42,7 +44,6 @@ import {
|
|||
mecanismReduction,
|
||||
mecanismSum,
|
||||
mecanismSynchronisation,
|
||||
mecanismVariations,
|
||||
mecanismOnePossibility
|
||||
} from './mecanisms'
|
||||
import { Node } from './mecanismViews/common'
|
||||
|
@ -145,7 +146,7 @@ export let parseObject = (rules, rule, parsedRules) => rawNode => {
|
|||
'une possibilité': mecanismOnePossibility(rule.dottedName),
|
||||
'inversion numérique': mecanismInversion(rule.dottedName),
|
||||
allègement: mecanismReduction,
|
||||
variations: mecanismVariations,
|
||||
variations,
|
||||
synchronisation: mecanismSynchronisation,
|
||||
...operationDispatch,
|
||||
filter: () =>
|
||||
|
|
Loading…
Reference in New Issue