consys-solver
Version:
consys-solver is a tool to find feasible model assignments for consys constraint systems.
257 lines (256 loc) • 7.9 kB
TypeScript
import { ConstraintSystem } from 'consys';
import Domain from './Domain';
/**
* Model domain object. Should have the same keys as the result model, which
* each key having a specific domain to be searched for a solution.
*/
export interface ModelDomain {
[key: string]: Domain<any> | ModelDomain;
}
/**
* Solver configuration.
*
* @param maxIterations Maximum number of iterations until the algorithm stops.
* The default number is 10000 iterations.
*
* @param retryIterations The number of iterations until the algorithm starts
* again with random values. Useful to get the algorithm out of dead ends.
*
* @param lookAheadModels Determines how many models should be considered for
* the next iteration. Set to the maximum domain size by default.
*
* @param randomnessFactor Value between 0.0 and 1.0, determines how often the
* algorithm chooses a random model for the next iteration. A value of 0.0
* means that it never chooses randomly, and a value of 1.0 means it always
* chooses randomly. This is useful to avoid local extrema and plateaus.
* The default value is 0.3.
*
* @param preferenceFactor Value between 0.0 and 1.0, determines how much the
* domain preference value is weighted when choosing the model for the next
* iteration. A value of 0.0 means that preferences are not considered, whereas
* a value of 1.0 means that they heavily influence the decision. The default
* value is 0.1.
*
*/
export interface SolverConfig {
maxIterations?: number;
retryIterations?: number;
lookAheadModels?: number;
randomnessFactor?: number;
preferenceFactor?: number;
}
/**
* Solver class, used to find solutions for a specific set of constraints and
* domains.
*/
export default class Solver<M, S> {
private readonly system;
private readonly config;
/**
* Create a new solver instance for a given constraint system and config.
*
* @param system constraint system
* @param config configuration
*/
constructor(system: ConstraintSystem<M, S>, config?: SolverConfig);
/**
* Initializes parameters based on the given config.
*
* @param config configuration
* @private
*/
private initConfig;
/**
* Flatten a model domain object to have keys as strings, seperated by a dot
* if the key is nested.
*
* @param modelDomain initial domain object
* @param parent parent key
* @param res result map
* @private
*/
private static flattenModelDomain;
/**
* Creates a model domains object with domain values and current search index.
*
* @param modelDomain model domain
* @private
*/
private static getModelDomains;
/**
* Inserts a value into an object. Key is a dot separated string, which will
* result in a nested value.
*
* @param object object where value should be inserted
* @param key key of the value
* @param value value to be inserted
* @private
*/
private static insertValue;
/**
* Randomizes the current search index of each domain.
*
* @param modelDomains model domains
* @private
*/
private static randomizeModel;
/**
* Creates a new model object from the values of the current search indices.
*
* @param modelDomains model domains
* @private
*/
private getCurrentModel;
/**
* Calculates a logarithmic score between 0 (bad) and 1 (perfect) for a given
* model and state.
*
* @param model model instance
* @param state state instance
* @private
*/
private getLogScore;
/**
* Returns a normalized preference score from 0 to 1
*
* @param preference preference of the domain value
* @private
*/
private getPreferenceScore;
/**
* Calculates the harmonic mean of the log score and preference score. This
* penalizes low values for the log score, as well as low values for the
* preference score. Only if both values are high, the harmonic mean will be
* high as well.
*
* @param logScore log score
* @param prefScore preference score
* @private
*/
private static getHarmonicMean;
/**
* Calculates the total score of a given model and state.
*
* @param instance model with preference value
* @param state state
* @private
*/
private getScore;
/**
* Checks if a model is consistent with a given state.
*
* @param model model to be checked
* @param state state to be checked
* @private
*/
private isModelFeasible;
/**
* Shuffles an array of values.
*
* @param array array to be shuffled
* @private
*/
private static shuffle;
/**
* Randomly chooses a key based on their counts as weights.
*
* @param domains key domains
* @param keyCounts key counts
* @private
*/
private static chooseKey;
/**
* Returns an array of values to be considered as the next value for a model
* domain.
*
* @param domains model domains
* @param key key to be searched for values
* @private
*/
private getNextValuesForKey;
/**
* Checks if two models have equal keys and values.
*
* @param model0 first model
* @param model1 second model
* @private
*/
private static modelsEqual;
/**
* Checks if a model is already in an array of solutions.
*
* @param solutions solutions
* @param model model
* @private
*/
private isModelInSolutions;
/**
* Returns an array of models to be considered as the next best model, along
* with their preference value.
*
* @param solutions current solutions
* @param domains model domains
* @param key key to be changed for the next models
* @param nextValues array of possible next values for the key
* @private
*/
private getNextModels;
/**
* Returns the next best model given a current model, state and solutions.
*
* @param solutions current solutions
* @param domains model domains
* @param currentModel current model
* @param state state
* @private
*/
private getNextBestModel;
/**
* Chooses a random element from array.
*
* @param values array
* @private
*/
private static chooseRandom;
/**
* Returns the model with the minimum amount of conflicts (heuristic) and
* factors in the preference value.
*
* @param models models to be considered
* @param state state
* @private
*/
private minConflicts;
/**
* Returns the maximum look ahead value based on the size of the largest
* domain.
*
* @param domains model domains
* @private
*/
private static getMaxLookAhead;
private static initializePreferredDomains;
/**
* Searches for solutions with a given configuration. Returns an array of
* solutions as well as the number of iterations it took to find them.
*
* @param maxSolutions maximum number of solutions to be found before stopping
* @param modelDomain model domain to be searched
* @param state state
* @param config solver configuration
*/
solve(maxSolutions: number, modelDomain: ModelDomain, state: S, config?: SolverConfig): {
iterations: number;
solutions: M[];
};
/**
* Searches for solutions with a given configuration. Returns an array of
* solutions.
*
* @param maxSolutions maximum number of solutions to be found before stopping
* @param modelDomain model domain to be searched
* @param state state
* @param config solver configuration
*/
find(maxSolutions: number, modelDomain: ModelDomain, state: S, config?: SolverConfig): M[];
}