jsketcher/web/app/sketcher/constr/AlgNumSystem.js
Val Erastov (xibyte) 58f3ac1846 checkpoint
2020-01-14 22:04:47 -08:00

247 lines
6.5 KiB
JavaScript

import {createByConstraintName} from "./solverConstraints";
import {Param, prepare} from "./solver";
import {findConstructionCluster} from "./constructions";
import {GCCircle, GCPoint} from "./constractibles";
import {eqEps, eqTol} from "../../brep/geom/tolerance";
import {Polynomial, POW_1_FN} from "./polynomial";
import {compositeFn, NOOP} from "../../../../modules/gems/func";
export class AlgNumSubSystem {
generator = NOOP;//new BoundaryObjectsGenerator();
constraints = [];
ownParams = new Set();
readOnlyParams = new Set();
generatedParams = new Set();
beingSolvedParams = new Set();
// generators = [];
subSystems = []; //subsystems are generated by generators only
polynomials = [];
substitutedParams = [];
polyToConstr = new Map();
conflicting = new Set();
redundant = new Set();
SubSystem(generator) {
this.generator = generator;
}
addConstraint(constraint, _ancestorParams) {
if (this.canBeAdded(constraint.params)) {
// this.constraints.push(constraint);
// this.constraints
}
this.constraints.push(constraint);
}
reset() {
this.polynomials = [];
this.substitutedParams = [];
this.polyToConstr.clear();
this.conflicting.clear();
this.redundant.clear();
this.beingSolvedParams.clear();
}
evaluatePolynomials() {
this.constraints.forEach(c => {
c.collectPolynomials(this.polynomials);
this.polynomials.forEach(p => this.polyToConstr.set(p, c))
});
console.log('reducing system:');
this.polynomials.forEach(p => console.log(p.toString()));
const toEliminate = Array.from(this.readOnlyParams);
const toSubstitute = [];
const linearSub = [];
let requirePass = true;
while (requirePass) {
requirePass = false;
for (let i = 0; i < this.polynomials.length; ++i) {
const polynomial = this.polynomials[i];
if (!polynomial) {
continue;
}
if (polynomial.monomials.length === 0) {
if (!eqEps(polynomial.constant, 0)) {
this.conflicting.add(this.polyToConstr.get(polynomial));
}
this.polynomials[i] = null;
} else if (polynomial.monomials.length === 1) {
const monomial = polynomial.monomials[0];
const terms = monomial.terms;
if (terms.length === 1) {
const term = terms[0];
if (term.fn.degree === 1) {
term.param.set(- polynomial.constant / monomial.constant);
toEliminate.push(term.param);
}
}
this.polynomials[i] = null;
} else if (polynomial.monomials.length === 2 && polynomial.isLinear) {
const [m1, m2] = polynomial.monomials;
const constant = - m2.constant / m1.constant;
if (eqEps(polynomial.constant, 0)) {
toSubstitute.push([m1.linearParam, m2.linearParam, constant]);
this.substitutedParams.push([m1.linearParam, new Polynomial().monomial(constant).term(m2.linearParam, POW_1_FN)]);
} else {
linearSub.push([m1.param, m2.param, constant, - polynomial.constant / m1.constant]);
}
this.polynomials[i] = null;
}
}
while (toEliminate.length) {
requirePass = true;
const param = toEliminate.pop();
for (let polynomial of this.polynomials) {
if (polynomial) {
polynomial.eliminate(param, param.get());
}
}
}
while (toSubstitute.length) {
requirePass = true;
const [param, toParam, dotConstant] = toSubstitute.pop();
for (let polynomial of this.polynomials) {
if (polynomial) {
polynomial.substitute(param, toParam, dotConstant);
}
}
}
if (linearSub.length) {
while (linearSub.length) {
const [param, toParam, k, b] = linearSub.pop();
let transaction = compositeFn();
for (let polynomial of this.polynomials) {
if (polynomial) {
const polyTransaction = polynomial.linearSubstitution(param, toParam, k, b);
if (!polyTransaction) {
transaction = null;
break;
}
transaction.push(polyTransaction);
transaction.push(() => this.substitutedParams.push(param, new Polynomial(b).monomial(k).term(toParam, POW_1_FN)));
}
}
if (transaction) {
requirePass = true;
transaction();
}
}
}
if (requirePass) {
this.polynomials.forEach(polynomial => polynomial && polynomial.compact());
}
}
this.polynomials = this.polynomials.filter(p => p);
}
prepare() {
this.reset();
this.evaluatePolynomials();
console.log('solving system:');
this.polynomials.forEach(p => console.log(p.toString()));
console.log('with respect to:');
this.substitutedParams.forEach(([x, expr]) => console.log('X' + x.id + ' = ' + expr.toString()));
const residuals = [];
this.polynomials.forEach(p => residuals.push(p.asResidual()));
for (let residual of residuals) {
residual.params.forEach(solverParam => {
if (!this.beingSolvedParams.has(solverParam)) {
solverParam.reset(solverParam.objectParam.get());
this.beingSolvedParams.add(solverParam);
}
});
}
this.numericalSolver = prepare(residuals);
}
solve(rough) {
this.generator();
this.beingSolvedParams.forEach(solverParam => {
solverParam.set(solverParam.objectParam.get());
});
this.numericalSolver.solveSystem(rough);
this.beingSolvedParams.forEach(solverParam => {
solverParam.objectParam.set(solverParam.get());
});
for (let i = this.substitutedParams.length - 1; i >= 0; i--) {
let [param, expression] = this.substitutedParams[i];
param.set(expression.value());
}
}
canBeAdded(subjectParams, ancestorParams) {
for (let p of subjectParams) {
if (!this.ownParams.has(p) && (!ancestorParams || !ancestorParams.has(p))) {
return false;
}
}
return true;
}
}
export class AlgNumSystem {
constraints = [];
generators = [];
locked = new Set();
constantParams = new Set();
constructor(visitAllObjects) {
this.visitAllObjects = visitAllObjects;
}
addConstraint(constraint) {
this.constraints.push(constraint);
if (constraint.schema.generator) {
}
}
startTransaction(interactiveLock = []) {
this.systemTransaction.prepare(interactiveLock);
return this.systemTransaction;
}
}