split system to independent decoupled subsystem

This commit is contained in:
Val Erastov 2015-02-23 23:00:03 -08:00
parent f79527efdc
commit 3889e6fdd2
8 changed files with 208 additions and 209 deletions

View file

@ -258,7 +258,7 @@ optim.inv = function inv(x) {
}
// this is Gauss-Newton least square algorithm with trust region(dog leg) control/
optim.dog_leg = function(subsys) {
optim.dog_leg = function(subsys, rough) {
var tolg=1e-80, tolx=1e-80, tolf=1e-10;
@ -361,7 +361,7 @@ optim.dog_leg = function(subsys) {
while (stop === 0) {
// check if finished
if (fx_inf <= tolf || err <= tolf) // Success
if (fx_inf <= tolf || (rough && err <= tolf)) // Success
stop = 1;
else if (g_inf <= tolg)
stop = 2;
@ -472,8 +472,11 @@ optim.dog_leg = function(subsys) {
iter++;
}
return (stop == 1) ? 'Success' : 'Failed';
return {
evalCount : iter,
error : err,
returnCode : stop
};
};

View file

@ -780,7 +780,7 @@ TCAD.TWO.DragTool.prototype.mousemove = function(e) {
var checkY = this.ref.y;
this.obj.translate(dx, dy);
if (!e.shiftKey) {
this.solveRequest(2);
this.solveRequest(true);
}
this.errorX = (this.ref.x - dx) - checkX;
@ -798,7 +798,7 @@ TCAD.TWO.DragTool.prototype.mousedown = function(e) {
};
TCAD.TWO.DragTool.prototype.mouseup = function(e) {
this.solveRequest(0);
this.solveRequest(false);
this.viewer.refresh();
this.viewer.toolManager.releaseControl();
};
@ -806,7 +806,7 @@ TCAD.TWO.DragTool.prototype.mouseup = function(e) {
TCAD.TWO.DragTool.prototype.mousewheel = function(e) {
};
TCAD.TWO.DragTool.prototype.solveRequest = function(fineLevel) {
TCAD.TWO.DragTool.prototype.solveRequest = function(rough) {
var locked;
if (this.obj._class === 'TCAD.TWO.EndPoint') {
@ -823,7 +823,7 @@ TCAD.TWO.DragTool.prototype.solveRequest = function(fineLevel) {
locked = [];
}
this.solver = this.viewer.parametricManager.prepare(locked);
this.solver.solve(fineLevel);
this.solver.solve(rough, 1);
this.solver.sync();
};

View file

@ -205,8 +205,6 @@ TCAD.parametric.lock2Equals2 = function(constrs, locked) {
return _locked;
};
TCAD.parametric._alg = 5;
TCAD.parametric.diagnose = function(sys) {
var jacobian = sys.makeJacobian();
var qr = new TCAD.math.QR(jacobian);
@ -224,15 +222,6 @@ TCAD.parametric.prepare = function(constrs, locked, aux, alg) {
var sys = new TCAD.parametric.System(constrs);
function arr(size) {
var out = [];
out.length = size;
for (var i = 0; i < size; ++i) {
out[i] = 0;
}
return out;
}
var model = function(point) {
sys.setParams(point);
return sys.getValues();
@ -242,62 +231,22 @@ TCAD.parametric.prepare = function(constrs, locked, aux, alg) {
sys.setParams(point);
return sys.makeJacobian();
};
alg = TCAD.parametric._alg;
var _point = [];
function solve(fineLevel) {
function solve(rough, alg) {
if (constrs.length == 0) return;
if (sys.params.length == 0) return;
if (TCAD.parametric.diagnose(sys).conflict) {
console.log("Conflicting or redundant constraints. Please fix your system.");
return;
}
if (alg > 0) {
switch (alg) {
case 1:
var res = TCAD.math.solve_BFGS(sys, 1e-4, 1e-4);
console.log(res);
break;
case 2:
TCAD.math.solve_TR(sys);
break;
case 3:
TCAD.math.noptim(sys);
break;
case 4:
TCAD.math.solve_UNCMIN(sys);
break;
case 5:
if (optim.dog_leg(sys) !== 0) {
//alg = -5;
//solve(fineLevel);
}
break;
}
return sys;
}
var opt = new LMOptimizer(sys.getParams(), arr(sys.constraints.length), model, jacobian);
var eps;
fineLevel = 1;
switch (fineLevel) {
case 1:
eps = 0.001;
opt.init0(eps, eps, eps);
break;
switch (alg) {
case 2:
eps = 0.1;
opt.init0(eps, eps, eps);
break;
default:
eps = 0.00000001;
opt.init0(eps, eps, eps);
return TCAD.parametric.solve_lm(sys, model, jacobian, rough);
case 1:
default:
return optim.dog_leg(sys, rough);
}
var res = opt.doOptimize();
sys.setParams(res[0]);
// console.log("Solved with error: " + sys.error());
return res;
}
var systemSolver = {
system : sys,
@ -308,7 +257,25 @@ TCAD.parametric.prepare = function(constrs, locked, aux, alg) {
}
}
};
return systemSolver;
};
TCAD.parametric.solve_lm = function(sys, model, jacobian, rough) {
var opt = new LMOptimizer(sys.getParams(), TCAD.math.vec(sys.constraints.length), model, jacobian);
opt.evalMaximalCount = 100 * sys.params.length;
var eps = rough ? 0.001 : 0.00000001;
opt.init0(eps, eps, eps);
var returnCode = 1;
try {
var res = opt.doOptimize();
} catch (e) {
returnCode = 2;
}
sys.setParams(res[0]);
return {
evalCount : opt.evalCount,
error : sys.error(),
returnCode : returnCode
};
};

View file

@ -88,11 +88,15 @@ TCAD.App2D = function() {
}
var constrs = sketch.constraints = [];
var sys = app.viewer.parametricManager.system;
for (var i = 0; i < sys.length; ++i) {
if (!sys[i].aux) {
constrs.push(app.serializeConstr(sys[i]));
var subSystems = app.viewer.parametricManager.subSystems;
for (var j = 0; j < subSystems.length; j++) {
var sub = subSystems[j];
for (var i = 0; i < sub.constraints.length; ++i) {
if (!sub.constraints[i].aux) {
constrs.push(app.serializeConstr(sub.constraints[i]));
}
}
}
var sketchData = JSON.stringify(sketch);
console.log(sketchData);
@ -150,17 +154,7 @@ TCAD.App2D = function() {
});
this.registerAction('solve', "Solve System", function () {
app.viewer.parametricManager.solve([], 0);
app.viewer.refresh();
});
this.registerAction('solveStep', "Solve Step", function () {
app.viewer.parametricManager.solve([], 0, 3);
app.viewer.refresh();
});
this.registerAction('stepUNCMIN', "Solve Step UNCMIN", function () {
app.viewer.parametricManager.solve([], 0, 4);
app.viewer.parametricManager.solve();
app.viewer.refresh();
});
@ -289,7 +283,7 @@ TCAD.App2D.prototype.loadSketch = function(sketch) {
if (sketch.constraints !== undefined) {
for (var i = 0; i < sketch.constraints.length; ++i) {
var c = this.parseConstr(sketch.constraints[i], index);
this.viewer.parametricManager.system.push(c);
this.viewer.parametricManager._add(c);
}
this.viewer.parametricManager.notify();
}

View file

@ -1,9 +1,15 @@
TCAD.TWO.Constraints = {};
TCAD.TWO.SubSystem = function() {
this.alg = 1;
this.error = 0;
this.reduce = false;
this.constraints = [];
};
TCAD.TWO.ParametricManager = function(viewer) {
this.viewer = viewer;
this.system = [];
this.REQUEST_COUNTER = 0;
this.subSystems = [];
this.listeners = [];
};
@ -14,27 +20,74 @@ TCAD.TWO.ParametricManager.prototype.notify = function(event) {
}
};
TCAD.TWO.ParametricManager.prototype.add = function(constr) {
this.system.push(constr);
this.solve([], 0.00000001, 5);
TCAD.TWO.ParametricManager.prototype.findComponents = function(constr) {
if (this.subSystems.length === 0) {
this.subSystems.push(new TCAD.TWO.SubSystem());
}
return [0];
};
TCAD.TWO.ParametricManager.prototype.tune = function(subSystem) {
};
TCAD.TWO.ParametricManager.prototype._add = function(constr) {
var subSystemIds = this.findComponents(constr);
var subSystem;
switch (subSystemIds.length) {
case 0:
subSystem = new TCAD.TWO.SubSystem();
this.subSystems.push(subSystem);
break;
case 1:
subSystem = this.subSystems[subSystemIds[0]];
break;
default:
subSystem = this.subSystems[subSystemIds[0]];
for (var i = 1; i < subSystemIds.length; i++) {
var toMerge = subSystemIds[i];
for (var j = 0; j < toMerge.constraints.length; j++) {
subSystem.push(toMerge.constraints[j]);
}
}
break;
}
subSystem.constraints.push(constr);
};
TCAD.TWO.ParametricManager.prototype.refresh = function() {
this.solve();
this.notify();
this.viewer.refresh();
};
TCAD.TWO.ParametricManager.prototype.add = function(constr) {
this._add(constr);
this.refresh();
};
TCAD.TWO.ParametricManager.prototype.addAll = function(constrs) {
for (var i = 0; i < constrs.length; i++) {
this._add(constrs[i]);
}
this.refresh();
};
TCAD.TWO.ParametricManager.prototype.remove = function(constr) {
for (var i = 0; i < this.system.length; ++i) {
var p = this.system[i];
if (p === constr) {
this.system.splice(i, 1);
if (p.NAME === 'coi') {
this.unlinkObjects(p.a, p.b);
for (var j = 0; j < this.subSystems.length; j++) {
var sub = this.subSystems[j];
for (var i = 0; i < sub.constraints.length; ++i) {
var p = sub.constraints[i];
if (p === constr) {
sub.constraints(i, 1);
if (p.NAME === 'coi') {
this.unlinkObjects(p.a, p.b);
}
break;
}
break;
}
}
this.solve();
this.notify();
this.viewer.refresh();
this.refresh();
};
TCAD.TWO.ParametricManager.prototype.removeConstraintsByObj = function(obj) {
@ -44,40 +97,41 @@ TCAD.TWO.ParametricManager.prototype.removeConstraintsByObj = function(obj) {
};
TCAD.TWO.ParametricManager.prototype.removeConstraintsByParams = function(ownedParams) {
var toRemove = [];
for (var i = 0; i < this.system.length; ++i) {
var sdataArr = this.system[i].getSolveData();
for (var j = 0; j < sdataArr.length; j++) {
var sdata = sdataArr[j];
var params = sdata[1];
MAIN:
for (var j = 0; j < ownedParams.length; ++j) {
for (var k = 0; k < params.length; ++k) {
if (ownedParams[j].id === params[k].id) {
toRemove.push(i);
break MAIN;
for (var s = 0; s < this.subSystems.length; s++) {
var toRemove = [];
var sub = this.subSystems[s];
for (var i = 0; i < sub.constraints.length; ++i) {
var sdataArr = sub.constraints[i].getSolveData();
for (var j = 0; j < sdataArr.length; j++) {
var sdata = sdataArr[j];
var params = sdata[1];
MAIN:
for (var oi = 0; oi < ownedParams.length; ++oi) {
for (var k = 0; k < params.length; ++k) {
if (ownedParams[oi].id === params[k].id) {
toRemove.push(i);
break MAIN;
}
}
}
}
}
toRemove.sort();
for (var i = toRemove.length - 1; i >= 0 ; --i) {
sub.constraints.splice( toRemove[i], 1);
}
}
toRemove.sort();
for (var i = toRemove.length - 1; i >= 0 ; --i) {
this.system.splice( toRemove[i], 1);
}
this.notify();
};
TCAD.TWO.ParametricManager.prototype.lock = function(objs) {
var p = this._fetchPoints(objs);
for (var i = 0; i < p.length; ++i) {
this.system.push(new TCAD.TWO.Constraints.Lock(p[i], { x : p[i].x, y : p[i].y} ));
this._add(new TCAD.TWO.Constraints.Lock(p[i], { x : p[i].x, y : p[i].y} ));
}
this.solve();
this.notify();
this.viewer.refresh();
this.refresh();
};
TCAD.TWO.ParametricManager.prototype.vertical = function(objs) {
@ -109,12 +163,10 @@ TCAD.TWO.ParametricManager.prototype.rr = function(objs) {
var arcs = this._fetchArkCirc(objs, 2);
var prev = arcs[0];
for (var i = 1; i < arcs.length; ++i) {
this.system.push(new TCAD.TWO.Constraints.RR(prev, arcs[i]));
this._add(new TCAD.TWO.Constraints.RR(prev, arcs[i]));
prev = arcs[i];
}
this.solve();
this.notify();
this.viewer.refresh();
this.refresh();
};
TCAD.TWO.ParametricManager.prototype.p2lDistance = function(objs, promptCallback) {
@ -164,11 +216,9 @@ TCAD.TWO.ParametricManager.prototype.radius = function(objs, promptCallback) {
promptDistance = Number(promptDistance);
if (promptDistance == promptDistance) { // check for NaN
for (var i = 0; i < arcs.length; ++i) {
this.system.push(new TCAD.TWO.Constraints.Radius(arcs[i], promptDistance));
this._add(new TCAD.TWO.Constraints.Radius(arcs[i], promptDistance));
}
this.solve();
this.notify();
this.viewer.refresh();
this.refresh();
}
}
};
@ -180,9 +230,8 @@ TCAD.TWO.ParametricManager.prototype.linkObjects = function(objs) {
objs[i].x = objs[last].x;
objs[i].y = objs[last].y;
var c = new TCAD.TWO.Constraints.Coincident(objs[i], objs[last]);
this.system.push(c);
this._add(c);
}
this.notify();
};
@ -209,82 +258,65 @@ TCAD.TWO.ParametricManager.prototype.coincident = function(objs) {
};
TCAD.TWO.ParametricManager.prototype.getSolveData = function() {
var sdata = [];
for (i = 0; i < this.system.length; ++i) {
var data = this.system[i].getSolveData();
for (var j = 0; j < data.length; ++j) {
data[j].push(this.system[i].reducible !== undefined);
sdata.push(data[j]);
}
var sdata = [];
for (var i = 0; i < this.subSystems.length; i++) {
this.__getSolveData(this.subSystems[i], sdata);
}
return sdata;
};
TCAD.TWO.ParametricManager.prototype.solve1 = function(locked, onSolved) {
var pdict = {};
var refsCounter = 0;
var params = [];
var i;
var data = {params : [], constraints: [], locked: []};
var sdataArr = this.getSolveData();
for (var j = 0; j < sdataArr.length; j++) {
var sdata = sdataArr[j];
var prefs = [];
var constr = [sdata[0], prefs, sdata[2]];
data.constraints.push(constr);
for (var p = 0; p < sdata[1].length; ++p) {
var param = sdata[1][p];
var pref = pdict[param.id];
if (pref === undefined) {
pref = refsCounter++;
data.params.push(param.get());
params.push(param);
pdict[param.id] = pref;
}
prefs.push(pref);
TCAD.TWO.ParametricManager.prototype.__getSolveData = function(subSystem, out) {
for (var i = 0; i < subSystem.constraints.length; ++i) {
var constraint = subSystem.constraints[i];
var data = constraint.getSolveData();
for (var j = 0; j < data.length; ++j) {
data[j].push(constraint.reducible !== undefined);
out.push(data[j]);
}
}
return out;
};
if (locked !== undefined) {
for (i = 0; i < locked.length; ++i) {
var lp = pdict[locked[i].id];
if (lp !== undefined) {
data.locked.push(lp);
TCAD.TWO.ParametricManager.prototype.solve = function() {
var solver = this.prepare([]);
solver.solve(false);
solver.sync();
};
TCAD.TWO.ParametricManager.prototype.prepare = function(locked) {
var solvers = [];
for (var i = 0; i < this.subSystems.length; i++) {
solvers.push(this._prepare(locked, this.subSystems[i]));
}
var subSystems = this.subSystems;
return {
solve : function(rough) {
for (var i = 0; i < solvers.length; i++) {
var alg = subSystems[i].alg;
if (solvers[i].solve(rough, alg) !== 1) {
alg = alg == 1 ? 2 : 1;
if (solvers[i].solve(rough, alg) == 1) {
subSystems[i].alg = alg;
}
}
}
},
sync : function() {
for (var i = 0; i < solvers.length; i++) {
solvers[i].sync();
}
},
updateLock : function() {
for (var i = 0; i < solvers.length; i++) {
solvers[i].updateLock();
}
}
}
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
var pm = this;
var request = {reqId : this.REQUEST_COUNTER ++, system : data};
xhr.onreadystatechange=function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var response = JSON.parse(xhr.responseText);
if (response.reqId != pm.REQUEST_COUNTER - 1) {
return;
}
for (var p = 0; p < response.params.length; ++p) {
params[p].set(response.params[p]);
}
if (onSolved !== undefined) {
onSolved();
}
pm.viewer.refresh();
}
};
xhr.open("POST", "http://localhost:8080/solve", true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(JSON.stringify(request));
};
TCAD.TWO.ParametricManager.prototype.solve = function(locked, fineLevel, alg) {
var solver = this.prepare(locked, alg);
solver.solve(fineLevel);
solver.sync()
};
TCAD.TWO.ParametricManager.prototype.prepare = function(locked, alg) {
TCAD.TWO.ParametricManager.prototype._prepare = function(locked, subSystem) {
var pdict = {};
var params;
@ -298,7 +330,7 @@ TCAD.TWO.ParametricManager.prototype.prepare = function(locked, alg) {
function peq(p1, p2) {
return Math.abs(p1.get() - p2.get()) <= 0.000001
}
var system = this.getSolveData();
var system = this.__getSolveData(subSystem, []);
var tuples = [];
for (i = 0; i < system.length; ++i) {
var c = system[i];
@ -416,7 +448,7 @@ TCAD.TWO.ParametricManager.prototype.prepare = function(locked, alg) {
var _constr = TCAD.constraints.create(sdata[0], params, sdata[2]);
_constrs.push(_constr);
if (sdata[0] === 'equal') {
equals.push(this.system[i]);
equals.push(system[i]);
}
}
@ -430,8 +462,8 @@ TCAD.TWO.ParametricManager.prototype.prepare = function(locked, alg) {
}
var lockedValues = [];
var solver = TCAD.parametric.prepare(_constrs, _locked, aux, alg);
function solve(fineLevel) {
var solver = TCAD.parametric.prepare(_constrs, _locked, aux);
function solve(rough, alg) {
if (_locked.length != 0) {
for (p = 0; p < locked.length; ++p) {
lockedValues[p] = locked[p].get() ;
@ -442,7 +474,7 @@ TCAD.TWO.ParametricManager.prototype.prepare = function(locked, alg) {
_p = pdict[p];
_p.set(_p._backingParam.get());
}
solver.solveSystem(fineLevel);
solver.solveSystem(rough, alg);
}
var viewer = this.viewer;
function sync() {

View file

@ -67,8 +67,8 @@ TCAD.TWO.Arc.prototype.normalDistance = function(aim) {
TCAD.TWO.Arc.prototype.stabilize = function(viewer) {
this.r.set(this.distanceA());
viewer.parametricManager.system.push(new TCAD.TWO.Constraints.P2PDistanceV(this.b, this.c, this.r));
viewer.parametricManager.system.push(new TCAD.TWO.Constraints.P2PDistanceV(this.a, this.c, this.r));
viewer.parametricManager._add(new TCAD.TWO.Constraints.P2PDistanceV(this.b, this.c, this.r));
viewer.parametricManager._add(new TCAD.TWO.Constraints.P2PDistanceV(this.a, this.c, this.r));
};
TCAD.TWO.AddArcTool = function(viewer, layer) {

View file

@ -58,15 +58,15 @@ TCAD.TWO.EditCircleTool.prototype.mousemove = function(e) {
var r = TCAD.math.distance(p.x, p.y, this.circle.c.x, this.circle.c.y);
this.circle.r.set(r);
if (!e.shiftKey) {
this.solveRequest(2);
this.solveRequest(true);
}
this.viewer.refresh();
}
};
TCAD.TWO.EditCircleTool.prototype.solveRequest = function(fineLevel) {
TCAD.TWO.EditCircleTool.prototype.solveRequest = function(rough) {
this.solver = this.viewer.parametricManager.prepare([this.circle.r]);
this.solver.solve(fineLevel);
this.solver.solve(rough, 1);
this.solver.sync();
};
@ -79,7 +79,7 @@ TCAD.TWO.EditCircleTool.prototype.mouseup = function(e) {
this.layer.objects.push(this.circle);
this.viewer.refresh();
} else {
this.solveRequest(0);
this.solveRequest(false);
this.viewer.refresh();
this.viewer.toolManager.releaseControl();
}

View file

@ -227,10 +227,13 @@
var constrList = new TCAD.ui.List($('#constrs'), {
items : function() {
var theItems = [];
for (var i = 0; i < pm.system.length; ++i) {
var constr = pm.system[i];
if (constr.aux !== true) {
theItems.push({name : constr.NAME, constr : constr});
for (var j = 0; j < pm.subSystems.length; j++) {
var sub = pm.subSystems[j];
for (var i = 0; i < sub.constraints.length; ++i) {
var constr = sub.constraints[i];
if (constr.aux !== true) {
theItems.push({name : constr.NAME, constr : constr});
}
}
}
return theItems;