some success with non linear optimization

This commit is contained in:
Val Erastov 2014-09-20 01:44:33 -07:00
parent c4a79d2078
commit 789d9f0aee
23 changed files with 1725 additions and 76 deletions

26
misc/perp Normal file
View file

@ -0,0 +1,26 @@
pkg load optim;
function y = f (x)
y(1) = (
(x(3) - x(1)) * (x(7) - x(5)) +
(x(4) - x(2)) * (x(8) - x(6))
) ^ 2;
y(2) = (
(x(11) - x(9)) * (x(7) - x(5)) +
(x(12) - x(10)) * (x(8) - x(6))
) ^ 2;
y(3) = 0;y(4) = 0;y(5) = 0;y(6) = 0;y(7) = 0;y(8) = 0;
y(9) = 0;y(10) = 0;y(11) = 0;y(12) = 0;
endfunction
x0 = [100, 100, 600, 600, 700, 600, 900, 100, 1100, 100, 1600, 600];
#x = fminunc(@f, reshape(x0, 12,1));
x = bfgsmin('f', {reshape(x0, 12,1)}); #WORKS!
#x = x0;
l1 = [x(1), x(2); x(3), x(4)];
l2 = [x(5), x(6); x(7), x(8)];
l3 = [x(9), x(10); x(11), x(12)];
plot(l1(:,1), l1(:,2), l2(:,1), l2(:,2), l3(:,1), l3(:,2),'-');

31
misc/simple.m Normal file
View file

@ -0,0 +1,31 @@
function y = angle (x)
a = [x(3) - x(1); x(4) - x(2)];
b = [x(7) - x(5); x(8) - x(6)];
y = acos(dot(a, b) / (norm(a) * norm(b))) / pi * 180;
endfunction
function y = f (x)
y(1) = (
(x(3) - x(1)) * (x(7) - x(5)) +
(x(4) - x(2)) * (x(8) - x(6))
) ^ 2;
endfunction
x0 = [100, 100, 600, 600, 700, 600, 900, 100];
x = sqp(x0, @f);
#pkg load optim;
#x = bfgsmin('f', {reshape(x0, 8,1)}); #WORKS!
l1 = [x(1), x(2); x(3), x(4)];
l2 = [x(5), x(6); x(7), x(8)];
plot(l1(:,1), l1(:,2), l2(:,1), l2(:,2), '-');
#d = (x(3) - x(1)) * (x(7) - x(5)) + (x(4) - x(2)) * (x(8) - x(6)) ;
disp("Angle: "), disp(angle(x));

View file

