diff --git a/source/engine/evaluation.js b/source/engine/evaluation.js index 983a22af6..7816c5617 100644 --- a/source/engine/evaluation.js +++ b/source/engine/evaluation.js @@ -1,9 +1,11 @@ import { + add, map, pluck, any, equals, reduce, + mergeWith, chain, length, flatten, @@ -20,7 +22,10 @@ export let makeJsx = node => ? node.jsx(node.nodeValue, node.explanation) : node.jsx -export let collectNodeMissing = node => node.missingVariables || [] +export let collectNodeMissing = node => node.missingVariables || {} + +export let mergeAllMissing = missings => reduce(mergeWith(add),{},map(collectNodeMissing,missings)) +export let mergeMissing = (left, right) => mergeWith(add, left || {}, right || {}) export let evaluateNode = (cache, situationGate, parsedRules, node) => node.evaluate ? node.evaluate(cache, situationGate, parsedRules, node) : node @@ -46,8 +51,8 @@ export let evaluateArray = (reducer, start) => ( ? null : reduce(reducer, start, values), missingVariables = node.nodeValue == null - ? map(collectNodeMissing, explanation) - : [] + ? mergeAllMissing(explanation) + : {} // console.log("".padStart(cache.parseLevel),map(node => length(flatten(collectNodeMissing(node))) ,explanation)) return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -69,10 +74,8 @@ export let evaluateArrayWithFilter = (evaluationFilter, reducer, start) => ( ? null : reduce(reducer, start, values), missingVariables = node.nodeValue == null - // TODO - this works by coincidence, composantes are usually of a computation - // where missing variables are shared - ? uniq(map(collectNodeMissing, explanation)) - : [] + ? mergeAllMissing(explanation) + : {} return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -98,7 +101,7 @@ export let evaluateObject = (objectShape, effect) => ( let transforms = map(k => [k, evaluateOne], keys(objectShape)), explanation = evolve(fromPairs(transforms))(node.explanation), nodeValue = effect(explanation), - missingVariables = map(collectNodeMissing, values(explanation)) + missingVariables = mergeAllMissing(values(explanation)) // console.log("".padStart(cache.parseLevel),map(node => length(flatten(collectNodeMissing(node))) ,explanation)) return rewriteNode(node, nodeValue, explanation, missingVariables) } diff --git a/source/engine/generateQuestions.js b/source/engine/generateQuestions.js index c5d02168c..1155a1a69 100644 --- a/source/engine/generateQuestions.js +++ b/source/engine/generateQuestions.js @@ -1,5 +1,6 @@ import { flatten, + mergeAll, pluck, groupBy, toPairs, @@ -39,14 +40,10 @@ import { findRuleByDottedName, disambiguateRuleReference } from './rules' missingVariables: {variable: [objectives]} */ -export let collectMissingVariables = targets => { - let missing = flatten(pluck('missingVariables', targets)) -// console.log("total # missing", length(missing)) - return groupBy(identity, missing) -} +export let collectMissingVariables = targets => mergeAll(pluck('missingVariables', targets)) export let getNextSteps = (situationGate, analysis) => { - let impact = ([, objectives]) => length(objectives) + let impact = ([, count]) => count let missingVariables = collectMissingVariables(analysis.targets), pairs = toPairs(missingVariables), diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index 018fbc661..8bfbe240b 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -1,5 +1,6 @@ import { flatten, + mergeAll, length, objOf, toPairs, @@ -42,7 +43,9 @@ import { evaluateArrayWithFilter, evaluateObject, parseObject, - collectNodeMissing + collectNodeMissing, + mergeAllMissing, + mergeMissing } from './evaluation' import { findRuleByName, @@ -151,14 +154,12 @@ let devariate = (recurse, k, v) => { nodeValue = choice ? choice.nodeValue : null let leftMissing = choice - ? [] - : uniq( - map(collectNodeMissing, pluck('condition', explanation)) - ), + ? {} + : mergeAllMissing(pluck('condition', explanation)), rightMissing = !choice - ? [] - : map(collectNodeMissing, satisfied), - missingVariables = concat(leftMissing, rightMissing || []) + ? {} + : mergeAllMissing(satisfied), + missingVariables = mergeMissing(leftMissing, rightMissing) return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -222,7 +223,7 @@ export let mecanismOneOf = (recurse, k, v) => { nodeValue = any(equals(true), values) ? true : any(equals(null), values) ? null : false, - missingVariables = nodeValue == null ? uniq(map(collectNodeMissing, explanation)) : [] + missingVariables = nodeValue == null ? mergeAllMissing(explanation) : {} return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -265,7 +266,7 @@ export let mecanismAllOf = (recurse, k, v) => { nodeValue = any(equals(false), values) ? false // court-circuit : any(equals(null), values) ? null : true, - missingVariables = nodeValue == null ? map(collectNodeMissing, explanation) : [] + missingVariables = nodeValue == null ? mergeAllMissing(explanation) : {} return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -311,8 +312,8 @@ export let mecanismNumericalSwitch = (recurse, k, v) => { investigate = explanation.condition.nodeValue !== false, missingOnTheRight = investigate ? explanation.consequence.missingVariables - : [], - missingVariables = concat(missingOnTheLeft || [], missingOnTheRight || []) + : {}, + missingVariables = mergeMissing(missingOnTheLeft, missingOnTheRight) return { ...node, @@ -359,7 +360,7 @@ export let mecanismNumericalSwitch = (recurse, k, v) => { choice = find(node => node.condValue, explanation), missingVariables = choice ? choice.missingVariables - : map(collectNodeMissing, explanation) + : mergeAllMissing(explanation) return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -426,7 +427,7 @@ let doInversion = (oldCache, situationGate, parsedRules, v, dottedName) => { if (inversion.inversionChoiceNeeded) return { - missingVariables: [dottedName], + missingVariables: {[dottedName]:1}, nodeValue: null } let { fixedObjectiveValue, fixedObjectiveRule } = inversion @@ -461,7 +462,7 @@ let doInversion = (oldCache, situationGate, parsedRules, v, dottedName) => { return { nodeValue, - missingVariables: [], + missingVariables: {}, inversionCache } } @@ -473,7 +474,7 @@ export let mecanismInversion = dottedName => (recurse, k, v) => { situationGate(dottedName) == undefined && doInversion(cache, situationGate, parsedRules, v, dottedName), nodeValue = inversion.nodeValue, - missingVariables = uniq(flatten(inversion.missingVariables)) + missingVariables = inversion.missingVariables let evaluatedNode = rewriteNode(node, nodeValue, null, missingVariables) diff --git a/source/engine/traverse.js b/source/engine/traverse.js index 07ce38eac..74c41cd1c 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -19,6 +19,7 @@ import { divide, multiply, map, + merge, length, flatten, intersection, @@ -57,7 +58,9 @@ import { import { evaluateNode, rewriteNode, - makeJsx + makeJsx, + mergeMissing, + mergeAllMissing } from './evaluation' import { anyNull, @@ -152,10 +155,10 @@ let fillVariableNode = (rules, rule, filter) => parseResult => { ? parsedRule.nodeValue // la valeur du calcul fait foi : null, // elle restera donc nulle missingVariables = nodeValue != null // notamment si situationValue != null - ? [] + ? {} : variableIsCalculable ? parsedRule.missingVariables - : [dottedName] + : {[dottedName]:1} cache[cacheName] = rewriteNode(node, nodeValue, explanation, missingVariables) return cache[cacheName] @@ -300,9 +303,9 @@ let treat = (rules, rule) => rawNode => { value1 == null || value2 == null ? null : operatorFunction(value1, value2), - missingVariables = concat( - explanation[0].missingVariables || [], - explanation[1].missingVariables || []) + missingVariables = mergeMissing( + explanation[0].missingVariables, + explanation[1].missingVariables) return rewriteNode(node, nodeValue, explanation, missingVariables) } @@ -407,7 +410,7 @@ let treat = (rules, rule) => rawNode => { sélection: mecanismSelection, 'une possibilité': always({ 'une possibilité': 'oui', - missingVariables: [rule.dottedName] + missingVariables: {[rule.dottedName]:1} }), inversion: mecanismInversion(rule.dottedName), allègement: mecanismReduction @@ -480,16 +483,16 @@ export let treatRuleRoot = (rules, rule) => { let condMissing = val(notApplicable) === true - ? [] + ? {} : val(applicable) === false - ? [] - : concat( - (notApplicable && notApplicable.missingVariables) || [], - (applicable && applicable.missingVariables) || [] + ? {} + : merge( + (notApplicable && notApplicable.missingVariables) || {}, + (applicable && applicable.missingVariables) || {} ), collectInFormule = isApplicable !== false, - formMissing = (collectInFormule && formule.missingVariables) || [], - missingVariables = concat(condMissing, formMissing) + formMissing = (collectInFormule && formule.missingVariables) || {}, + missingVariables = mergeMissing(condMissing, formMissing) cache.parseLevel-- // console.log("".padStart(cache.parseLevel-1),map(mv => length(flatten(mv)), {ruleCond:condMissing, formule:formMissing}))