UNPKG

consys-solver

Version:

consys-solver is a tool to find feasible model assignments for consys constraint systems.

257 lines (256 loc) 7.9 kB
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[]; }