Speed up the inconsistent constraint detection; there's no reason

not to solve by substitution before rank testing. And report the
unsatisfied constraints when we don't converge.

[git-p4: depot-paths = "//depot/solvespace/": change = 1874]
This commit is contained in:
Jonathan Westhues 2008-09-05 03:25:53 -08:00
parent 33654c7ce7
commit 92f55dd195
4 changed files with 73 additions and 30 deletions

View File

@ -554,6 +554,9 @@ public:
class hEquation {
public:
DWORD v;
inline bool isFromConstraint(void);
inline hConstraint constraint(void);
};
class Equation {
@ -599,5 +602,10 @@ inline hRequest hParam::request(void)
inline hEquation hConstraint::equation(int i)
{ hEquation r; r.v = (v << 16) | i; return r; }
inline bool hEquation::isFromConstraint(void)
{ if(v & 0xc0000000) return false; else return true; }
inline hConstraint hEquation::constraint(void)
{ hConstraint r; r.v = (v >> 16); return r; }
#endif

View File

@ -212,7 +212,7 @@ public:
} B;
} mat;
static const double RANK_MAG_TOLERANCE;
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
int CalculateRank(void);
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
double B[], int N);

View File

@ -1,6 +1,7 @@
#include "solvespace.h"
const double System::RANK_MAG_TOLERANCE = 1e-4;
const double System::CONVERGE_TOLERANCE = 1e-10;
void System::WriteJacobian(int tag) {
int a, i, j;
@ -328,7 +329,7 @@ bool System::NewtonSolve(int tag) {
if(isnan(mat.B.num[i])) {
return false;
}
if(fabs(mat.B.num[i]) > 1e-10) {
if(fabs(mat.B.num[i]) > CONVERGE_TOLERANCE) {
converged = false;
break;
}
@ -360,18 +361,31 @@ void System::WriteEquationsExceptFor(hConstraint hc, hGroup hg) {
}
void System::FindWhichToRemoveToFixJacobian(Group *g) {
int i;
int a, i;
(g->solved.remove).Clear();
for(a = 0; a < 2; a++) {
for(i = 0; i < SS.constraint.n; i++) {
Constraint *c = &(SS.constraint.elem[i]);
if(c->group.v != g->h.v) continue;
if((c->type == Constraint::POINTS_COINCIDENT && a == 0) ||
(c->type != Constraint::POINTS_COINCIDENT && a == 1))
{
// Do the constraints in two passes: first everything but
// the point-coincident constraints, then only those
// constraints (so they appear last in the list).
continue;
}
param.ClearTags();
eq.Clear();
WriteEquationsExceptFor(c->h, g->h);
eq.ClearTags();
// It's a major speedup to solve the easy ones by substitution here,
// and that doesn't break anything.
SolveBySubstitution();
WriteJacobian(0);
EvalJacobian();
@ -382,6 +396,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
}
}
}
}
void System::Solve(Group *g) {
g->solved.remove.Clear();
@ -476,6 +491,25 @@ void System::Solve(Group *g) {
didnt_converge:
g->solved.how = Group::DIDNT_CONVERGE;
(g->solved.remove).Clear();
SS.constraint.ClearTags();
for(i = 0; i < eq.n; i++) {
if(fabs(mat.B.num[i]) > CONVERGE_TOLERANCE) {
// This constraint is unsatisfied.
if(!mat.eq[i].isFromConstraint()) continue;
hConstraint hc = mat.eq[i].constraint();
Constraint *c = SS.constraint.FindByIdNoOops(hc);
if(!c) continue;
// Don't double-show constraints that generated multiple
// unsatisfied equations
if(!c->tag) {
(g->solved.remove).Add(&(c->h));
c->tag = 1;
}
}
}
TextWindow::ReportHowGroupSolved(g->h);
}

View File

@ -510,11 +510,15 @@ void TextWindow::ShowGroupSolveInfo(void) {
switch(g->solved.how) {
case Group::DIDNT_CONVERGE:
Printf(true, "%FxSOLVE FAILED!%Fd no convergence");
Printf(true, "the following constraints are unsatisfied");
break;
case Group::SINGULAR_JACOBIAN: {
case Group::SINGULAR_JACOBIAN:
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
Printf(true, "remove any one of these to fix it");
break;
}
for(int i = 0; i < g->solved.remove.n; i++) {
hConstraint hc = g->solved.remove.elem[i];
Constraint *c = SS.constraint.FindByIdNoOops(hc);
@ -526,9 +530,6 @@ void TextWindow::ShowGroupSolveInfo(void) {
(&TextWindow::ScreenHoverConstraint),
c->DescriptionString());
}
break;
}
}
Printf(true, "It may be possible to fix the problem ");
Printf(false, "by selecting Edit -> Undo.");