Little optimizations in the solver; don't write the Jacobian

redundantly, more zero partial avoidance, slight speedup to linear
system solve.

[git-p4: depot-paths = "//depot/solvespace/": change = 1940]
solver
Jonathan Westhues 2009-04-18 19:55:46 -08:00
parent 16de9a485a
commit bab13b821f
4 changed files with 25 additions and 11 deletions

View File

@ -364,10 +364,10 @@ Expr *Expr::PartialWrt(hParam p) {
}
}
DWORD Expr::ParamsUsed(void) {
DWORD r = 0;
if(op == PARAM) r |= (1 << (x.parh.v % 31));
if(op == PARAM_PTR) r |= (1 << (x.parp->h.v % 31));
QWORD Expr::ParamsUsed(void) {
QWORD r = 0;
if(op == PARAM) r |= ((QWORD)1 << (x.parh.v % 61));
if(op == PARAM_PTR) r |= ((QWORD)1 << (x.parp->h.v % 61));
int c = Children();
if(c >= 1) r |= a->ParamsUsed();
@ -375,6 +375,16 @@ DWORD Expr::ParamsUsed(void) {
return r;
}
bool Expr::DependsOn(hParam p) {
if(op == PARAM) return (x.parh.v == p.v);
if(op == PARAM_PTR) return (x.parp->h.v == p.v);
int c = Children();
if(c == 1) return a->DependsOn(p);
if(c == 2) return a->DependsOn(p) || b->DependsOn(p);
return false;
}
bool Expr::Tol(double a, double b) {
return fabs(a - b) < 0.001;
}

3
expr.h
View File

@ -77,7 +77,8 @@ public:
Expr *PartialWrt(hParam p);
double Eval(void);
DWORD ParamsUsed(void);
QWORD ParamsUsed(void);
bool DependsOn(hParam p);
static bool Tol(double a, double b);
Expr *FoldConstants(void);
void Substitute(hParam oldh, hParam newh);

View File

@ -43,6 +43,7 @@ inline double WRAP_SYMMETRIC(double v, double n) {
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
typedef unsigned __int64 QWORD;
typedef signed long SDWORD;
typedef signed short SWORD;
@ -201,7 +202,7 @@ void MakePathAbsolute(char *base, char *path);
class System {
public:
#define MAX_UNKNOWNS 200
#define MAX_UNKNOWNS 1000
EntityList entity;
ParamList param;

View File

@ -24,11 +24,13 @@ void System::WriteJacobian(int tag) {
Expr *f = e->e->DeepCopyWithParamsAsPointers(&param, &(SS.param));
f = f->FoldConstants();
// Hash table (31 bits) to accelerate generation of zero partials.
DWORD scoreboard = f->ParamsUsed();
// Hash table (61 bits) to accelerate generation of zero partials.
QWORD scoreboard = f->ParamsUsed();
for(j = 0; j < mat.n; j++) {
Expr *pd;
if(scoreboard & (1 << (mat.param[j].v % 31))) {
if(scoreboard & ((QWORD)1 << (mat.param[j].v % 61)) &&
f->DependsOn(mat.param[j]))
{
pd = f->PartialWrt(mat.param[j]);
pd = pd->FoldConstants();
pd = pd->DeepCopyWithParamsAsPointers(&param, &(SS.param));
@ -225,7 +227,7 @@ bool System::SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
for(ip = i+1; ip < n; ip++) {
temp = A[ip][i]/A[i][i];
for(jp = 0; jp < n; jp++) {
for(jp = i; jp < n; jp++) {
A[ip][jp] -= temp*(A[i][jp]);
}
B[ip] -= temp*B[i];
@ -291,7 +293,6 @@ bool System::SolveLeastSquares(void) {
}
bool System::NewtonSolve(int tag) {
WriteJacobian(tag);
if(mat.m > mat.n) return false;
int iter = 0;
@ -438,6 +439,7 @@ void System::Solve(Group *g, bool andFindFree) {
e->tag = alone;
p->tag = alone;
WriteJacobian(alone);
if(!NewtonSolve(alone)) {
// Failed to converge, bail out early
goto didnt_converge;