UNPKG

javascript-lp-solver

Version:

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

198 lines (169 loc) 6.51 kB
/*global describe*/ /*global require*/ /*global module*/ /*global it*/ /*global console*/ /*global process*/ /*************************************************************** * Method: polyopt * Scope: private * Agruments: * model: The model we want solver to operate on. Because we're in here, we're assuming that we're solving a multi-objective optimization problem. Poly-Optimization. polyopt. This model has to be formed a little differently because it has multiple objective functions. Normally, a model has 2 attributes: opType (string, "max" or "min"), and optimize (string, whatever attribute we're optimizing. Now, there is no opType attribute on the model, and optimize is an object of attributes to be optimized, and how they're to be optimized. For example: ... "optimize": { "pancakes": "max", "cost": "minimize" } ... **************************************************************/ module.exports = function(solver, model){ // I have no idea if this is actually works, or what, // but here is my algorithm to solve linear programs // with multiple objective functions // 1. Optimize for each constraint // 2. The results for each solution is a vector // representing a vertex on the polytope we're creating // 3. The results for all solutions describes the shape // of the polytope (would be nice to have the equation // representing this) // 4. Find the mid-point between all vertices by doing the // following (a_1 + a_2 ... a_n) / n; var objectives = model.optimize, new_constraints = JSON.parse(JSON.stringify(model.optimize)), keys = Object.keys(model.optimize), tmp, counter = 0, vectors = {}, vector_key = "", obj = {}, pareto = [], i,j,x,y,z; // Delete the optimize object from the model delete model.optimize; // Iterate and Clear for(i = 0; i < keys.length; i++){ // Clean up the new_constraints new_constraints[keys[i]] = 0; } // Solve and add for(i = 0; i < keys.length; i++){ // Prep the model model.optimize = keys[i]; model.opType = objectives[keys[i]]; // solve the model tmp = solver.Solve(model, undefined, undefined, true); // Only the variables make it into the solution; // not the attributes. // // Because of this, we have to add the attributes // back onto the solution so we can do math with // them later... // Loop over the keys for(y in keys){ // We're only worried about attributes, not variables if(!model.variables[keys[y]]){ // Create space for the attribute in the tmp object tmp[keys[y]] = tmp[keys[y]] ? tmp[keys[y]] : 0; // Go over each of the variables for(x in model.variables){ // Does the variable exist in tmp *and* does attribute exist in this model? if(model.variables[x][keys[y]] && tmp[x]){ // Add it to tmp tmp[keys[y]] += tmp[x] * model.variables[x][keys[y]]; } } } } // clear our key vector_key = "base"; // this makes sure that if we get // the same vector more than once, // we only count it once when finding // the midpoint for(j = 0; j < keys.length; j++){ if(tmp[keys[j]]){ vector_key += "-" + ((tmp[keys[j]] * 1000) | 0) / 1000; } else { vector_key += "-0"; } } // Check here to ensure it doesn't exist if(!vectors[vector_key]){ // Add the vector-key in vectors[vector_key] = 1; counter++; // Iterate over the keys // and update our new constraints for(j = 0; j < keys.length; j++){ if(tmp[keys[j]]){ new_constraints[keys[j]] += tmp[keys[j]]; } } // Push the solution into the paretos // array after cleaning it of some // excess data markers delete tmp.feasible; delete tmp.result; pareto.push(tmp); } } // Trying to find the mid-point // divide each constraint by the // number of constraints // *midpoint formula* // (x1 + x2 + x3) / 3 for(i = 0; i < keys.length; i++){ model.constraints[keys[i]] = {"equal": new_constraints[keys[i]] / counter}; } // Give the model a fake thing to optimize on model.optimize = "cheater-" + Math.random(); model.opType = "max"; // And add the fake attribute to the variables // in the model for(i in model.variables){ model.variables[i].cheater = 1; } // Build out the object with all attributes for(i in pareto){ for(x in pareto[i]){ obj[x] = obj[x] || {min: 1e99, max: -1e99}; } } // Give each pareto a full attribute list // while getting the max and min values // for each attribute for(i in obj){ for(x in pareto){ if(pareto[x][i]){ if(pareto[x][i] > obj[i].max){ obj[i].max = pareto[x][i]; } if(pareto[x][i] < obj[i].min){ obj[i].min = pareto[x][i]; } } else { pareto[x][i] = 0; obj[i].min = 0; } } } // Solve the model for the midpoints tmp = solver.Solve(model, undefined, undefined, true); return { midpoint: tmp, vertices: pareto, ranges: obj }; };