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 { class hEquation {
public: public:
DWORD v; DWORD v;
inline bool isFromConstraint(void);
inline hConstraint constraint(void);
}; };
class Equation { class Equation {
@ -599,5 +602,10 @@ inline hRequest hParam::request(void)
inline hEquation hConstraint::equation(int i) inline hEquation hConstraint::equation(int i)
{ hEquation r; r.v = (v << 16) | i; return r; } { 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 #endif

View File

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

View File

@ -1,6 +1,7 @@
#include "solvespace.h" #include "solvespace.h"
const double System::RANK_MAG_TOLERANCE = 1e-4; const double System::RANK_MAG_TOLERANCE = 1e-4;
const double System::CONVERGE_TOLERANCE = 1e-10;
void System::WriteJacobian(int tag) { void System::WriteJacobian(int tag) {
int a, i, j; int a, i, j;
@ -328,7 +329,7 @@ bool System::NewtonSolve(int tag) {
if(isnan(mat.B.num[i])) { if(isnan(mat.B.num[i])) {
return false; return false;
} }
if(fabs(mat.B.num[i]) > 1e-10) { if(fabs(mat.B.num[i]) > CONVERGE_TOLERANCE) {
converged = false; converged = false;
break; break;
} }
@ -360,18 +361,31 @@ void System::WriteEquationsExceptFor(hConstraint hc, hGroup hg) {
} }
void System::FindWhichToRemoveToFixJacobian(Group *g) { void System::FindWhichToRemoveToFixJacobian(Group *g) {
int i; int a, i;
(g->solved.remove).Clear(); (g->solved.remove).Clear();
for(a = 0; a < 2; a++) {
for(i = 0; i < SS.constraint.n; i++) { for(i = 0; i < SS.constraint.n; i++) {
Constraint *c = &(SS.constraint.elem[i]); Constraint *c = &(SS.constraint.elem[i]);
if(c->group.v != g->h.v) continue; 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(); param.ClearTags();
eq.Clear(); eq.Clear();
WriteEquationsExceptFor(c->h, g->h); WriteEquationsExceptFor(c->h, g->h);
eq.ClearTags(); eq.ClearTags();
// It's a major speedup to solve the easy ones by substitution here,
// and that doesn't break anything.
SolveBySubstitution();
WriteJacobian(0); WriteJacobian(0);
EvalJacobian(); EvalJacobian();
@ -382,6 +396,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
} }
} }
} }
}
void System::Solve(Group *g) { void System::Solve(Group *g) {
g->solved.remove.Clear(); g->solved.remove.Clear();
@ -476,6 +491,25 @@ void System::Solve(Group *g) {
didnt_converge: didnt_converge:
g->solved.how = Group::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); TextWindow::ReportHowGroupSolved(g->h);
} }

View File

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