A ~10x speedup in the solver. Simplify equations before evaluating
or taking partials (constant folding). Also keep a little hash table to mark with params are used in each equation, in order to quickly discard trivial partial derivatives. This is solving a 64x64 system in <20 ms. I suspect this is now much faster than Sketchflat. Slightly fake situation, though, since substitution solver has not yet been written, and no partitioning. I'll do those next. [git-p4: depot-paths = "//depot/solvespace/": change = 1698]
This commit is contained in:
parent
70bf14530d
commit
60925e4040
82
expr.cpp
82
expr.cpp
@ -186,7 +186,7 @@ Expr *Expr::PartialWrt(hParam p) {
|
|||||||
Expr *da, *db;
|
Expr *da, *db;
|
||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case PARAM_PTR: oops();
|
case PARAM_PTR: return FromConstant(p.v == x.parp->h.v ? 1 : 0);
|
||||||
case PARAM: return FromConstant(p.v == x.parh.v ? 1 : 0);
|
case PARAM: return FromConstant(p.v == x.parh.v ? 1 : 0);
|
||||||
|
|
||||||
case CONSTANT: return FromConstant(0);
|
case CONSTANT: return FromConstant(0);
|
||||||
@ -218,6 +218,86 @@ 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));
|
||||||
|
|
||||||
|
int c = Children();
|
||||||
|
if(c >= 1) r |= a->ParamsUsed();
|
||||||
|
if(c >= 2) r |= b->ParamsUsed();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Expr::Tol(double a, double b) {
|
||||||
|
return fabs(a - b) < 0.001;
|
||||||
|
}
|
||||||
|
Expr *Expr::FoldConstants(void) {
|
||||||
|
Expr *n = AllocExpr();
|
||||||
|
*n = *this;
|
||||||
|
|
||||||
|
int c = Children();
|
||||||
|
if(c >= 1) n->a = a->FoldConstants();
|
||||||
|
if(c >= 2) n->b = b->FoldConstants();
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
case PARAM_PTR:
|
||||||
|
case PARAM:
|
||||||
|
case CONSTANT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MINUS:
|
||||||
|
case TIMES:
|
||||||
|
case DIV:
|
||||||
|
case PLUS:
|
||||||
|
// If both ops are known, then we can evaluate immediately
|
||||||
|
if(n->a->op == CONSTANT && n->b->op == CONSTANT) {
|
||||||
|
double nv = n->Eval();
|
||||||
|
n->op = CONSTANT;
|
||||||
|
n->x.v = nv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// x + 0 = 0 + x = x
|
||||||
|
if(op == PLUS && n->b->op == CONSTANT && Tol(n->b->x.v, 0)) {
|
||||||
|
*n = *(n->a); break;
|
||||||
|
}
|
||||||
|
if(op == PLUS && n->a->op == CONSTANT && Tol(n->a->x.v, 0)) {
|
||||||
|
*n = *(n->b); break;
|
||||||
|
}
|
||||||
|
// 1*x = x*1 = x
|
||||||
|
if(op == TIMES && n->b->op == CONSTANT && Tol(n->b->x.v, 1)) {
|
||||||
|
*n = *(n->a); break;
|
||||||
|
}
|
||||||
|
if(op == TIMES && n->a->op == CONSTANT && Tol(n->a->x.v, 1)) {
|
||||||
|
*n = *(n->b); break;
|
||||||
|
}
|
||||||
|
// 0*x = x*0 = 0
|
||||||
|
if(op == TIMES && n->b->op == CONSTANT && Tol(n->b->x.v, 0)) {
|
||||||
|
n->op = CONSTANT; n->x.v = 0; break;
|
||||||
|
}
|
||||||
|
if(op == TIMES && n->a->op == CONSTANT && Tol(n->a->x.v, 0)) {
|
||||||
|
n->op = CONSTANT; n->x.v = 0; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQRT:
|
||||||
|
case SQUARE:
|
||||||
|
case NEGATE:
|
||||||
|
case SIN:
|
||||||
|
case COS:
|
||||||
|
if(n->a->op == CONSTANT) {
|
||||||
|
double nv = n->Eval();
|
||||||
|
n->op = CONSTANT;
|
||||||
|
n->x.v = nv;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: oops();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static char StringBuffer[4096];
|
static char StringBuffer[4096];
|
||||||
void Expr::App(char *s, ...) {
|
void Expr::App(char *s, ...) {
|
||||||
va_list f;
|
va_list f;
|
||||||
|
3
expr.h
3
expr.h
@ -73,6 +73,9 @@ public:
|
|||||||
|
|
||||||
Expr *PartialWrt(hParam p);
|
Expr *PartialWrt(hParam p);
|
||||||
double Eval(void);
|
double Eval(void);
|
||||||
|
DWORD ParamsUsed(void);
|
||||||
|
static bool Tol(double a, double b);
|
||||||
|
Expr *FoldConstants(void);
|
||||||
|
|
||||||
void ParamsToPointers(void);
|
void ParamsToPointers(void);
|
||||||
|
|
||||||
|
1
file.cpp
1
file.cpp
@ -11,6 +11,7 @@ void SolveSpace::NewFile(void) {
|
|||||||
// Our initial group, that contains the references.
|
// Our initial group, that contains the references.
|
||||||
Group g;
|
Group g;
|
||||||
memset(&g, 0, sizeof(g));
|
memset(&g, 0, sizeof(g));
|
||||||
|
g.visible = true;
|
||||||
g.name.strcpy("#references");
|
g.name.strcpy("#references");
|
||||||
g.type = Group::DRAWING;
|
g.type = Group::DRAWING;
|
||||||
g.h = Group::HGROUP_REFERENCES;
|
g.h = Group::HGROUP_REFERENCES;
|
||||||
|
25
system.cpp
25
system.cpp
@ -18,12 +18,22 @@ void System::WriteJacobian(int eqTag, int paramTag) {
|
|||||||
if(e->tag != eqTag) continue;
|
if(e->tag != eqTag) continue;
|
||||||
|
|
||||||
mat.eq[i] = e->h;
|
mat.eq[i] = e->h;
|
||||||
mat.B.sym[i] = e->e->DeepCopyWithParamsAsPointers(¶m, &(SS.param));
|
Expr *f = e->e->DeepCopyWithParamsAsPointers(¶m, &(SS.param));
|
||||||
|
f = f->FoldConstants();
|
||||||
|
|
||||||
|
// Hash table (31 bits) to accelerate generation of zero partials.
|
||||||
|
DWORD scoreboard = f->ParamsUsed();
|
||||||
for(j = 0; j < mat.n; j++) {
|
for(j = 0; j < mat.n; j++) {
|
||||||
Expr *pd = e->e->PartialWrt(mat.param[j]);
|
Expr *pd;
|
||||||
mat.A.sym[i][j] =
|
if(scoreboard & (1 << (mat.param[j].v % 31))) {
|
||||||
pd->DeepCopyWithParamsAsPointers(¶m, &(SS.param));
|
pd = f->PartialWrt(mat.param[j]);
|
||||||
|
pd = pd->FoldConstants();
|
||||||
|
} else {
|
||||||
|
pd = Expr::FromConstant(0);
|
||||||
}
|
}
|
||||||
|
mat.A.sym[i][j] = pd;
|
||||||
|
}
|
||||||
|
mat.B.sym[i] = f;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mat.m = i;
|
mat.m = i;
|
||||||
@ -220,7 +230,12 @@ bool System::Solve(void) {
|
|||||||
|
|
||||||
WriteJacobian(0, 0);
|
WriteJacobian(0, 0);
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
/*
|
|
||||||
|
/* dbp("write/eval jacboian=%d", GetMilliseconds() - in);
|
||||||
|
for(i = 0; i < mat.m; i++) {
|
||||||
|
dbp("function %d: %s", i, mat.B.sym[i]->Print());
|
||||||
|
}
|
||||||
|
dbp("m=%d", mat.m);
|
||||||
for(i = 0; i < mat.m; i++) {
|
for(i = 0; i < mat.m; i++) {
|
||||||
for(j = 0; j < mat.n; j++) {
|
for(j = 0; j < mat.n; j++) {
|
||||||
dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]);
|
dbp("A[%d][%d] = %.3f", i, j, mat.A.num[i][j]);
|
||||||
|
Loading…
Reference in New Issue
Block a user