UNPKG

javascript-lp-solver

Version:

Easy to use, JSON oriented Linear Programming and Mixed Int. Programming Solver

200 lines (167 loc) 6.11 kB
/*global describe*/ /*global require*/ /*global module*/ /*global it*/ /*global console*/ /*global process*/ //------------------------------------------------------------------- //------------------------------------------------------------------- function Variable(id, cost, index, priority) { this.id = id; this.cost = cost; this.index = index; this.value = 0; this.priority = priority; } function IntegerVariable(id, cost, index, priority) { Variable.call(this, id, cost, index, priority); } IntegerVariable.prototype.isInteger = true; function SlackVariable(id, index) { Variable.call(this, id, 0, index, 0); } SlackVariable.prototype.isSlack = true; //------------------------------------------------------------------- //------------------------------------------------------------------- function Term(variable, coefficient) { this.variable = variable; this.coefficient = coefficient; } function createRelaxationVariable(model, weight, priority) { if (priority === 0 || priority === "required") { return null; } weight = weight || 1; priority = priority || 1; if (model.isMinimization === false) { weight = -weight; } return model.addVariable(weight, "r" + (model.relaxationIndex++), false, false, priority); } //------------------------------------------------------------------- //------------------------------------------------------------------- function Constraint(rhs, isUpperBound, index, model) { this.slack = new SlackVariable("s" + index, index); this.index = index; this.model = model; this.rhs = rhs; this.isUpperBound = isUpperBound; this.terms = []; this.termsByVarIndex = {}; // Error variable in case the constraint is relaxed this.relaxation = null; } Constraint.prototype.addTerm = function (coefficient, variable) { var varIndex = variable.index; var term = this.termsByVarIndex[varIndex]; if (term === undefined) { // No term for given variable term = new Term(variable, coefficient); this.termsByVarIndex[varIndex] = term; this.terms.push(term); if (this.isUpperBound === true) { coefficient = -coefficient; } this.model.updateConstraintCoefficient(this, variable, coefficient); } else { // Term for given variable already exists // updating its coefficient var newCoefficient = term.coefficient + coefficient; this.setVariableCoefficient(newCoefficient, variable); } return this; }; Constraint.prototype.removeTerm = function (term) { // TODO return this; }; Constraint.prototype.setRightHandSide = function (newRhs) { if (newRhs !== this.rhs) { var difference = newRhs - this.rhs; if (this.isUpperBound === true) { difference = -difference; } this.rhs = newRhs; this.model.updateRightHandSide(this, difference); } return this; }; Constraint.prototype.setVariableCoefficient = function (newCoefficient, variable) { var varIndex = variable.index; if (varIndex === -1) { console.warn("[Constraint.setVariableCoefficient] Trying to change coefficient of inexistant variable."); return; } var term = this.termsByVarIndex[varIndex]; if (term === undefined) { // No term for given variable this.addTerm(newCoefficient, variable); } else { // Term for given variable already exists // updating its coefficient if changed if (newCoefficient !== term.coefficient) { var difference = newCoefficient - term.coefficient; if (this.isUpperBound === true) { difference = -difference; } term.coefficient = newCoefficient; this.model.updateConstraintCoefficient(this, variable, difference); } } return this; }; Constraint.prototype.relax = function (weight, priority) { this.relaxation = createRelaxationVariable(this.model, weight, priority); this._relax(this.relaxation); }; Constraint.prototype._relax = function (relaxationVariable) { if (relaxationVariable === null) { // Relaxation variable not created, priority was probably "required" return; } if (this.isUpperBound) { this.setVariableCoefficient(-1, relaxationVariable); } else { this.setVariableCoefficient(1, relaxationVariable); } }; //------------------------------------------------------------------- //------------------------------------------------------------------- function Equality(constraintUpper, constraintLower) { this.upperBound = constraintUpper; this.lowerBound = constraintLower; this.model = constraintUpper.model; this.rhs = constraintUpper.rhs; this.relaxation = null; } Equality.prototype.isEquality = true; Equality.prototype.addTerm = function (coefficient, variable) { this.upperBound.addTerm(coefficient, variable); this.lowerBound.addTerm(coefficient, variable); return this; }; Equality.prototype.removeTerm = function (term) { this.upperBound.removeTerm(term); this.lowerBound.removeTerm(term); return this; }; Equality.prototype.setRightHandSide = function (rhs) { this.upperBound.setRightHandSide(rhs); this.lowerBound.setRightHandSide(rhs); this.rhs = rhs; }; Equality.prototype.relax = function (weight, priority) { this.relaxation = createRelaxationVariable(this.model, weight, priority); this.upperBound.relaxation = this.relaxation; this.upperBound._relax(this.relaxation); this.lowerBound.relaxation = this.relaxation; this.lowerBound._relax(this.relaxation); }; module.exports = { Constraint: Constraint, Variable: Variable, IntegerVariable: IntegerVariable, SlackVariable: SlackVariable, Equality: Equality, Term: Term };