UNPKG

@uandi/javascript-lp-solver

Version:

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

125 lines (101 loc) 3.83 kB
/*global require*/ var Tableau = require("./Tableau.js"); var SlackVariable = require("../expressions.js").SlackVariable; Tableau.prototype.addCutConstraints = function (cutConstraints) { var nCutConstraints = cutConstraints.length; var height = this.height; var heightWithCuts = height + nCutConstraints; // Adding rows to hold cut constraints for (var h = height; h < heightWithCuts; h += 1) { if (this.matrix[h] === undefined) { this.matrix[h] = this.matrix[h - 1].slice(); } } // Adding cut constraints this.height = heightWithCuts; this.nVars = this.width + this.height - 2; var c; var lastColumn = this.width - 1; for (var i = 0; i < nCutConstraints; i += 1) { var cut = cutConstraints[i]; // Constraint row index var r = height + i; var sign = (cut.type === "min") ? -1 : 1; // Variable on which the cut is applied var varIndex = cut.varIndex; var varRowIndex = this.rowByVarIndex[varIndex]; var constraintRow = this.matrix[r]; if (varRowIndex === -1) { // Variable is non basic constraintRow[this.rhsColumn] = sign * cut.value; for (c = 1; c <= lastColumn; c += 1) { constraintRow[c] = 0; } constraintRow[this.colByVarIndex[varIndex]] = sign; } else { // Variable is basic var varRow = this.matrix[varRowIndex]; var varValue = varRow[this.rhsColumn]; constraintRow[this.rhsColumn] = sign * (cut.value - varValue); for (c = 1; c <= lastColumn; c += 1) { constraintRow[c] = -sign * varRow[c]; } } // Creating slack variable var slackVarIndex = this.getNewElementIndex(); this.varIndexByRow[r] = slackVarIndex; this.rowByVarIndex[slackVarIndex] = r; this.colByVarIndex[slackVarIndex] = -1; this.variablesPerIndex[slackVarIndex] = new SlackVariable("s"+slackVarIndex, slackVarIndex); this.nVars += 1; } }; Tableau.prototype._addLowerBoundMIRCut = function(rowIndex) { if(rowIndex === this.costRowIndex) { //console.log("! IN MIR CUTS : The index of the row corresponds to the cost row. !"); return false; } var model = this.model; var matrix = this.matrix; var intVar = this.variablesPerIndex[this.varIndexByRow[rowIndex]]; if (!intVar.isInteger) { return false; } var d = matrix[rowIndex][this.rhsColumn]; var frac_d = d - Math.floor(d); if (frac_d < this.precision || 1 - this.precision < frac_d) { return false; } //Adding a row var r = this.height; matrix[r] = matrix[r - 1].slice(); this.height += 1; // Creating slack variable this.nVars += 1; var slackVarIndex = this.getNewElementIndex(); this.varIndexByRow[r] = slackVarIndex; this.rowByVarIndex[slackVarIndex] = r; this.colByVarIndex[slackVarIndex] = -1; this.variablesPerIndex[slackVarIndex] = new SlackVariable("s"+slackVarIndex, slackVarIndex); matrix[r][this.rhsColumn] = Math.floor(d); for (var colIndex = 1; colIndex < this.varIndexByCol.length; colIndex += 1) { var variable = this.variablesPerIndex[this.varIndexByCol[colIndex]]; if (!variable.isInteger) { matrix[r][colIndex] = Math.min(0, matrix[rowIndex][colIndex] / (1 - frac_d)); } else { var coef = matrix[rowIndex][colIndex]; var termCoeff = Math.floor(coef)+Math.max(0, coef - Math.floor(coef) - frac_d) / (1 - frac_d); matrix[r][colIndex] = termCoeff; } } for(var c = 0; c < this.width; c += 1) { matrix[r][c] -= matrix[rowIndex][c]; } return true; }; Tableau.prototype.applyMIRCuts = function () { var nRows = this.height; for (var cst = 0; cst < nRows; cst += 1) { this._addLowerBoundMIRCut(cst); } };