Optimise le calcul des variables manquantes

pull/197/head
Laurent Bossavit 2018-04-12 15:43:02 +02:00
parent ac5ec86adb
commit 48b2158ff8
4 changed files with 48 additions and 44 deletions

View File

@ -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)
}

View File

@ -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),

View File

@ -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)

View File

@ -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}))