javascript-lp-solver
Version:
Easy to use, JSON oriented Linear Programming and Mixed Int. Programming Solver
256 lines (177 loc) • 9.47 kB
HTML
<html lang="en" class=" is-copy-enabled">
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Language" content="en">
<meta name="viewport" content="width=1020">
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<script src="/prod/solver.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" charset="utf-8"></script>
<script type="text/javascript">
window.models = [];
$(document).ready(function(){
mocha.setup('bdd');
mocha.reporter("html");
let assert = chai.assert;
$.getJSON("/test/test-sanity/", function(problems){
for(var problem in problems){
$.getJSON("/test/test-sanity/" + problems[problem], function(model){
window.models.push(model);
//result = solver.Solve(model);
});
}
});
setTimeout(function(){
console.log("KABOOM!");
// Build out our test suite
describe("Test Suite of EXPECTED results to ACTUAL results:",
function () {
//var solver = require("../src/solver");
// Iterate over each problem in the suite
models.forEach(function (jsonModel) {
// Generic "Should" Statement
// (should come up with a better test scheme and description...)
// Also...
// How big are you?
var _variables = Object.keys(jsonModel.variables).length;
var _constraints = Object.keys(jsonModel.constraints).length;
var _ints = Object.keys(jsonModel.ints || {}).length;
it("Model Name: " + jsonModel.name + "[ " + _variables +" variables | " + _constraints + " constraints | " + _ints + " integers] => ",
function () {
// Look to see if the JSON Model's "expects"
// has a "_timeout". If so, set it and delete it (to not
// interfere with any test expectations)
if(jsonModel.expects._timeout){
this.timeout(jsonModel.expects._timeout);
delete jsonModel.expects._timeout;
}
// Each problem has its correct answer attached to its
// JSON as an "expects" object
//
// TODO: This is where you can handle the type
// of solver used.
//
// Say if the model has an "external" attribute,
// use whatever the external attribute tells it to
// do...
var expectedResult = jsonModel.expects,
obtainedResult = solver.Solve(jsonModel);
// Compare what we expect the problem to be
// to what solver comes up with
assertSolution(
obtainedResult,
expectedResult
);
});
});
});
mocha.run();
},3000);
});
// Step 3. [kind of]) Build a function to evaluate the results of the model
// and its expected results..
//
//
function assertSolution(solutionA, solutionB) {
let assert = chai.assert;
//
// Quick and dirty way to compare 2 objects
// Excluding other crap we throw in the solution
// for sake of legacy or ease...
//
// 0.) Check Feasibility as to not burn cycles needlessly...
// Also...all models must have a "feasible" attribute...
//
// TODO: Enforce that all 'solve' methods return a 'feasible'
// attribute
//
if(solutionA.feasible === false && solutionB.feasible === false){
// Skip work, and return that the model couldn't solve it...
//
return assert.deepEqual(true, true);
} else {
// 1.) Remove aforementioned noise...
["isIntegral","bounded"].forEach(function(noise){
delete solutionA[noise];
delete solutionB[noise];
});
// 2.) To keep track of what we've already hit...
var keys = {},
fail_actual = {},
fail_expects = {};
// 3.) Build an object with the keys from the 'expected' results
// and the actual results...
Object.keys(solutionA)
.forEach(function(key){
keys[key] = 1;
});
Object.keys(solutionB)
.forEach(function(key){
keys[key] = 1;
});
// 4.) Loop through each UNIQUE key the models provided,
Object.keys(keys).forEach(function(key){
// 5.) Format the result provided
//
// n.b. for all intents and purposes, an attribute being 0
// is essentially the same as it not being there ('undefined')
// thus, here, undefined *IS* 0...
//
var temp_a = {},
temp_b = {};
if(typeof solutionB[key] === "undefined"){
temp_a[key] = solutionA[key];
temp_b[key] = 0;
} else if(typeof solutionA[key] === "undefined"){
temp_b[key] = solutionB[key];
temp_a[key] = 0;
} else if(key === "feasible"){
//
// Clean this crap up.
// This is lazy.
// *sigh*
// ...
// Do Nothing...
var fake = true;
} else {
temp_a[key] = solutionA[key].toFixed(6);
// Need to be able to handle "Infinity"
//
temp_b[key] = parseFloat(solutionB[key]).toFixed(6);
}
try{
assert.deepEqual(temp_a, temp_b);
} catch(e){
fail_actual[key] = solutionA[key];
fail_expects[key] = solutionB[key];
}
});
// Lets be a little more liberal with this, no?
// Given numeric instability and all...
if(Object.keys(fail_actual).length > 0 || Object.keys(fail_expects).length){
// If the results are the same (more or less; its ok)
//
if(typeof fail_actual["results"] === "undefined" || typeof fail_expects["results"] === "undefined"){
// Warn the user...
//
console.warn("THESE ARE DIFFERENT!!!",fail_actual, fail_expects);
return assert.deepEqual(1,1);
} else {
// This is a bad fail, log and bomb...
console.warn("THESE ARE FAILURES!!!",fail_actual, fail_expects);
return assert.deepEqual(fail_actual, fail_expects);
}
} else {
return assert.deepEqual(fail_actual, fail_expects);
}
}
}
</script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>