@ -1,15 +1,40 @@
package cad.fx;
import cad.gcs.Constraint;
import cad.gcs.GradientDescent;
import cad.gcs.GradientDescent2;
import cad.gcs.GradientDescent3;
import cad.gcs.Param;
import cad.gcs.Solver;
import cad.gcs.constr.Constraint2;
import cad.gcs.constr.Perpendicular;
import cad.gcs.constr.Perpendicular2;
import cad.gcs.constr.X;
import cad.gcs.constr.XY;
import cad.math.Vector;
import gnu.trove.list.TDoubleList;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.Group;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
import org.apache.commons.math3.analysis.MultivariateVectorFunction;
import org.apache.commons.math3.analysis.function.Max;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.optim.ConvergenceChecker;
import org.apache.commons.math3.optim.InitialGuess;
import org.apache.commons.math3.optim.MaxEval;
import org.apache.commons.math3.optim.MaxIter;
import org.apache.commons.math3.optim.PointVectorValuePair;
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunction;
import org.apache.commons.math3.optim.nonlinear.vector.ModelFunctionJacobian;
import org.apache.commons.math3.optim.nonlinear.vector.Target;
import org.apache.commons.math3.optim.nonlinear.vector.Weight;
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.GaussNewtonOptimizer;
import java.net.URL;
import java.util.Arrays;
@ -35,33 +60,135 @@ public class App2DCtrl implements Initializable {
content.getChildren().addAll(l1, l2);
solve.setOnAction(event -> {
Vector a1 = new Vector(l1.getStartX(), l1.getStartY());
Vector b1 = new Vector(l1.getEndX(), l1.getEndY());
Vector a2 = new Vector(l2.getStartX(), l2.getStartY());
Vector b2 = new Vector(l2.getEndX(), l2.getEndY());
Perpendicular perpendicular = new Perpendicular(a1, b1, a2, b2);
Vector as = new Vector(l1.getStartX(), l1.getStartY());
Vector ae = new Vector(l1.getEndX(), l1.getEndY());
Vector bs = new Vector(l2.getStartX(), l2.getStartY());
Vector be = new Vector(l2.getEndX(), l2.getEndY());
List<Constraint> parallels = Arrays.<Constraint>asList(perpendicular);
Solver.SubSystem subSystem = new Solver.SubSystem(parallels);
Solver.solve_DL(subSystem);
perpendicular.out(a1, b1, a2, b2);
Param l1p1x = new Param(l1.getStartX());
Param l1p1y = new Param(l1.getStartY());
Param l1p2x = new Param(l1.getEndX());
Param l1p2y = new Param(l1.getEndY());
Param l2p1x = new Param(l2.getStartX());
Param l2p1y = new Param(l2.getStartY());
Param l2p2x = new Param(l2.getEndX());
Param l2p2y = new Param(l2.getEndY());
l1.setStartX(a1.x);
l1.setStartY(a1.y);
l1.setEndX(b1.x);
l1.setEndY(b1.y);
l2.setStartX(a2.x);
l2.setStartY(a2.y);
l2.setEndX(b2.x);
l2.setEndY(b2.y);
Perpendicular2 perpendicular2 = new Perpendicular2(as, ae, bs, be);
Perpendicular perpendicular = new Perpendicular(
l1p1x,
l1p1y,
l1p2x,
l1p2y,
l2p1x,
l2p1y,
l2p2x,
l2p2y
);
XY xy = new XY(as, new Vector(100, 100));
X x = new X(
l1p1x,
l1p1y,
l1p2x,
l1p2y,
l2p1x,
l2p1y,
l2p2x,
l2p2y
);
List<Constraint> constrs = Arrays.<Constraint>asList(perpendicular);
Solver.SubSystem subSystem = new Solver.SubSystem(constrs);
// Solver.optimize(subSystem);
//
// while (subSystem.error() > 0.0001 ) {
Solver.solve_LM(subSystem);
// }
// solveGC(subSystem);
java.lang.System.out.println(perpendicular.angle());
Constraint2 constr = perpendicular2;
// Constraint2 constr = xy;
// Constraint constr = perpendicular;
// GradientDescent.solve(constr);
// perpendicular.out(a1, b1, a2, b2);
// GradientDescent2.solve(constr);
// l1.setStartX(as.x);
// l1.setStartY(as.y);
// l1.setEndX(ae.x);
// l1.setEndY(ae.y);
//
// l2.setStartX(bs.x);
// l2.setStartY(bs.y);
// l2.setEndX(be.x);
// l2.setEndY(be.y);
l1.setStartX(l1p1x.get());
l1.setStartY(l1p1y.get());
l1.setEndX(l1p2x.get());
l1.setEndY(l1p2y.get());
l2.setStartX(l2p1x.get());
l2.setStartY(l2p1y.get());
l2.setEndX(l2p2x.get());
l2.setEndY(l2p2y.get());
});
}
private void solveGC(final Solver.SubSystem subSystem) {
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer((iteration, previous, current) -> {
return subSystem.value() < 0.00000001;
}) {
@Override
protected double[] computeResiduals(double[] objectiveValue) {
TDoubleList residual = subSystem.calcResidual();
return residual.toArray();
}
};
double[] wieght = new double[subSystem.cSize()];
Arrays.fill(wieght, 1);
optimizer.optimize(
new MaxEval(10000),
new MaxIter(10000),
new InitialGuess(subSystem.getParams().toArray()),
new Target(new double[subSystem.cSize()]),
new Weight(wieght),
new ModelFunctionJacobian(point -> {
subSystem.setParams(point);
return subSystem.makeJacobi().getData();
}),
new ModelFunction(new MultivariateVectorFunction() {
@Override
public double[] value(double[] point) throws IllegalArgumentException {
subSystem.setParams(point);
return subSystem.getValues().toArray();
}
})
);
}
private void solve(ActionEvent e) {
// UnconstrainedLeastSquares opt = FactoryOptimization.leastSquaresTrustRegion(100, RegionStepType.DOG_LEG_FTF, false);

View file

@ -112,7 +112,7 @@ public class CadContext {
}
Sketch sketch = selection.csgNode.getSketch(selection.poly);
Vector dir = sketch.owner.normal.scale(height);
Vector dir = sketch.owner.normal.multi(height);
for (List<Vector> polygon : sketch.polygons) {
if (polygon.isEmpty()) {
continue;

View file

@ -149,7 +149,7 @@ public class Utils3D {
public static List<Polygon> createCube(double width) {
Polygon square = createSquare(width);
return Polygon.extrude(square, square.normal.scale(width));
return Polygon.extrude(square, square.normal.multi(width));
}
public static Polygon createSquare(double width) {

View file

@ -1,11 +1,11 @@
package cad.gcs;
import java.util.List;
public interface Constraint extends System {
double error();
void step(double alpha);
void set(double[] input);
}

View file

@ -0,0 +1,56 @@
package cad.gcs;
import cad.gcs.constr.Perpendicular;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.RealVector;
public class GradientDescent {
static double EPS = 0.0000001;
public static void solve(Constraint constr) {
double last = value(constr);
double alpha = 10;
int pSize = constr.pSize();
RealVector steps = new ArrayRealVector(pSize);
steps.set(10);
for (int i = 0; i < 1000000; i++) {
double[] gradData = new double[pSize];
constr.gradient(gradData);
ArrayRealVector grad = new ArrayRealVector(gradData);
RealVector dir = grad.mapDivide(grad.getNorm());
dir = dir.mapMultiply( alpha);
java.lang.System.out.println(dir.getNorm());
ArrayRealVector params = new ArrayRealVector(constr.params());
params = params.add(dir);
constr.set(params.toArray());
java.lang.System.out.println(((Perpendicular) constr).angle());
// constr.step(alpha);
double err = value(constr);
if (err < last) {
} else if (alpha < EPS) {
return;
} else {
alpha /= 3;
}
last = err;
}
}
private static double value(Constraint constr) {
double err = constr.error();
return err * err;
}
}

View file

@ -0,0 +1,54 @@
package cad.gcs;
import cad.gcs.constr.Constraint2;
import cad.gcs.constr.Perpendicular2;
import cad.math.Vector;
import java.lang.*;
import java.util.List;
public class GradientDescent2 {
private static final double DBL_EPSILON = Double.MIN_VALUE;
static double EPS = 0.0000000001;
public static void solve(Constraint2 constr) {
double last = value(constr);
double alpha = .01;
List<Vector> params = constr.params();
for (int i = 0; i < 100000; i++) {
List<Vector> grad = constr.gradient();
for (int j = 0; j < grad.size(); j++) {
Vector gr = grad.get(j);
Vector param = params.get(j);
Vector step = gr.normalize().multi(alpha);
param._plus(step);
}
double err = value(constr);
java.lang.System.out.println(constr.debug() + "===" + err + "====>" + alpha );
if (err < last) {
} else {
if (alpha < EPS) {
return;
} else {
alpha /= 3;
}
}
last = err;
}
}
private static double value(Constraint2 constr) {
double err = constr.error();
return Math.abs(err);
}
}

View file

@ -0,0 +1,78 @@
package cad.gcs;
import cad.gcs.constr.Constraint2;
import cad.gcs.constr.Perpendicular2;
import cad.math.Vector;
import gnu.trove.list.TDoubleList;
import gnu.trove.list.array.TDoubleArrayList;
import gnu.trove.map.hash.TObjectDoubleHashMap;
import java.lang.*;
import java.util.HashMap;
import java.util.List;
public class GradientDescent3 {
private static final double DBL_EPSILON = Double.MIN_VALUE;
static double EPS = 0.0000001;
public static void solve(Constraint2... constrs) {
TObjectDoubleHashMap<Vector> alphas = new TObjectDoubleHashMap<>();
double[] values = new double[constrs.length];
double[] calphas = new double[constrs.length];
for (int k = 0; k < constrs.length; k++) {
Constraint2 constr = constrs[k];
for (Vector p : constr.params()) {
alphas.put(p, 1);
}
values[k] = (value(constr));
}
for (int i = 0; i < 100000; i++) {
for (int k = 0; k < constrs.length; k++) {
Constraint2 constr = constrs[k];
List<Vector> params = constr.params();
double calpha = calphas[k];
List<Vector> grad = constr.gradient();
for (int j = 0; j < grad.size(); j++) {
Vector gr = grad.get(j);
Vector param = params.get(j);
double alpha = alphas.get(param);
Vector step = gr.normalize().multi(alpha);
param._plus(step);
}
double err = value(constr);
double last = values[k];
// java.lang.System.out.println(constr.debug() + "===" + err + "====>" + alpha );
if (err < last) {
} else {
boolean divergence = true;
for (double a : calphas) {
if (a >= EPS) {
divergence = false;
}
}
if (divergence) {
return;
} else {
calpha /= 3;
calphas[k] = calpha;
for (Vector param : params) {
alphas.put(param, Math.min(alphas.get(param), calpha));
}
}
}
values[k] = err;
}
}
}
private static double value(Constraint2 constr) {
double err = constr.error();
return Math.abs(err);
}
}

256
src/cad/gcs/LM.java Normal file
View file

@ -0,0 +1,256 @@
// levenberg-marquardt in java
//
// To use this, implement the functions in the LMfunc interface.
//
// This library uses simple matrix routines from the JAMA java matrix package,
// which is in the public domain. Reference:
// http://math.nist.gov/javanumerics/jama/
// (JAMA has a matrix object class. An earlier library JNL, which is no longer
// available, represented matrices as low-level arrays. Several years
// ago the performance of JNL matrix code was better than that of JAMA,
// though improvements in java compilers may have fixed this by now.)
//
// One further recommendation would be to use an inverse based
// on Choleski decomposition, which is easy to implement and
// suitable for the symmetric inverse required here. There is a choleski
// routine at idiom.com/~zilla.
//
// If you make an improved version, please consider adding your
// name to it ("modified by ...") and send it back to me
// (and put it on the web).
//
// ----------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// initial author contact info:
// jplewis www.idiom.com/~zilla zilla # computer.org, #=at
//
// Improvements by:
// dscherba www.ncsa.uiuc.edu/~dscherba
// Jonathan Jackson j.jackson # ucl.ac.uk
package cad.gcs;
// see comment above
import Jama.*;
/**
* Levenberg-Marquardt, implemented from the general description
* in Numerical Recipes (NR), then tweaked slightly to mostly
* match the results of their code.
* Use for nonlinear least squares assuming Gaussian errors.
* <p>
* TODO this holds some parameters fixed by simply not updating them.
* this may be ok if the number if fixed parameters is small,
* but if the number of varying parameters is larger it would
* be more efficient to make a smaller hessian involving only
* the variables.
* <p>
* The NR code assumes a statistical context, e.g. returns
* covariance of parameter errors; we do not do this.
*/
public final class LM {
/**
* calculate the current sum-squared-error
* (Chi-squared is the distribution of squared Gaussian errors,
* thus the name)
*/
static double chiSquared(double[] a, double[] y, double[] s,
LMfunc f) {
int npts = y.length;
double sum = 0.;
double[] val = f.val(a);
for (int i = 0; i < npts; i++) {
double d = y[i] - val[i];
d = d / s[i];
sum = sum + (d * d);
}
return sum;
} //chiSquared
/**
* Minimize E = sum {(y[k] - f(x[k],a)) / s[k]}^2
* The individual errors are optionally scaled by s[k].
* Note that LMfunc implements the value and gradient of f(x,a),
* NOT the value and gradient of E with respect to a!
*
* @param y corresponding array of values
* @param a the parameters/state of the model
* @param vary false to indicate the corresponding a[k] is to be held fixed
* @param s sigma^2 for point i
* @param lambda blend between steepest descent (lambda high) and
* jump to bottom of quadratic (lambda zero).
* Start with 0.001.
* @param termepsilon termination accuracy (0.01)
* @param maxiter stop and return after this many iterations if not done
* @param verbose set to zero (no prints), 1, 2
* @return the new lambda for future iterations.
* Can use this and maxiter to interleave the LM descent with some other
* task, setting maxiter to something small.
*/
public static double solve(double[] a, double[] y, double[] s,
boolean[] vary, LMfunc f,
double lambda, double termepsilon, int maxiter,
int verbose)
throws Exception {
int npts = y.length;
int nparm = a.length;
assert s.length == npts;
if (verbose > 0) {
out().print(" a[" + a.length + "]");
out().println(" y[" + y.length + "]");
}
double e0 = chiSquared(a, y, s, f);
//double lambda = 0.001;
boolean done = false;
// g = gradient, H = hessian, d = step to minimum
// H d = -g, solve for d
double[][] H = new double[nparm][nparm];
double[] g = new double[nparm];
//double[] d = new double[nparm];
double[] oos2 = new double[s.length];
for (int i = 0; i < npts; i++) {
oos2[i] = 1. / (s[i] * s[i]);
}
int iter = 0;
int term = 0; // termination count test
do {
++iter;
// hessian approximation
for (int r = 0; r < nparm; r++) {
for (int c = 0; c < nparm; c++) {
for (int i = 0; i < npts; i++) {
if (i == 0) {
H[r][c] = 0.;
}
double[] grad = f.grad(a);
H[r][c] += (oos2[i] * grad[r] * grad[c]);
} //npts
} //c
} //r
// boost diagonal towards gradient descent
for (int r = 0; r < nparm; r++) {
H[r][r] *= (1. + lambda);
}
// gradient
for (int r = 0; r < nparm; r++) {
for (int i = 0; i < npts; i++) {
if (i == 0) {
g[r] = 0.;
}
double[] grad = f.grad(a);
double[] val = f.val(a);
g[r] += (oos2[i] * (y[i] - val[i]) * grad[r]);
}
} //npts
// scale (for consistency with NR, not necessary)
if (false) {
for (int r = 0; r < nparm; r++) {
g[r] = -0.5 * g[r];
for (int c = 0; c < nparm; c++) {
H[r][c] *= 0.5;
}
}
}
// solve H d = -g, evaluate error at new location
//double[] d = DoubleMatrix.solve(H, g);
double[] d = (new Matrix(H)).lu().solve(new Matrix(g, nparm)).getRowPackedCopy();
//double[] na = DoubleVector.add(a, d);
double[] na = (new Matrix(a, nparm)).plus(new Matrix(d, nparm)).getRowPackedCopy();
double e1 = chiSquared(na, y, s, f);
if (verbose > 0) {
out().println("\n\niteration " + iter + " lambda = " + lambda);
out().print("a = ");
(new Matrix(a, nparm)).print(10, 2);
if (verbose > 1) {
out().print("H = ");
(new Matrix(H)).print(10, 2);
out().print("g = ");
(new Matrix(g, nparm)).print(10, 2);
out().print("d = ");
(new Matrix(d, nparm)).print(10, 2);
}
out().print("e0 = " + e0 + ": ");
out().print("moved from ");
(new Matrix(a, nparm)).print(10, 2);
out().print("e1 = " + e1 + ": ");
if (e1 < e0) {
out().print("to ");
(new Matrix(na, nparm)).print(10, 2);
} else {
out().println("move rejected");
}
}
// termination test (slightly different than NR)
if (Math.abs(e1 - e0) > termepsilon) {
term = 0;
} else {
term++;
if (term == 4) {
out().println("terminating after " + iter + " iterations");
done = true;
}
}
if (iter >= maxiter) {
done = true;
}
// in the C++ version, found that changing this to e1 >= e0
// was not a good idea. See comment there.
//
if (e1 > e0 || Double.isNaN(e1)) { // new location worse than before
lambda *= 10.;
} else { // new location better, accept new parameters
lambda *= 0.1;
e0 = e1;
// simply assigning a = na will not get results copied back to caller
for (int i = 0; i < nparm; i++) {
if (vary[i]) {
a[i] = na[i];
}
}
}
} while (!done);
return lambda;
} //solve
private static java.io.PrintStream out() {
return java.lang.System.out;
}
//----------------------------------------------------------------
} //LM

26
src/cad/gcs/LMfunc.java Normal file
View file

@ -0,0 +1,26 @@
// LMfunc.java
package cad.gcs;
/**
* Caller implement this interface to specify the
* function to be minimized and its gradient.
*
* Optionally return an initial guess and some test data,
* though the LM.java only uses this in its optional main() test program.
* Return null if these are not needed.
*/
public interface LMfunc
{
/**
* x is a single point, but domain may be mulidimensional
*/
double[] val(double[] a);
/**
* return the kth component of the gradient df(x,a)/da_k
*/
double[] grad(double[] a);
} //LMfunc

View file

@ -1,12 +1,18 @@
package cad.gcs;
public abstract class Param {
public class Param {
public final Constraint constraint;
public double value;
protected Param(Constraint constraint) {
this.constraint = constraint;
public Param(double value) {
this.value = value;
}
public abstract double value();
public double get() {
return value;
}
public double set(double value) {
return this.value = value;
}
}

View file

@ -2,15 +2,26 @@ package cad.gcs;
import gnu.trove.list.TDoubleList;
import gnu.trove.list.array.TDoubleArrayList;
import org.apache.commons.math3.exception.ConvergenceException;
import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.MathInternalError;
import org.apache.commons.math3.exception.util.LocalizedFormats;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.BlockRealMatrix;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.QRDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.SingularMatrixException;
import java.util.List;
public class Solver {
public static final boolean useLU = true;
private static final double DBL_EPSILON = Double.MIN_VALUE;
enum SolveStatus {
Success, // Found a solution zeroing the error function
Converged, // Found a solution minimizing the error function
@ -164,12 +175,108 @@ public class Solver {
private static RealMatrix lu(RealMatrix jx, RealMatrix fx) {
return new cad.gcs.LUDecomposition(jx).solve(fx);
return new org.apache.commons.math3.linear.LUDecomposition(new Array2DRowRealMatrix(makeSquare(jx.getData()))).getSolver().solve(fx);
// DoubleMatrix2D solve = new LUDecomposition(new DenseDoubleMatrix2D(jx.getData()))
// .solve(new DenseDoubleMatrix2D(fx.getData()));
}
public static double[][] makeSquare(double[][] m) {
if (m.length > m[0].length) {
for (int r = 0; r < m.length; r++) {
double[] row = m[r];
m[r] = new double[m.length];
java.lang.System.arraycopy(row, 0, m[r], 0, row.length);
}
} else {
double[][] _m = new double[m[0].length][];
for (int r = 0; r < m.length; r++) {
_m[r] = m[r];
}
for (int r = m.length; r < _m.length; r++) {
_m[r] = new double[m[0].length];
}
m = _m;
}
return m;
}
public static void optimize(SubSystem subSystem) {
final int cSize = subSystem.cSize();
final double[] currentPoint = subSystem.getParams().toArray();
final int pSize = currentPoint.length;
// iterate until convergence is reached
double[] current = null;
int iter = 0;
for (boolean converged = false; !converged; ) {
++iter;
// evaluate the objective function and its jacobian
// Value of the objective function at "currentPoint".
final double[] currentResiduals = subSystem.calcResidual().toArray();
final RealMatrix jacobian = new Array2DRowRealMatrix(makeSquare(subSystem.makeJacobi().getData()));
// build the linear problem
final double[] b = new double[pSize];
final double[][] a = new double[pSize][pSize];
for (int i = 0; i < cSize; ++i) {
final double[] grad = jacobian.getRow(i);
final double weight = 1;
final double residual = currentResiduals[i];
// compute the normal equation
final double wr = weight * residual;
for (int j = 0; j < pSize; ++j) {
b[j] += wr * grad[j];
}
// build the contribution matrix for measurement i
for (int k = 0; k < pSize; ++k) {
double[] ak = a[k];
double wgk = weight * grad[k];
for (int l = 0; l < pSize; ++l) {
ak[l] += wgk * grad[l];
}
}
}
try {
// solve the linearized least squares problem
RealMatrix mA = new BlockRealMatrix(a);
DecompositionSolver solver = useLU ?
new org.apache.commons.math3.linear.LUDecomposition(jacobian).getSolver() :
new QRDecomposition(jacobian).getSolver();
final double[] dX = solver.solve(new ArrayRealVector(currentPoint).mapMultiply(-1)).toArray();
// update the estimated parameters
for (int i = 0; i < pSize; ++i) {
currentPoint[i] += dX[i];
}
subSystem.setParams(currentPoint);
} catch (SingularMatrixException e) {
throw new ConvergenceException(LocalizedFormats.UNABLE_TO_SOLVE_SINGULAR_PROBLEM);
}
// Check convergence.
if (iter != 0) {
// converged = checker.converged(iter, previous, current);
// if (converged) {
// setCost(computeCost(currentResiduals));
// return current;
// }
if (subSystem.value() < 0.0001) {
return;
}
}
}
// Must never happen.
throw new MathInternalError();
}
public RealMatrix solve(RealMatrix b, int[] pivot, double[][] lu) {
final int m = pivot.length;
@ -218,7 +325,334 @@ public class Solver {
return new Array2DRowRealMatrix(bp, false);
}
public static SolveStatus solve_LM(SubSystem subsys) {
int xsize = subsys.pSize();
int csize = subsys.cSize();
if (xsize == 0) {
return SolveStatus.Success;
}
RealMatrix e = mtrx(csize), e_new = mtrx(csize); // vector of all function errors (every constraint is one function)
RealMatrix J = mtrx(csize, xsize); // Jacobi of the subsystem
RealMatrix A = mtrx(xsize, xsize);
RealMatrix x = mtrx(xsize), h = mtrx(xsize), x_new = mtrx(xsize), g = mtrx(xsize);
double[] diag_A;
// subsys.redirectParams();
subsys.fillParams(x);
subsys.calcResidual(e);
e = e.scalarMultiply(-1);
int maxIterNumber = MaxIterations * xsize;
double divergingLim = 1e6 * squaredNorm(e) + 1e12;
double eps = 1e-10, eps1 = 1e-80;
double tau = 1e-3;
double nu = 2, mu = 0;
int iter = 0, stop = 0;
for (iter = 0; iter < maxIterNumber && stop == 0; ++iter) {
// check error
double err = squaredNorm(e);
if (err <= eps) { // error is small, Success
stop = 1;
break;
} else if (err > divergingLim || err != err) { // check for diverging and NaN
stop = 6;
break;
}
// J^T J, J^T e
subsys.calcJacobi(J);
;
A = J.transpose().multiply(J);
g = J.transpose().multiply(e);
// Compute ||J^T e||_inf
double g_inf = infinityNorm(g);
diag_A = diagonal(A); // save diagonal entries so that augmentation can be later canceled
// check for convergence
if (g_inf <= eps1) {
stop = 2;
break;
}
// compute initial damping factor
if (iter == 0) {
mu = tau * new ArrayRealVector(diag_A).getLInfNorm() ;
}
// determine increment using adaptive damping
int k = 0;
while (k < 50) {
// augment normal equations A = A+uI
for (int i = 0; i < xsize; ++i) {
A.addToEntry(i, i, mu);
}
//solve augmented functions A*h=-g
try {
h = new LUDecomposition(A).getSolver().solve(g);
} catch (Exception ssse) {
java.lang.System.out.println( "");
return SolveStatus.Success;
}
;
double rel_error = (A.multiply(h).subtract(g)).getFrobeniusNorm() / g.getFrobeniusNorm();
// check if solving works
if (rel_error < 1e-5) {
// restrict h according to maxStep
// double scale = subsys.maxStep(h);
// if (scale < 1.) {
// h = h.scalarMultiply(scale);
// }
// compute par's new estimate and ||d_par||^2
x_new = x.add(h);
double h_norm = squaredNorm(h);
if (h_norm <= eps1 * eps1 * x.getFrobeniusNorm()) { // relative change in p is small, stop
stop = 3;
break;
} else if (h_norm >= (x.getFrobeniusNorm() + eps1) / (DBL_EPSILON * DBL_EPSILON)) { // almost singular
stop = 4;
break;
}
subsys.setParams(x_new);
subsys.calcResidual(e_new);
e_new = e_new.scalarMultiply(-1);
double dF = squaredNorm(e) - squaredNorm(e_new);
double dL = dot(h, (h.scalarMultiply(mu).add(g)));
if (dF > 0. && dL > 0.) { // reduction in error, increment is accepted
double tmp = 2 * dF / dL - 1.;
mu *= Math.max(1. / 3., 1. - tmp * tmp * tmp);
nu = 2;
// update par's estimate
x = x_new.copy();
e = e_new.copy();
break;
}
}
// if this point is reached, either the linear system could not be solved or
// the error did not reduce; in any case, the increment must be rejected
mu *= nu;
nu *= 2.0;
for (int i = 0; i < xsize; ++i) // restore diagonal J^T J entries
{
A.setEntry(i, i, diag_A[i]);
}
k++;
}
if (k > 50) {
stop = 7;
break;
}
}
if (iter >= maxIterNumber) {
stop = 5;
}
// subsys.revertParams();
return (stop == 1) ? SolveStatus.Success : SolveStatus.Failed;
}
private static void identity(RealMatrix m) {
for (int i = 0; i < m.getColumnDimension() && i < m.getRowDimension(); i++) {
m.setEntry(i, i, 1.0);
}
}
static double lineSearch(SubSystem subsys, RealMatrix xdir) {
double f1, f2, f3, alpha1, alpha2, alpha3, alphaStar;
double alphaMax = 1;//subsys.maxStep(xdir);
int pSize = subsys.pSize();
RealMatrix x0 = mtrx(pSize), x = mtrx(pSize);
//Save initial values
subsys.fillParams(x0);
//Start at the initial position alpha1 = 0
alpha1 = 0.;
f1 = subsys.error();
//Take a step of alpha2 = 1
alpha2 = 1.;
x = x0.add(xdir.scalarMultiply(alpha2));
subsys.setParams(x);
f2 = subsys.error();
//Take a step of alpha3 = 2*alpha2
alpha3 = alpha2 * 2;
x = x0.add(xdir.scalarMultiply(alpha3));
subsys .setParams(x);
f3 = subsys . error();
//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 ));
subsys . setParams(x);
f2 = subsys . error();
} 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));
subsys . setParams(x);
f3 = subsys . error();
}
}
//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 ) );
subsys . setParams(x);
return alphaStar;
}
public static SolveStatus solve_BFGS(SubSystem subsys, boolean isFine) {
int xsize = subsys.pSize();
if (xsize == 0) {
return SolveStatus.Success;
}
RealMatrix D = new Array2DRowRealMatrix(xsize, xsize);
identity(D);
//
RealMatrix x = new Array2DRowRealMatrix(xsize, 1);
RealMatrix xdir = new Array2DRowRealMatrix(xsize, 1);
RealMatrix grad = new Array2DRowRealMatrix(xsize, 1);
RealMatrix h = new Array2DRowRealMatrix(xsize, 1);
RealMatrix y = new Array2DRowRealMatrix(xsize, 1);
RealMatrix Dy = new Array2DRowRealMatrix(xsize, 1);
// Initial unknowns vector and initial gradient vector
subsys.fillParams(x);
subsys.calcGrad(grad);
// Initial search direction oposed to gradient (steepest-descent)
xdir = grad.scalarMultiply(-1);
lineSearch(subsys, xdir);
double err = subsys.error();
h = new Array2DRowRealMatrix(x.getData());
subsys.fillParams(x);
h = x.subtract(h); // = x - xold
double convergence = isFine ? XconvergenceFine : XconvergenceRough;
int maxIterNumber = MaxIterations * xsize;
double divergingLim = 1e6 * err + 1e12;
for (int iter = 1; iter < maxIterNumber; iter++) {
if (h.getFrobeniusNorm() <= convergence || err <= smallF) {
break;
}
if (err > divergingLim || err != err) // check for diverging and NaN
{
break;
}
y = new Array2DRowRealMatrix(grad.getData());
subsys.calcGrad(grad);
y = grad.subtract(y); // = grad - gradold
double hty = dotProduct(h, y);
//make sure that hty is never 0
if (hty == 0) {
hty = .0000000001;
}
Dy = D.multiply(y);
double ytDy = dotProduct(y, Dy);
//Now calculate the BFGS update on D
D = D.add(h.scalarMultiply((1. + ytDy / hty) / hty).multiply(h.transpose()));
D = D.subtract((
h.multiply(Dy.transpose())
.add(Dy.multiply(h.transpose()))
).scalarMultiply(1. / hty)
);
xdir = D.scalarMultiply(-1).multiply(grad);
lineSearch(subsys, xdir);
err = subsys.error();
h = new Array2DRowRealMatrix(x.getData());
subsys.fillParams(x);
h = x.subtract(h); // = x - xold
}
// subsys.revertParams();
if (err <= smallF) {
return SolveStatus.Success;
}
if (h.getFrobeniusNorm() <= convergence) {
return SolveStatus.Converged;
}
return SolveStatus.Failed;
}
private static double[] diagonal(RealMatrix a) {
int s = Math.min(a.getColumnDimension(), a.getRowDimension());
double[] d = new double[s];
for (int i = 0; i < s; i++) {
d[i] = a.getEntry(i, i);
}
return d;
}
private static double dot(RealMatrix m1, RealMatrix m2) {
return new ArrayRealVector(m1.getData()[0]).dotProduct(new ArrayRealVector(m2.getData()[0]));
@ -271,6 +705,34 @@ public class Solver {
x.setColumn(0, params.toArray());
}
public TDoubleList getParams() {
int i = 0;
TDoubleList params = new TDoubleArrayList();
for (Constraint c : constraints) {
params.add(c.params());
}
return params;
}
public TDoubleList getValues2() {
TDoubleList params = new TDoubleArrayList();
for (Constraint c : constraints) {
double err = c.error();
params.add(err);
}
return params;
}
public TDoubleList getValues() {
TDoubleList params = new TDoubleArrayList();
for (Constraint c : constraints) {
params.add(c.error());
}
return params;
}
public double calcResidual(RealMatrix r) {
double err = 0.;
int i = 0;
@ -283,6 +745,30 @@ public class Solver {
return err;
}
public TDoubleList calcResidual() {
TDoubleList r = new TDoubleArrayList();
double err = 0.;
int i = 0;
for (Constraint c : constraints) {
double v = c.error();
r.add(v);
err += v * v;
}
err *= 0.5;
return r;
}
public double value() {
double err = 0.;
for (Constraint c : constraints) {
double v = c.error();
err += v * v;
}
err *= 0.5;
return err;
}
public void calcJacobi(RealMatrix jacobi) {
// jacobi.setZero(csize, params.size());
for (int j=0; j < pSize(); j++) {
@ -300,6 +786,25 @@ public class Solver {
}
}
public RealMatrix makeJacobi() {
RealMatrix jacobi = new Array2DRowRealMatrix(cSize(), pSize());
for (int j=0; j < pSize(); j++) {
for (int i=0; i < constraints.size(); i++) {
jacobi.setEntry(i, j, 0);
}
}
for (int i=0; i < constraints.size(); i++) {
Constraint c = constraints.get(i);
double[] grad = new double[c.params().length];
c.gradient(grad);
for (int j=0; j < grad.length; j++) {
jacobi.setEntry(i,j, grad[j]);
}
}
return jacobi;
}
public void setParams(RealMatrix params) {
int off = 0;
double[] arr = params.getColumn(0);
@ -310,5 +815,40 @@ public class Solver {
c.set(cp);
}
}
public void setParams(double[] arr) {
int off = 0;
for (Constraint c : constraints) {
int l = c.params().length;
double[] cp = new double[l];
java.lang.System.arraycopy(arr, off, cp, 0, l);
c.set(cp);
}
}
public double error() {
return value();
}
public void calcGrad(RealMatrix out) {
int cc = 0;
for (Constraint c : constraints) {
double[] grad = new double[c.params().length];
c.gradient(grad);
for (double aGrad : grad) {
out.setEntry(cc++, 0, aGrad);
}
}
}
}
private static double dotProduct(RealMatrix m1, RealMatrix m2) {
return new ArrayRealVector(m1.getData()[0]).dotProduct(new ArrayRealVector(m2.getData()[0]));
}
static double XconvergenceRough = 1e-8;
static double XconvergenceFine = 1e-10;
static double smallF = 1e-20;
}

View file

@ -5,4 +5,6 @@ public interface System {
double[] params();
void gradient(double[] out);
int pSize();
}

View file

@ -0,0 +1,9 @@
package cad.gcs.constr;
import cad.gcs.Constraint;
/**
* Created by verastov
*/
public abstract class AbstractConstraint implements Constraint {
}

View file

@ -0,0 +1,15 @@
package cad.gcs.constr;
import cad.math.Vector;
import java.util.List;
public interface Constraint2 {
double error();
List<Vector> params();
List<Vector> gradient();
Object debug();
}

View file

@ -0,0 +1,17 @@
package cad.gcs.constr;
import cad.gcs.Param;
/**
* Created by verastov
*/
public class PRef {
private final Param x;
private final Param y;
public PRef(Param x, Param y) {
this.x = x;
this.y = y;
}
}

View file

@ -4,8 +4,6 @@ import cad.gcs.Constraint;
import cad.gcs.Param;
import cad.math.Vector;
import java.util.List;
public class Perpendicular implements Constraint {
public static final int l1p1x = 0;
@ -16,66 +14,187 @@ public class Perpendicular implements Constraint {
public static final int l2p1y = 5;
public static final int l2p2x = 6;
public static final int l2p2y = 7;
private final double[] params = new double[8];
public Perpendicular(Vector a1, Vector a2, Vector b1, Vector b2) {
params[l1p1x] = a1.x;
params[l1p1y] = a1.y;
params[l1p2x] = b1.x;
params[l1p2y] = b1.y;
params[l2p1x] = a2.x;
params[l2p1y] = a2.y;
params[l2p2x] = b2.x;
params[l2p2y] = b2.y;
private final Param[] params = new Param[8];
public Perpendicular(
Param _l1p1x,
Param _l1p1y,
Param _l1p2x,
Param _l1p2y,
Param _l2p1x,
Param _l2p1y,
Param _l2p2x,
Param _l2p2y
) {
params[l1p1x] = _l1p1x;
params[l1p1y] = _l1p1y;
params[l1p2x] = _l1p2x;
params[l1p2y] = _l1p2y;
params[l2p1x] = _l2p1x;
params[l2p1y] = _l2p1y;
params[l2p2x] = _l2p2x;
params[l2p2y] = _l2p2y;
}
public void out(Vector a1, Vector a2, Vector b1, Vector b2) {
a1.x = params[l1p1x];
a1.y = params[l1p1y];
b1.x = params[l1p2x];
b1.y = params[l1p2y];
a2.x = params[l2p1x];
a2.y = params[l2p1y];
b2.x = params[l2p2x];
b2.y = params[l2p2y];
public void out(Vector p1, Vector p2, Vector p3, Vector p4) {
p1.x = params[l1p1x].get();
p1.y = params[l1p1y].get();
p2.x = params[l1p2x].get();
p2.y = params[l1p2y].get();
p3.x = params[l2p1x].get();
p3.y = params[l2p1y].get();
p4.x = params[l2p2x].get();
p4.y = params[l2p2y].get();
}
@Override
public double[] params() {
return params;
double[] _params = new double[8];
_params[l1p1x] = params[l1p1x].get();
_params[l1p1y] = params[l1p1y].get();
_params[l1p2x] = params[l1p2x].get();
_params[l1p2y] = params[l1p2y].get();
_params[l2p1x] = params[l2p1x].get();
_params[l2p1y] = params[l2p1y].get();
_params[l2p2x] = params[l2p2x].get();
_params[l2p2y] = params[l2p2y].get();
return _params;
}
@Override
public double error() {
double dx1 = (params[l1p1x] - params[l1p2x]);
double dy1 = (params[l1p1y] - params[l1p2y]);
double dx2 = (params[l2p1x] - params[l2p2x]);
double dy2 = (params[l2p1y] - params[l2p2y]);
double dx1 = (params[l1p1x].get() - params[l1p2x].get());
double dy1 = (params[l1p1y].get() - params[l1p2y].get());
double dx2 = (params[l2p1x].get() - params[l2p2x].get());
double dy2 = (params[l2p1y].get() - params[l2p2y].get());
//dot product shows how the lines off to be perpendicular
double off = dx1 * dx2 + dy1 * dy2;
return off;
return off * off;
}
//derivative of ((x-a1)*a2 + a3)^2
public double partDerivative1(double a1, double a2, double a3, double x) {
return 2*a2*(-a1*a2 + a2*x+a3);
}
//derivative of ((a1-x)*a2 + a3)^2
public double partDerivative2(double a1, double a2, double a3, double x) {
return -2*a2*(a1*a2 - a2*x+a3);
}
@Override
public void gradient(double[] out) {
out[l1p1x] = (params[l2p1x] - params[l2p2x]); // = dx2
out[l1p2x] = -(params[l2p1x] - params[l2p2x]); // = -dx2
out[l1p1y] = (params[l2p1y] - params[l2p2y]); // = dy2
out[l1p2y] = -(params[l2p1y] - params[l2p2y]); // = -dy2
out[l2p1x] = (params[l1p1x] - params[l1p2x]); // = dx1
out[l2p2x] = -(params[l1p1x] - params[l1p2x]); // = -dx1
out[l2p1y] = (params[l1p1y] - params[l1p2y]); // = dy1
out[l2p2y] = -(params[l1p1y] - params[l1p2y]); // = -dy1
// for (int i = 0; i < out.length; i++) {
// out[i] *= err;
// }
double x1 = params[l1p1x].get();
double x2 = params[l1p1y].get();
double x3 = params[l1p2x].get();
double x4 = params[l1p2y].get();
double x5 = params[l2p1x].get();
double x6 = params[l2p1y].get();
double x7 = params[l2p2x].get();
double x8 = params[l2p2y].get();
double c1 = x3 - x1;
double c2 = x7 - x5;
double c3 = x4 - x2;
double c4 = x8 - x6;
//f(x) = ( (x3 - x1) * (x7 - x5) + (x4 - x2) * (x8 - x6) ) ^ 2
out[l1p1x] = partDerivative2(x3, c2, c3 * c4, x1);
out[l1p1y] = partDerivative2(x4, c4, c1 * c2, x2);
out[l1p2x] = partDerivative1(x1, c2, c3 * c4, x3);
out[l1p2y] = partDerivative1(x2, c4, c1 * c2, x4);
out[l2p1x] = partDerivative2(x7, c1, c3 * c4, x5);
out[l2p1y] = partDerivative2(x8, c3, c1 * c2, x6);
out[l2p2x] = partDerivative1(x5, c1, c3 * c4, x7);
out[l2p2y] = partDerivative1(x6, c3, c1 * c2, x8);
}
public void gradient2(double[] out) {
Vector p1 = new Vector();
Vector p2 = new Vector();
Vector p3 = new Vector();
Vector p4 = new Vector();
out(p1, p2, p3, p4);
Vector da = p2.minus(p1);
Vector db = p4.minus(p3);
double k = (da.dot(db) * 2);
Vector g1 = p1.multi(db.x, db.y, db.z).multi(-k);
Vector g2 = p2.multi(db.x, db.y, db.z).multi(k);
Vector g3 = p3.multi(da.x, da.y, da.z).multi(-k);
Vector g4 = p4.multi(da.x, da.y, da.z).multi(k);
out[l1p1x] = g1.x; // = dx2
out[l1p1y] = g1.y; // = dx2
out[l1p2x] = g2.x;
out[l1p2y] = g2.y;
out[l2p1x] = g3.x;
out[l2p1y] = g3.y;
out[l2p2x] = g4.x;
out[l2p2y] = g4.y;
}
@Override
public void step(double alpha) {
System.out.println(angle());
step(l1p1x, l1p1y, params[l2p1x].get() - params[l2p2x].get(), params[l2p1y].get() - params[l2p2y].get(), alpha);
step(l1p2x, l1p2y, -(params[l2p1x].get() - params[l2p2x].get()), -(params[l2p1y].get() - params[l2p2y].get()), alpha);
step(l2p1x, l2p1y, (params[l1p1x].get() - params[l1p2x].get()), (params[l1p1y].get() - params[l1p2y].get()), alpha);
step(l2p2x, l2p2y, -(params[l1p1x].get() - params[l1p2x].get()), -(params[l1p1y].get() - params[l1p2y].get()), alpha);
}
public double angle() {
double dx1 = (params[l1p2x].get() - params[l1p1x].get());
double dy1 = (params[l1p2y].get() - params[l1p1y].get());
double dx2 = (params[l2p2x].get() - params[l2p1x].get());
double dy2 = (params[l2p2y].get() - params[l2p1y].get());
//dot product shows how the lines off to be perpendicular
double xl = Math.sqrt(dx1 * dx1 + dx2 * dx2);
double yl = Math.sqrt(dy1*dy1 + dy2*dy2);
double off = (dx1 * dx2 + dy1 * dy2) / (xl*yl);
return Math.acos(off) / Math.PI * 180;
}
private void step(int px, int py, double gx, double gy, double alpha) {
Vector dd = new Vector(gx, gy).normalize().multi(alpha);
Vector n = new Vector(params[px].get(), params[py].get()).plus(dd);
params[px].set(n.x);
params[py].set(n.y);
}
@Override
public int pSize() {
return 8;
}
@Override
public void set(double[] input) {
System.arraycopy(input, 0, params, 0, params.length);
params[l1p1x].set(input[l1p1x]);
params[l1p1y].set(input[l1p1y]);
params[l1p2x].set(input[l1p2x]);
params[l1p2y].set(input[l1p2y]);
params[l2p1x].set(input[l2p1x]);
params[l2p1y].set(input[l2p1y]);
params[l2p2x].set(input[l2p2x]);
params[l2p2y].set(input[l2p2y]);
}
}

View file

@ -0,0 +1,74 @@
package cad.gcs.constr;
import cad.math.Vector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Perpendicular2 implements Constraint2 {
public final Vector a1;
public final Vector a2;
public final Vector b1;
public final Vector b2;
private double target;
public Perpendicular2(Vector a1, Vector a2, Vector b1, Vector b2) {
this.a1 = a1;
this.a2 = a2;
this.b1 = b1;
this.b2 = b2;
this.target = target;
}
@Override
public double error() {
return da().dot(db());
}
@Override
public List<Vector> params() {
return Arrays.asList(a1, a2, b1, b2);
}
@Override
public List<Vector> gradient() {
List<Vector> grad = new ArrayList<>(4);
// Vector da = da();
// Vector db = db();
// double k = da().dot(db()) > 0 ? -1 : 1;
//// double k = 1;
// grad.add(db.multi(- k));
// grad.add(db.multi( k));
// grad.add(da.multi(- k));
// grad.add(da.multi( k));
// return grad;
double k = (da().dot(db()) * 2);
Vector da = da();
Vector db = db();
grad.add(a1.multi(db.x, db.y, db.z).multi(-1));
grad.add(a2.multi(db.x, db.y, db.z));
grad.add(b1.multi(da.x, da.y, da.z).multi(-1));
grad.add(b2.multi(da.x, da.y, da.z));
return grad;
}
private Vector db() {
return b2.minus(b1);
}
private Vector da() {
return a2.minus(a1);
}
@Override
public Object debug() {
return Math.acos(error() / (da().length() * db().length()) ) / Math.PI * 180;
}
}

163
src/cad/gcs/constr/X.java Normal file
View file

@ -0,0 +1,163 @@
package cad.gcs.constr;
import cad.gcs.Constraint;
import cad.gcs.Param;
import cad.math.Vector;
public class X implements Constraint {
public static final int l1p1x = 0;
public static final int l1p1y = 1;
public static final int l1p2x = 2;
public static final int l1p2y = 3;
public static final int l2p1x = 4;
public static final int l2p1y = 5;
public static final int l2p2x = 6;
public static final int l2p2y = 7;
private final Param[] params = new Param[8];
public X(
Param _l1p1x,
Param _l1p1y,
Param _l1p2x,
Param _l1p2y,
Param _l2p1x,
Param _l2p1y,
Param _l2p2x,
Param _l2p2y
) {
params[l1p1x] = _l1p1x;
params[l1p1y] = _l1p1y;
params[l1p2x] = _l1p2x;
params[l1p2y] = _l1p2y;
params[l2p1x] = _l2p1x;
params[l2p1y] = _l2p1y;
params[l2p2x] = _l2p2x;
params[l2p2y] = _l2p2y;
}
public void out(Vector p1, Vector p2, Vector p3, Vector p4) {
p1.x = params[l1p1x].get();
p1.y = params[l1p1y].get();
p2.x = params[l1p2x].get();
p2.y = params[l1p2y].get();
p3.x = params[l2p1x].get();
p3.y = params[l2p1y].get();
p4.x = params[l2p2x].get();
p4.y = params[l2p2y].get();
}
public double valueX() {
return (params[l2p2x].get() - params[l2p1x].get()) * .5 - (params[l1p2x].get() - params[l1p1x].get()) * .5;
}
public double valueY() {
return (params[l2p2y].get() - params[l2p1y].get()) * .5 - (params[l1p2y].get() - params[l1p1y].get()) * .5;
}
@Override
public double[] params() {
double[] _params = new double[8];
_params[l1p1x] = params[l1p1x].get();
_params[l1p1y] = params[l1p1y].get();
_params[l1p2x] = params[l1p2x].get();
_params[l1p2y] = params[l1p2y].get();
_params[l2p1x] = params[l2p1x].get();
_params[l2p1y] = params[l2p1y].get();
_params[l2p2x] = params[l2p2x].get();
_params[l2p2y] = params[l2p2y].get();
return _params;
}
@Override
public double error() {
double v = valueX() + valueY();
return v;
}
@Override
public void gradient(double[] out) {
double valueX = valueX();
double valueY = valueY();
Vector p1 = new Vector();
Vector p2 = new Vector();
Vector p3 = new Vector();
Vector p4 = new Vector();
out(p1, p2, p3, p4);
Vector da = p2.minus(p1);
Vector db = p4.minus(p3);
Vector g1 = p1.multi(valueX, valueY, 0);
Vector g2 = p2.multi(valueX, valueY, 0).multi(-1);
Vector g3 = p3.multi(valueX, valueY, 0).multi(-1);
Vector g4 = p4.multi(valueX, valueY, 0);
out[l1p1x] = g1.x; // = dx2
out[l1p1y] = g1.y; // = dx2
out[l1p2x] = g2.x;
out[l1p2y] = g2.y;
out[l2p1x] = g3.x;
out[l2p1y] = g3.y;
out[l2p2x] = g4.x;
out[l2p2y] = g4.y;
}
@Override
public void step(double alpha) {
System.out.println(angle());
step(l1p1x, l1p1y, params[l2p1x].get() - params[l2p2x].get(), params[l2p1y].get() - params[l2p2y].get(), alpha);
step(l1p2x, l1p2y, -(params[l2p1x].get() - params[l2p2x].get()), -(params[l2p1y].get() - params[l2p2y].get()), alpha);
step(l2p1x, l2p1y, (params[l1p1x].get() - params[l1p2x].get()), (params[l1p1y].get() - params[l1p2y].get()), alpha);
step(l2p2x, l2p2y, -(params[l1p1x].get() - params[l1p2x].get()), -(params[l1p1y].get() - params[l1p2y].get()), alpha);
}
public double angle() {
double dx1 = (params[l1p1x].get() - params[l1p2x].get());
double dy1 = (params[l1p1y].get() - params[l1p2y].get());
double dx2 = (params[l2p1x].get() - params[l2p2x].get());
double dy2 = (params[l2p1y].get() - params[l2p2y].get());
//dot product shows how the lines off to be perpendicular
double xl = Math.abs(dx1 * dx1 - dx2 * dx2);
double yl = Math.abs(dy1*dy1 - dy2*dy2);
double off = (dx1 * dx2 + dy1 * dy2) / (xl*yl);
return Math.acos(off) / Math.PI * 180;
}
private void step(int px, int py, double gx, double gy, double alpha) {
Vector dd = new Vector(gx, gy).normalize().multi(alpha);
Vector n = new Vector(params[px].get(), params[py].get()).plus(dd);
params[px].set(n.x);
params[py].set(n.y);
}
@Override
public int pSize() {
return 8;
}
@Override
public void set(double[] input) {
params[l1p1x].set(input[l1p1x]);
params[l1p1y].set(input[l1p1y]);
params[l1p2x].set(input[l1p2x]);
params[l1p2y].set(input[l1p2y]);
params[l2p1x].set(input[l2p1x]);
params[l2p1y].set(input[l2p1y]);
params[l2p2x].set(input[l2p2x]);
params[l2p2y].set(input[l2p2y]);
}
}

View file

@ -0,0 +1,45 @@
package cad.gcs.constr;
import cad.math.Vector;
import java.util.Collections;
import java.util.List;
/**
* Created by verastov
*/
public class XY implements Constraint2 {
private final Vector point;
private final Vector lock;
public XY(Vector point, Vector lock) {
this.point = point;
this.lock = lock;
}
public Vector diff() {
return lock.minus(point);
}
@Override
public double error() {
Vector diff = diff();
return diff.x * diff.x + diff.y * diff.y;
}
@Override
public List<Vector> params() {
return Collections.singletonList(point);
}
@Override
public List<Vector> gradient() {
return Collections.singletonList(diff());
}
@Override
public Object debug() {
return point;
}
}

View file

@ -1,11 +1,9 @@
package cad.gl;
import cad.fx.Polygon;
import cad.math.Vector;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.opengl.GLWindow;
import com.sun.javafx.geom.*;
import javafx.scene.input.PickResult;
import javax.media.opengl.GL2;
@ -154,7 +152,7 @@ public class Scene implements GLEventListener, MouseListener {
// Vector dir = pickRay[1].minus(pickRay[0]);
// pickRay[1] = pickRay[1].minus(pickRay[0]).scale(700);//.normalize().scale(55);
pickRay[1] = pickRay[1].minus(pickRay[0]).normalize().scale(30);
pickRay[1] = pickRay[1].minus(pickRay[0]).normalize().multi(30);
}
public static float[] fixW(float[] v) {

View file

@ -53,11 +53,11 @@ public class Vector {
this.z = data[2];
}
public Vector scale(double factor) {
return scale(factor, factor, factor);
public Vector multi(double factor) {
return multi(factor, factor, factor);
}
public Vector scale(double dx, double dy, double dz) {
public Vector multi(double dx, double dy, double dz) {
return new Vector(x * dx, y * dy, z * dz);
}
@ -83,7 +83,14 @@ public class Vector {
}
public Vector plus(Vector vector) {
return new Vector(x + vector.x, y + vector.y, z + vector.z);
return new Vector(this)._plus(vector);
}
public Vector _plus(Vector vector) {
x += vector.x;
y += vector.y;
z += vector.z;
return this;
}
public Vector plus(double dx, double dy, double dz) {
@ -118,7 +125,7 @@ public class Vector {
}
public Vector negate() {
return scale(-1);
return multi(-1);
}
}