mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 08:25:19 +01:00
working on optimization
This commit is contained in:
parent
d796aea532
commit
aade377b1b
11 changed files with 5099 additions and 23 deletions
|
|
@ -57,10 +57,9 @@ TCAD.parametric.System.prototype.makeJacobian = function() {
|
|||
return jacobi;
|
||||
};
|
||||
|
||||
// ∇f(x) = E rj(x) ∇rj(x) = J(x)T r(x)
|
||||
TCAD.parametric.System.prototype.calcGrad = function(out) {
|
||||
TCAD.parametric.System.prototype.calcGrad_ = function(out) {
|
||||
var i;
|
||||
for (i = 0; i < out.length; ++i) {
|
||||
for (i = 0; i < out.length || i < this.params.length; ++i) {
|
||||
out[i][0] = 0;
|
||||
}
|
||||
|
||||
|
|
@ -74,10 +73,30 @@ TCAD.parametric.System.prototype.calcGrad = function(out) {
|
|||
for (var p = 0; p < cParams.length; p++) {
|
||||
var param = cParams[p];
|
||||
var j = param.j;
|
||||
out[j][0] += this.constraints[i].error() * grad[p]; // (10.4)
|
||||
out[j][0] += this.constraints[i].error() * grad[p]; // (10.4)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TCAD.parametric.System.prototype.calcGrad = function(out) {
|
||||
var i;
|
||||
for (i = 0; i < out.length || i < this.params.length; ++i) {
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
for (i=0; i < this.constraints.length; i++) {
|
||||
var c = this.constraints[i];
|
||||
|
||||
var cParams = c.params;
|
||||
var grad = [];
|
||||
c.gradient(grad);
|
||||
|
||||
for (var p = 0; p < cParams.length; p++) {
|
||||
var param = cParams[p];
|
||||
var j = param.j;
|
||||
out[j] += this.constraints[i].error() * grad[p]; // (10.4)
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TCAD.parametric.System.prototype.fillParams = function(out) {
|
||||
|
|
@ -112,7 +131,7 @@ TCAD.parametric.System.prototype.errorSquare = function() {
|
|||
var t = this.constraints[i].error();
|
||||
error += t * t;
|
||||
}
|
||||
return error * .5;
|
||||
return error * 0.5;
|
||||
};
|
||||
|
||||
TCAD.parametric.System.prototype.getValues = function() {
|
||||
|
|
@ -152,7 +171,7 @@ TCAD.parametric.lock2 = function(constrs, locked) {
|
|||
}
|
||||
};
|
||||
|
||||
TCAD.parametric.solve = function(constrs, locked, fineLevel) {
|
||||
TCAD.parametric.solve = function(constrs, locked, fineLevel, alg) {
|
||||
|
||||
if (constrs.length == 0) return;
|
||||
|
||||
|
|
@ -183,9 +202,24 @@ TCAD.parametric.solve = function(constrs, locked, fineLevel) {
|
|||
return sys.makeJacobian();
|
||||
};
|
||||
|
||||
// var res = TCAD.math.solve_BFGS(sys, 1e-4, 1e-4);
|
||||
// console.log(res);
|
||||
// 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;
|
||||
}
|
||||
return sys;
|
||||
}
|
||||
|
||||
var opt = new LMOptimizer(sys.getParams(), arr(sys.constraints.length), model, jacobian);
|
||||
var eps;
|
||||
|
|
@ -206,4 +240,5 @@ TCAD.parametric.solve = function(constrs, locked, fineLevel) {
|
|||
var res = opt.doOptimize();
|
||||
sys.setParams(res[0]);
|
||||
// console.log("Solved with error: " + sys.error());
|
||||
return sys;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -120,7 +120,18 @@ TCAD.App2D = function() {
|
|||
solve : function() {
|
||||
app.viewer.parametricManager.solve([], 0);
|
||||
app.viewer.refresh();
|
||||
},
|
||||
|
||||
step : function() {
|
||||
app.viewer.parametricManager.solve([], 0, 3);
|
||||
app.viewer.refresh();
|
||||
},
|
||||
|
||||
stepUNCMIN : function() {
|
||||
app.viewer.parametricManager.solve([], 0, 4);
|
||||
app.viewer.refresh();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
actionsF.add(actions, 'addSegment');
|
||||
|
|
@ -140,6 +151,8 @@ TCAD.App2D = function() {
|
|||
actionsF.add(actions, 'tangent');
|
||||
actionsF.add(actions, 'lock');
|
||||
actionsF.add(actions, 'solve');
|
||||
actionsF.add(actions, 'step');
|
||||
actionsF.add(actions, 'stepUNCMIN');
|
||||
actionsF.add(actions, 'analyze');
|
||||
actionsF.open();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
TCAD.math = {};
|
||||
|
||||
TCAD.math._arr = function(size) {
|
||||
var out = [];
|
||||
out.length = size;
|
||||
for (var i = 0; i < size; ++i) {
|
||||
out[i] = 0;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.distance = function(x1, y1, x2, y2) {
|
||||
var dx = x1 - x2;
|
||||
var dy = y1 - y2;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
};
|
||||
127
web/app/math/matrix.js
Normal file
127
web/app/math/matrix.js
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
|
||||
TCAD.math.Matrix = function(r, c) {
|
||||
this.data = [];
|
||||
this.rSize = r;
|
||||
this.cSize = c;
|
||||
for (var i = 0; i < r; i++) {
|
||||
this.data[i] = TCAD.math._arr(c)
|
||||
}
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.identity = function() {
|
||||
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
this.data[i][j] = i === j ? 1 : 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.subtract = function(m) {
|
||||
var out = new TCAD.math.Matrix(this.rSize, this.cSize);
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
out.data[i][j] = this.data[i][j] - m.data[i][j];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.add = function(m) {
|
||||
var out = new TCAD.math.Matrix(this.rSize, this.cSize);
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
out.data[i][j] = this.data[i][j] + m.data[i][j];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.multiply = function(m) {
|
||||
|
||||
var nRows = this.rSize;
|
||||
var nCols = m.cSize;
|
||||
var nSum = this.cSize;
|
||||
|
||||
var out = new TCAD.math.Matrix(nRows, nCols);
|
||||
|
||||
var outData = out.data;
|
||||
// Will hold a column of "m".
|
||||
var mCol = TCAD.math._arr(nSum);
|
||||
var mData = m.data;
|
||||
|
||||
// Multiply.
|
||||
for (var col = 0; col < nCols; col++) {
|
||||
// Copy all elements of column "col" of "m" so that
|
||||
// will be in contiguous memory.
|
||||
for (var mRow = 0; mRow < nSum; mRow++) {
|
||||
mCol[mRow] = mData[mRow][col];
|
||||
}
|
||||
|
||||
for (var row = 0; row < nRows; row++) {
|
||||
var dataRow = this.data[row];
|
||||
var sum = 0;
|
||||
for (var i = 0; i < nSum; i++) {
|
||||
sum += dataRow[i] * mCol[i];
|
||||
}
|
||||
outData[row][col] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.scalarMultiply = function(s) {
|
||||
var out = new TCAD.math.Matrix(this.rSize, this.cSize);
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
out.data[i][j] = this.data[i][j] * s;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.transpose = function() {
|
||||
var out = new TCAD.math.Matrix(this.cSize, this.rSize);
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
out.data[j][i] = this.data[i][j];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.copy = function() {
|
||||
var out = new TCAD.math.Matrix(this.rSize, this.cSize);
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
for (var j = 0; j < this.cSize; j++) {
|
||||
out.data[i][j] = this.data[i][j];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.dot = function(v) {
|
||||
var vData = v.data;
|
||||
var dot = 0;
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
dot += this.data[i][0] * vData[i][0];
|
||||
}
|
||||
return dot;
|
||||
};
|
||||
|
||||
TCAD.math.Matrix.prototype.norm = function(v) {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < this.rSize; i++) {
|
||||
var a = this.data[i][0];
|
||||
sum += a * a;
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
};
|
||||
|
||||
TCAD.math.Vector = function(n) {
|
||||
TCAD.math.Matrix.call(this, n, 1);
|
||||
};
|
||||
|
||||
TCAD.TWO.utils.extend(TCAD.math.Vector, TCAD.math.Matrix);
|
||||
|
||||
59
web/app/math/noptim.js
Normal file
59
web/app/math/noptim.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
numeric.grdec = function uncmin(f,x0,tol,gradient,maxit,callback,options) {
|
||||
var grad = numeric.gradient;
|
||||
if(typeof options === "undefined") { options = {}; }
|
||||
if(typeof tol === "undefined") { tol = 1e-8; }
|
||||
if(typeof gradient === "undefined") { gradient = function(x) { return grad(f,x); }; }
|
||||
if(typeof maxit === "undefined") maxit = 1000;
|
||||
x0 = numeric.clone(x0);
|
||||
var n = x0.length;
|
||||
var f0 = f(x0),f1,df0;
|
||||
if(isNaN(f0)) throw new Error('uncmin: f(x0) is a NaN!');
|
||||
var max = Math.max, norm2 = numeric.norm2;
|
||||
tol = max(tol,numeric.epsilon);
|
||||
var step,g0,g1,H1 = options.Hinv || numeric.identity(n);
|
||||
var dot = numeric.dot, inv = numeric.inv, sub = numeric.sub, add = numeric.add, ten = numeric.tensor, div = numeric.div, mul = numeric.mul;
|
||||
var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg;
|
||||
var it=0,i,s,x1,y,Hy,Hs,ys,i0,t,nstep,t1,t2;
|
||||
var msg = "";
|
||||
g0 = gradient(x0);
|
||||
while(it<maxit) {
|
||||
if(typeof callback === "function") { if(callback(it,x0,f0,g0,H1)) { msg = "Callback returned true"; break; } }
|
||||
if(!all(isfinite(g0))) { msg = "Gradient has Infinity or NaN"; break; }
|
||||
step = neg(dot(H1,g0));
|
||||
if(!all(isfinite(step))) { msg = "Search direction has Infinity or NaN"; break; }
|
||||
nstep = norm2(step);
|
||||
if(nstep < tol) { msg="Newton step smaller than tol"; break; }
|
||||
t = 1;
|
||||
df0 = dot(g0,step);
|
||||
// line search
|
||||
x1 = x0;
|
||||
while(it < maxit) {
|
||||
if(t*nstep < tol) { break; }
|
||||
s = mul(step,t);
|
||||
x1 = add(x0,s);
|
||||
f1 = f(x1);
|
||||
if(f1-f0 >= 0.1*t*df0 || isNaN(f1)) {
|
||||
t *= 0.5;
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; }
|
||||
if(it === maxit) { msg = "maxit reached during line search"; break; }
|
||||
g1 = gradient(x1);
|
||||
y = sub(g1,g0);
|
||||
ys = dot(y,s);
|
||||
Hy = dot(H1,y);
|
||||
// H1 = sub(add(H1,
|
||||
// mul(
|
||||
// (ys+dot(y,Hy))/(ys*ys),
|
||||
// ten(s,s) )),
|
||||
// div(add(ten(Hy,s),ten(s,Hy)),ys));
|
||||
x0 = x1;
|
||||
f0 = f1;
|
||||
g0 = g1;
|
||||
++it;
|
||||
}
|
||||
return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg};
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ TCAD.math.solve_BFGS = function(subsys, convergence, smallF) {
|
|||
if (xsize == 0) {
|
||||
return "Success";
|
||||
}
|
||||
|
||||
|
||||
var xdir; //Vector
|
||||
var B = new TCAD.math.Matrix(xsize, xsize);
|
||||
B.identity();
|
||||
|
|
@ -21,7 +21,7 @@ TCAD.math.solve_BFGS = function(subsys, convergence, smallF) {
|
|||
|
||||
// Initial unknowns vector and initial gradient vector
|
||||
TCAD.math.fillParams(subsys, x.data);
|
||||
subsys.calcGrad(grad.data);
|
||||
subsys.calcGrad_(grad.data);
|
||||
|
||||
// Initial search direction oposed to gradient (steepest-descent)
|
||||
xdir = grad.scalarMultiply(-1);
|
||||
|
|
@ -43,16 +43,16 @@ TCAD.math.solve_BFGS = function(subsys, convergence, smallF) {
|
|||
break;
|
||||
|
||||
y = grad.copy();
|
||||
subsys.calcGrad(grad.data);
|
||||
subsys.calcGrad_(grad.data);
|
||||
y = grad.subtract(y); // = grad - gradold
|
||||
|
||||
//Now calculate the BFGS update on B
|
||||
// TCAD.math.bfgsUpdate(B, h, y);
|
||||
TCAD.math.bfgsUpdateInverse(B, y, h);
|
||||
|
||||
// B = TCAD.math.bfgsUpdate(B, h, y);
|
||||
// B = TCAD.math.bfgsUpdateInverse(B, y, h);
|
||||
|
||||
xdir = B.multiply(grad).scalarMultiply(-1);
|
||||
// xdir = grad.scalarMultiply(-1);
|
||||
|
||||
TCAD.math.lineSearch(subsys, xdir);
|
||||
err = subsys.errorSquare();
|
||||
|
||||
|
|
@ -68,6 +68,130 @@ TCAD.math.solve_BFGS = function(subsys, convergence, smallF) {
|
|||
return "Failed";
|
||||
};
|
||||
|
||||
TCAD.math.solve_UNCMIN = function(subsys) {
|
||||
var x0 = [];
|
||||
subsys.fillParams(x0);
|
||||
|
||||
var f = function(x) {
|
||||
subsys.setParams(x);
|
||||
return subsys.errorSquare();
|
||||
};
|
||||
var gradient = function(x) {
|
||||
subsys.setParams(x);
|
||||
var grad = [];
|
||||
subsys.calcGrad(grad);
|
||||
return grad;
|
||||
};
|
||||
numeric.uncmin(f,x0,0.01,gradient,1000);
|
||||
};
|
||||
|
||||
|
||||
TCAD.math.solve_TR = function(subsys) {
|
||||
|
||||
var xsize = subsys.params.length;
|
||||
if (xsize == 0) {
|
||||
return "Success";
|
||||
}
|
||||
|
||||
var p; //Vector
|
||||
var B = new TCAD.math.Matrix(xsize, xsize);
|
||||
B.identity();
|
||||
var H = new TCAD.math.Matrix(xsize, xsize);
|
||||
H.identity();
|
||||
|
||||
var x = new TCAD.math.Vector(xsize);
|
||||
var grad = new TCAD.math.Vector(xsize);
|
||||
var h = new TCAD.math.Vector(xsize);
|
||||
var y = new TCAD.math.Vector(xsize);
|
||||
var pZero = new TCAD.math.Vector(xsize);
|
||||
|
||||
TCAD.math.fillParams(subsys, x.data);
|
||||
subsys.calcGrad_(grad.data);
|
||||
p = grad.scalarMultiply(-1);
|
||||
|
||||
var err = subsys.errorSquare();
|
||||
|
||||
var delta = 0.01;
|
||||
var deltaD = 1;
|
||||
var nu = 0.1;
|
||||
|
||||
|
||||
var maxIterNumber = 100 * xsize;
|
||||
var divergingLim = 1e6*err + 1e12;
|
||||
|
||||
|
||||
function m(fx, p, g, B) {
|
||||
return fx + g.dot(p) + 0.5 * p.dot(B.multiply(p)); //4.3
|
||||
}
|
||||
|
||||
function norm(x) {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < x.rSize; i++) {
|
||||
var a = x.data[i][0];
|
||||
sum += a * a;
|
||||
}
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
var tolx = 0.01;
|
||||
for (var iter=1; iter < maxIterNumber; iter++) {
|
||||
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
var fx = subsys.errorSquare();
|
||||
|
||||
if (fx <= tolx) break;
|
||||
//if (h.norm() <= tolx) break;
|
||||
// if (delta <= tolx*(tolx + x.norm())) break;
|
||||
if (fx > divergingLim || fx != fx) break;
|
||||
|
||||
p = TCAD.math.cauchyPoint(delta, grad, B, norm);
|
||||
|
||||
var xAddP = x.add(p);
|
||||
|
||||
TCAD.math.setParams2(subsys, xAddP.data);
|
||||
var fxAddP = subsys.errorSquare();
|
||||
|
||||
var r = ( fx - fxAddP ) / ( m(fx, pZero, grad, H) - m(fx, p, grad, H) );
|
||||
|
||||
if (r < 0.25) {
|
||||
delta = 0.25 * norm(p);
|
||||
} else {
|
||||
if (r > 0.75) {
|
||||
delta = Math.min(delta * 2, deltaD);
|
||||
}
|
||||
}
|
||||
|
||||
if (r > nu) {
|
||||
h = xAddP.subtract(x); // = x - xold
|
||||
x = xAddP;
|
||||
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
|
||||
y = grad.copy();
|
||||
subsys.calcGrad_(grad.data);
|
||||
y = grad.subtract(y);
|
||||
|
||||
//Now calculate the BFGS on B and H
|
||||
B = TCAD.math.bfgsUpdateInverse(B, y, h);
|
||||
H = TCAD.math.bfgsUpdate(H, y, h);
|
||||
}
|
||||
}
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
};
|
||||
|
||||
|
||||
TCAD.math.cauchyPoint = function(delta, grad, B, normaF) {
|
||||
var tau;
|
||||
var tauCondition = grad.dot(B.multiply(grad))
|
||||
var norm = normaF(grad);
|
||||
if (tauCondition <= 0) {
|
||||
tau = 1;
|
||||
} else {
|
||||
tau = Math.min((norm*norm*norm)/(delta*tauCondition), 1);
|
||||
}
|
||||
return grad.scalarMultiply(- tau * delta / norm) ;
|
||||
};
|
||||
|
||||
TCAD.math.fillParams = function(sys, out) {
|
||||
for (var p = 0; p < sys.params.length; p++) {
|
||||
out[p][0] = sys.params[p].get();
|
||||
|
|
@ -113,13 +237,14 @@ TCAD.math.bfgsUpdate = function(B, y, h) {
|
|||
|
||||
B = B.add( y_x_yT.scalarMultiply( 1 / yT_x_h ) );
|
||||
B = B.subtract( ( B_x_h.multiply(hT_x_B) ).scalarMultiply( 1./hT_x_B_x_h ) );
|
||||
return B;
|
||||
};
|
||||
|
||||
TCAD.math.solve_SD = function(subsys) {
|
||||
var i = 0;
|
||||
var grad = new TCAD.math.Vector(subsys.params.length);
|
||||
while (subsys.errorSquare() > 0.1 ) {
|
||||
subsys.calcGrad(grad.data);
|
||||
subsys.calcGrad_(grad.data);
|
||||
var xdir = grad.scalarMultiply(-1);
|
||||
TCAD.math.lineSearch(subsys, xdir);
|
||||
if (i ++ > 100) {
|
||||
|
|
@ -129,7 +254,7 @@ TCAD.math.solve_SD = function(subsys) {
|
|||
console.log(subsys.errorSquare());
|
||||
};
|
||||
|
||||
TCAD.math.lineSearch = function(subsys, xdir) {
|
||||
TCAD.math.lineSearchOrig = function(subsys, xdir) {
|
||||
|
||||
var f1,f2,f3,alpha1,alpha2,alpha3,alphaStar;
|
||||
|
||||
|
|
@ -199,11 +324,191 @@ TCAD.math.lineSearch = function(subsys, xdir) {
|
|||
//Take a final step to alphaStar
|
||||
x = x0 .add( xdir.scalarMultiply( alphaStar ) );
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
|
||||
return alphaStar;
|
||||
|
||||
|
||||
};
|
||||
|
||||
TCAD.math.lineSearchWeight = function(subsys, xdir) {
|
||||
|
||||
var f1,f2,f3,alpha1,alpha2,alpha3,alphaStar;
|
||||
|
||||
|
||||
var alphaMax = 1e28; //maxStep(xdir);
|
||||
|
||||
var x;
|
||||
var x0 = new TCAD.math.Vector(subsys.params.length);
|
||||
|
||||
var costs = [];
|
||||
function updateCosts() {
|
||||
var maxErr = -1;
|
||||
var i;
|
||||
var t;
|
||||
for (i=0; i < subsys.constraints.length; i++) {
|
||||
t = subsys.constraints[i].error();
|
||||
maxErr = Math.max(maxErr, t*t);
|
||||
}
|
||||
if (maxErr > 0) {
|
||||
for (i=0; i < subsys.constraints.length; i++) {
|
||||
t = subsys.constraints[i].error();
|
||||
costs[i] = t*t / maxErr;
|
||||
}
|
||||
} else {
|
||||
TCAD.math.fill_array(costs, 0, subsys.constraints.length, 1)
|
||||
}
|
||||
}
|
||||
updateCosts();
|
||||
// console.log(costs);
|
||||
var xdir = new TCAD.math.Vector(subsys.params.length);
|
||||
calcGrad = function(out) {
|
||||
var i;
|
||||
for (i = 0; i < out.length; ++i) {
|
||||
out[i][0] = 0;
|
||||
}
|
||||
|
||||
for (i=0; i < subsys.constraints.length; i++) {
|
||||
var c = subsys.constraints[i];
|
||||
|
||||
var cParams = c.params;
|
||||
var grad = [];
|
||||
c.gradient(grad);
|
||||
|
||||
for (var p = 0; p < cParams.length; p++) {
|
||||
var param = cParams[p];
|
||||
var j = param.j;
|
||||
out[j][0] += costs[i] * grad[p]; // (10.4)
|
||||
}
|
||||
}
|
||||
};
|
||||
calcGrad(xdir.data)
|
||||
console.log(xdir.data);
|
||||
|
||||
function errorSquare() {
|
||||
var error = 0;
|
||||
for (var i = 0; i < subsys.constraints.length; i++) {
|
||||
var t = subsys.constraints[i].error();
|
||||
error += t * t * costs[i];
|
||||
}
|
||||
return error * 0.5;
|
||||
}
|
||||
|
||||
|
||||
//Save initial values
|
||||
TCAD.math.fillParams(subsys, x0.data);
|
||||
|
||||
//Start at the initial position alpha1 = 0
|
||||
alpha1 = 0.;
|
||||
f1 = errorSquare();
|
||||
|
||||
|
||||
//Take a step of alpha2 = 1
|
||||
alpha2 = 1.;
|
||||
x = x0.add(xdir.scalarMultiply(alpha2));
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
f2 = errorSquare();
|
||||
|
||||
//Take a step of alpha3 = 2*alpha2
|
||||
alpha3 = alpha2*2;
|
||||
x = x0.add(xdir.scalarMultiply(alpha3));
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
f3 = errorSquare();
|
||||
|
||||
//Now reduce or lengthen alpha2 and alpha3 until the minimum is
|
||||
//Bracketed by the triplet f1>f2<f3
|
||||
while (f2 > f1 || f2 > f3) {
|
||||
if (f2 > f1) {
|
||||
//If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
|
||||
//Effectively both are shortened by a factor of two.
|
||||
alpha3 = alpha2;
|
||||
f3 = f2;
|
||||
alpha2 = alpha2 / 2;
|
||||
x = x0.add( xdir.scalarMultiply(alpha2 ));
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
f2 = errorSquare();
|
||||
}
|
||||
else if (f2 > f3) {
|
||||
if (alpha3 >= alphaMax)
|
||||
break;
|
||||
//If f2 is greater than f3 then we increase alpha2 and alpha3 away from f1
|
||||
//Effectively both are lengthened by a factor of two.
|
||||
alpha2 = alpha3;
|
||||
f2 = f3;
|
||||
alpha3 = alpha3 * 2;
|
||||
x = x0.add( xdir.scalarMultiply(alpha3));
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
f3 = errorSquare();
|
||||
}
|
||||
}
|
||||
//Get the alpha for the minimum f of the quadratic approximation
|
||||
alphaStar = alpha2 + ((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3));
|
||||
|
||||
//Guarantee that the new alphaStar is within the bracket
|
||||
if (alphaStar >= alpha3 || alphaStar <= alpha1)
|
||||
alphaStar = alpha2;
|
||||
|
||||
if (alphaStar > alphaMax)
|
||||
alphaStar = alphaMax;
|
||||
|
||||
if (alphaStar != alphaStar)
|
||||
alphaStar = 0.;
|
||||
|
||||
//Take a final step to alphaStar
|
||||
x = x0 .add( xdir.scalarMultiply( alphaStar ) );
|
||||
TCAD.math.setParams2(subsys, x.data);
|
||||
// console.log(alphaStar);
|
||||
return alphaStar;
|
||||
|
||||
};
|
||||
|
||||
TCAD.math.lineSearchWolfeCond = function(sys, d) {
|
||||
|
||||
var c1 = 0.1;
|
||||
var c2 = 0.9;
|
||||
|
||||
var x0 = new TCAD.math.Vector(sys.params.length);
|
||||
TCAD.math.fillParams(sys, x0.data);
|
||||
|
||||
var alpha = 1;
|
||||
var fx0 = sys.errorSquare();
|
||||
var grad = new TCAD.math.Vector(sys.params.length);
|
||||
sys.calcGrad_(grad.data);
|
||||
var gx0 = grad.dot(d);
|
||||
|
||||
//bound the solution
|
||||
var alphaL = 0;
|
||||
var alphaR = 10000;
|
||||
var maxit = 800;
|
||||
|
||||
for (var iter = 1; iter <= maxit; iter++){
|
||||
var xp = x0.add(d.scalarMultiply(alpha));
|
||||
|
||||
TCAD.math.setParams2(sys, xp.data);
|
||||
var erroralpha = sys.errorSquare(); //get the error at that point
|
||||
|
||||
if (erroralpha >= fx0 + alpha * c1 * gx0) { // if error is not sufficiently reduced
|
||||
alphaR = alpha;//move halfway between current alpha and lower alpha
|
||||
alpha = (alphaL + alphaR)/2.0;
|
||||
}else{//if error is sufficiently decreased
|
||||
|
||||
TCAD.math.setParams2(sys, xp.data);
|
||||
sys.calcGrad_(grad.data);
|
||||
var slopealpha = grad.dot(d); // then get slope along search direction
|
||||
if (slopealpha <= c2 * Math.abs(gx0)){ // if slope sufficiently closer to 0
|
||||
break;//then this is an acceptable point
|
||||
}else if ( slopealpha >= c2 * gx0) { // if slope is too steep and positive then go to the left
|
||||
alphaR = alpha;//move halfway between current alpha and lower alpha
|
||||
alpha = (alphaL+ alphaR)/2;
|
||||
}else{//if slope is too steep and negative then go to the right of this alpha
|
||||
alphaL = alpha;//move halfway between current alpha and upper alpha
|
||||
alpha = (alphaL+ alphaR)/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if ran out of iterations then return the best thing we got
|
||||
var x = x0.add(d.scalarMultiply(alpha));
|
||||
TCAD.math.setParams2(sys, x.data);
|
||||
return alpha;
|
||||
};
|
||||
|
||||
TCAD.math.lineSearch3 = function(sys, xdir) {
|
||||
|
||||
|
|
@ -342,4 +647,12 @@ TCAD.math.lineSearch2 = function(subsys, xdir) {
|
|||
|
||||
return alphaStar;
|
||||
|
||||
};
|
||||
|
||||
|
||||
TCAD.math.lineSearch = TCAD.math.lineSearchWeight;
|
||||
//TCAD.math.lineSearch = TCAD.math.lineSearchOrig;
|
||||
|
||||
TCAD.math.fill_array = function(a, fromIndex, toIndex,val) {
|
||||
for (var i = fromIndex; i < toIndex; i++) a[i] = val;
|
||||
};
|
||||
53
web/app/math/test.js
Normal file
53
web/app/math/test.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
function perpAndCoinc() {
|
||||
var sys = [];
|
||||
var ID = 0;
|
||||
var l1 = {
|
||||
p1 : {
|
||||
x : new TCAD.parametric.Param(ID++, 10),
|
||||
y : new TCAD.parametric.Param(ID++, 10)
|
||||
},
|
||||
p2 : {
|
||||
x : new TCAD.parametric.Param(ID++, 300),
|
||||
y : new TCAD.parametric.Param(ID++, 300)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var l2 = {
|
||||
p1 : {
|
||||
x : new TCAD.parametric.Param(ID++, 10 + 100),
|
||||
y : new TCAD.parametric.Param(ID++, -10 + 100)
|
||||
},
|
||||
p2 : {
|
||||
x : new TCAD.parametric.Param(ID++, 300 + 100),
|
||||
y : new TCAD.parametric.Param(ID++, -300 + 100)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
sys.push(new TCAD.constraints.Perpendicular([l1.p1.x, l1.p1.y, l1.p2.x, l1.p2.y, l2.p1.x, l2.p1.y, l2.p2.x, l2.p2.y]));
|
||||
sys.push(new TCAD.constraints.Equal([l1.p1.x, l2.p1.x]));
|
||||
sys.push(new TCAD.constraints.Equal([l1.p1.y, l2.p1.y]));
|
||||
|
||||
return sys;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function testCompare() {
|
||||
var bfgs_ = perpAndCoinc();
|
||||
var lm_ = perpAndCoinc();
|
||||
var tr_ = perpAndCoinc();
|
||||
|
||||
var bfgs = TCAD.parametric.solve(bfgs_, [], 0, 1);
|
||||
var lm = TCAD.parametric.solve(lm_, [], 0, 0);
|
||||
var tr = TCAD.parametric.solve(tr_, [], 0, 2);
|
||||
|
||||
console.log("bfgs: " + bfgs.errorSquare());
|
||||
console.log("lm: " + lm.errorSquare());
|
||||
console.log("trusted region: " + tr.errorSquare());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ TCAD.TWO.ParametricManager.prototype.solve1 = function(locked, onSolved) {
|
|||
};
|
||||
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype.solve = function(locked, fineLevel) {
|
||||
TCAD.TWO.ParametricManager.prototype.solve = function(locked, fineLevel, alg) {
|
||||
var pdict = {};
|
||||
var params;
|
||||
var _constrs = [];
|
||||
|
|
@ -242,7 +242,7 @@ TCAD.TWO.ParametricManager.prototype.solve = function(locked, fineLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
TCAD.parametric.solve(_constrs, _locked, fineLevel);
|
||||
TCAD.parametric.solve(_constrs, _locked, fineLevel, alg);
|
||||
|
||||
for (p in pdict) {
|
||||
_p = pdict[p];
|
||||
|
|
|
|||
|
|
@ -10,11 +10,15 @@
|
|||
</style>
|
||||
|
||||
<script src="lib/three/three.js"></script>
|
||||
<script src="lib/numeric-1.2.6.js"></script>
|
||||
<script src="lib/dat.gui.min.js"></script>
|
||||
<script src="app/canvas.js"></script>
|
||||
<script src="app/arc.js"></script>
|
||||
<script src="app/circle.js"></script>
|
||||
<script src="app/math/math.js"></script>
|
||||
<script src="app/math/matrix.js"></script>
|
||||
<script src="app/math/optim.js"></script>
|
||||
<script src="app/math/noptim.js"></script>
|
||||
|
||||
<script src="app/math/lm.js"></script>
|
||||
<script src="app/constr/constraints.js"></script>
|
||||
|
|
|
|||
4424
web/lib/numeric-1.2.6.js
Normal file
4424
web/lib/numeric-1.2.6.js
Normal file
File diff suppressed because it is too large
Load diff
39
web/test.html
Normal file
39
web/test.html
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>TCAD</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Monospace;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<script> TCAD = {} </script>
|
||||
<script src="lib/three/three.js"></script>
|
||||
<script src="app/engine.js"></script>
|
||||
<script src="app/canvas.js"></script>
|
||||
<script src="app/math/math.js"></script>
|
||||
<script src="app/math/matrix.js"></script>
|
||||
<script src="app/math/optim.js"></script>
|
||||
|
||||
<script src="app/math/lm.js"></script>
|
||||
<script src="app/constr/constraints.js"></script>
|
||||
<script src="app/constr/solver.js"></script>
|
||||
|
||||
<script src="app/engine.js"></script>
|
||||
<script src="app/vector.js"></script>
|
||||
<script src="app/math/test.js"></script>
|
||||
|
||||
<script>
|
||||
function start() {
|
||||
new TCAD.App2D();
|
||||
}
|
||||
window.onload = function() {
|
||||
testCompare();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue