finitedomain
Version:
A fast feature rich finite domain solver
80 lines (61 loc) • 2.9 kB
JavaScript
import {
LOG_FLAG_PROPSTEPS,
ASSERT,
ASSERT_LOG,
ASSERT_NORDOM,
} from '../helpers';
import {
domain__debug,
domain_createEmpty,
domain_isSolved,
domain_min,
} from '../domain';
import {
markov_createLegend,
markov_createProbVector,
} from '../markov';
// BODY_START
/**
* Markov uses a special system for trying values. The domain doesn't
* govern the list of possible values, only acts as a mask for the
* current node in the search tree (-> space). But since FD will work
* based on this domain anyways we will need this extra step to verify
* whether a solved var is solved to a valid value in current context.
*
* Every markov variable should have a propagator. Perhaps later
* there can be one markov propagator that checks all markov vars.
*
* @param {$space} space
* @param {$config} config
* @param {number} varIndex
*/
function propagator_markovStepBare(space, config, varIndex) {
// THIS IS VERY EXPENSIVE IF expandVectorsWith IS ENABLED
ASSERT(typeof varIndex === 'number', 'VAR_INDEX_SHOULD_BE_NUMBER');
let domain = space.vardoms[varIndex];
ASSERT_NORDOM(domain);
ASSERT(domain, 'SHOULD_NOT_BE_REJECTED');
if (!domain_isSolved(domain)) {
ASSERT_LOG(LOG_FLAG_PROPSTEPS, log => log('propagator_markovStepBare; indexes:', varIndex, 'was solved:', domain__debug(domain)));
return;
}
let value = domain_min(domain); // note: solved so lo=hi=value
let configVarDistOptions = config.varDistOptions;
let distributeOptions = configVarDistOptions[config.allVarNames[varIndex]];
ASSERT(distributeOptions, 'var should have a config', varIndex, distributeOptions && JSON.stringify(configVarDistOptions));
ASSERT(distributeOptions.valtype === 'markov', 'var should be a markov var', distributeOptions.valtype);
let expandVectorsWith = distributeOptions.expandVectorsWith;
ASSERT(distributeOptions.matrix, 'there should be a matrix available for every var');
ASSERT(distributeOptions.legend || (expandVectorsWith != null), 'every var should have a legend or expandVectorsWith set');
// note: expandVectorsWith can be 0, so check with null
let values = markov_createLegend(expandVectorsWith != null, distributeOptions.legend, domain); // TODO: domain is a value, can this be optimized? is that worth the effort? (profile this)
let probabilities = markov_createProbVector(space, distributeOptions.matrix, expandVectorsWith, values.length);
let pos = values.indexOf(value);
if (pos < 0 || pos >= probabilities.length || probabilities[pos] === 0) {
space.vardoms[varIndex] = domain_createEmpty();
}
ASSERT_LOG(LOG_FLAG_PROPSTEPS, log => log('propagator_markovStepBare; indexes:', varIndex, 'was:', domain__debug(domain), 'became:', domain__debug(space.vardoms[varIndex])));
ASSERT_NORDOM(space.vardoms[varIndex], true, domain__debug);
}
// BODY_STOP
export default propagator_markovStepBare;