UNPKG

consys

Version:

consys is a flexible tool to evaluate models using generic and readable constraints.

319 lines (318 loc) 11.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const Util_1 = __importStar(require("./Util")); const Constraint_1 = __importDefault(require("./Constraint")); const TextProcessor_1 = __importDefault(require("./dsl/TextProcessor")); /** * A constraint system with multiple constraints and custom functions, defined for specific model and state types. */ class ConstraintSystem { constructor() { this.constraints = []; this.functions = {}; this.evaluationData = null; this.updatedFunctions = true; } /** * For a given evaluation filter type, return the corresponding function * * @param evaluationFilter filter type * @private */ static getFilterFunction(evaluationFilter) { switch (evaluationFilter) { case 'all': return () => true; case 'consistent': return (evaluation) => evaluation.consistent; case 'inconsistent': return (evaluation) => !evaluation.consistent; default: return (evaluation) => evaluationFilter(evaluation.resource); } } /** * Registers a plugin for this constraint system. * * @param plugin plugin to be registered */ registerPlugin(plugin) { return __awaiter(this, void 0, void 0, function* () { yield plugin.registerFunctions(this); yield plugin.registerConstraints(this); }); } /** * Adds a constraint to this constraint system. * * @param resource constraint data */ addConstraint(resource) { this.constraints.push(new Constraint_1.default(resource)); } /** * Adds an array of constraints to this constraint system. * * @param resources constraint data */ addConstraints(resources) { for (let resource of resources) { this.addConstraint(resource); } } /** * Adds a custom function to this constraint system. * * @param name name of the function * @param fun custom function */ addFunction(name, fun) { this.addFun(name, fun); } /** * Adds a custom statement (function without any arguments) to this constraint system. * * @param name name of the statement * @param fun custom statement */ addStatement(name, fun) { this.addFun(name, fun); } /** * Evaluates one or more models and a state given all registered constraints and functions. * * @param model model to be evaluated * @param state state to be evaluated * @param include optionally filter evaluations of reports */ evaluate(model, state, include = 'all') { let reports; if (model instanceof Array) { reports = this.evaluateMultiple(model, state); } else { reports = [this.evaluateSingle(model, state)]; } this.filterReportEvaluation(reports, include); this.updatedFunctions = false; return reports; } /** * Helper function to add a custom function or statement. * * @param name name of the function or statement * @param fun custom function or statement * @private */ addFun(name, fun) { if (this.functions[name] !== undefined) { throw Util_1.Log.error('Function with name ' + name + ' is already registered'); } this.functions[name] = fun; this.updatedFunctions = true; } /** * Filters evaluations of reports based on a given function. * * @param reports reports for which evaluations are filtered * @param evaluationFilter filter function * @private */ filterReportEvaluation(reports, evaluationFilter) { for (let report of reports) { let evaluation = report.evaluation; report.evaluation = evaluation.filter(ConstraintSystem.getFilterFunction(evaluationFilter)); } } /** * Evaluates multiple models and a single state. * * @param models models to be evaluated * @param state state to be evaluated * @private */ evaluateMultiple(models, state) { let reports = []; for (let model of models) { let report = this.evaluateSingle(model, state); reports.push(report); } return reports; } /** * Evaluates a single model and state. * * @param model model to be evaluated * @param state state to be evaluated * @private */ evaluateSingle(model, state) { let evaluationRes = []; this.updateEvaluationData(model, state); for (let constraint of this.constraints) { let evaluation = constraint.evaluate(this.evaluationData, this.updatedFunctions); evaluationRes.push(evaluation); } let constraintData = this.getConstraintData(); return { checkedModel: model, checkedState: state, checkedConstraints: constraintData, evaluation: evaluationRes, }; } /** * Accumulates the occurrences of keys in src to the keys in res. * * @param src src counts * @param res res counts * @private */ static accumulateOccurrences(src, res) { for (let srcKey of Object.keys(src)) { res[srcKey] += src[srcKey]; } } /** * Returns statistical data about the occurrences of model and state variables in consistent or inconsistent * constraints. This can be used to determine which variable has the most influence on the result. * * @param model model to be evaluated * @param state state to be evaluated */ evaluateStatistics(model, state) { let res = { totalConstraints: this.constraints.length, consistent: { total: 0, model: Util_1.default.initCounts(model, 0), state: Util_1.default.initCounts(state, 0), }, inconsistent: { total: 0, model: Util_1.default.initCounts(model, 0), state: Util_1.default.initCounts(state, 0), }, }; this.updateEvaluationData(model, state); for (let constraint of this.constraints) { if (constraint.isConsistent(this.evaluationData)) { res.consistent.total++; ConstraintSystem.accumulateOccurrences(constraint.getModelVarOccurrences(), res.consistent.model); ConstraintSystem.accumulateOccurrences(constraint.getStateVarOccurrences(), res.consistent.state); } else { res.inconsistent.total++; ConstraintSystem.accumulateOccurrences(constraint.getModelVarOccurrences(), res.inconsistent.model); ConstraintSystem.accumulateOccurrences(constraint.getStateVarOccurrences(), res.inconsistent.state); } } return res; } /** * Returns the number of constraints that are inconsistent with the given model and state. * * @param model model to be evaluated * @param state state to be evaluated */ getNumInconsistentConstraints(model, state) { this.updateEvaluationData(model, state); let numInconsistent = 0; for (let constraint of this.constraints) { if (!constraint.isConsistent(this.evaluationData)) { numInconsistent++; } } return numInconsistent; } /** * Returns the number of constraints that are consistent with the given model and state. * * @param model model to be evaluated * @param state state to be evaluated */ getNumConsistentConstraints(model, state) { return (this.constraints.length - this.getNumInconsistentConstraints(model, state)); } /** * Returns the number of constraints that were added to this system. */ getNumConstraints() { return this.constraints.length; } /** * Updates the data used to evaluate constraints with the new model, state and functions. * * @param model new model * @param state new state * @private */ updateEvaluationData(model, state) { if (!this.evaluationData) { this.evaluationData = { model: model, state: state, functions: this.functions, }; } else { this.evaluationData.model = model; this.evaluationData.state = state; this.evaluationData.functions = this.functions; } } /** * Returns a converted message string by replacing function calls or model and state variables with their * actual current value. * * @param msgString message to be converted * @param model model * @param state state */ getMessage(msgString, model, state) { return new TextProcessor_1.default(msgString).process(model, state, this.functions); } /** * Returns all constraint data that was registered. * @private */ getConstraintData() { let res = []; for (let constraint of this.constraints) { res.push(constraint.getResource()); } return res; } } exports.default = ConstraintSystem;