Test the rank of the Jacobian by Gram-Schmidt, instead of by a
questionable tolerance on the pivot while row reducing. [git-p4: depot-paths = "//depot/solvespace/": change = 1818]
This commit is contained in:
parent
48c5018613
commit
1bc68779d9
|
@ -195,8 +195,8 @@ public:
|
||||||
} B;
|
} B;
|
||||||
} mat;
|
} mat;
|
||||||
|
|
||||||
bool Tol(double v);
|
static const double RANK_MAG_TOLERANCE;
|
||||||
int GaussJordan(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);
|
||||||
bool SolveLeastSquares(void);
|
bool SolveLeastSquares(void);
|
||||||
|
|
93
system.cpp
93
system.cpp
|
@ -1,5 +1,7 @@
|
||||||
#include "solvespace.h"
|
#include "solvespace.h"
|
||||||
|
|
||||||
|
const double System::RANK_MAG_TOLERANCE = 1e-4;
|
||||||
|
|
||||||
void System::WriteJacobian(int tag) {
|
void System::WriteJacobian(int tag) {
|
||||||
int a, i, j;
|
int a, i, j;
|
||||||
|
|
||||||
|
@ -145,67 +147,46 @@ void System::SolveBySubstitution(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::Tol(double v) {
|
//-----------------------------------------------------------------------------
|
||||||
return (fabs(v) < 0.0001);
|
// Calculate the rank of the Jacobian matrix, by Gram-Schimdt orthogonalization
|
||||||
}
|
// in place. A row (~equation) is considered to be all zeros if its magnitude
|
||||||
|
// is less than the tolerance RANK_MAG_TOLERANCE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
int System::CalculateRank(void) {
|
||||||
|
// Actually work with magnitudes squared, not the magnitudes
|
||||||
|
double rowMag[MAX_UNKNOWNS];
|
||||||
|
ZERO(&rowMag);
|
||||||
|
double tol = RANK_MAG_TOLERANCE*RANK_MAG_TOLERANCE;
|
||||||
|
|
||||||
int System::GaussJordan(void) {
|
int i, iprev, j;
|
||||||
int i, j;
|
|
||||||
|
|
||||||
// Now eliminate.
|
|
||||||
i = 0;
|
|
||||||
int rank = 0;
|
int rank = 0;
|
||||||
for(j = 0; j < mat.n; j++) {
|
|
||||||
// First, seek a pivot in our column.
|
for(i = 0; i < mat.m; i++) {
|
||||||
int ip, imax;
|
// Subtract off this row's component in the direction of any
|
||||||
double max = 0;
|
// previous rows
|
||||||
for(ip = i; ip < mat.m; ip++) {
|
for(iprev = 0; iprev < i; iprev++) {
|
||||||
double v = fabs(mat.A.num[ip][j]);
|
if(rowMag[iprev] <= tol) continue; // ignore zero rows
|
||||||
if(v > max) {
|
|
||||||
imax = ip;
|
double dot = 0;
|
||||||
max = v;
|
for(j = 0; j < mat.n; j++) {
|
||||||
|
dot += (mat.A.num[iprev][j]) * (mat.A.num[i][j]);
|
||||||
|
}
|
||||||
|
for(j = 0; j < mat.n; j++) {
|
||||||
|
mat.A.num[i][j] -= (dot/rowMag[iprev])*mat.A.num[iprev][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!Tol(max)) {
|
// Our row is now normal to all previous rows; calculate the
|
||||||
// There's a usable pivot in this column. Swap it in:
|
// magnitude of what's left
|
||||||
int js;
|
double mag = 0;
|
||||||
for(js = j; js < mat.n; js++) {
|
for(j = 0; j < mat.n; j++) {
|
||||||
double temp;
|
mag += (mat.A.num[i][j]) * (mat.A.num[i][j]);
|
||||||
temp = mat.A.num[imax][js];
|
}
|
||||||
mat.A.num[imax][js] = mat.A.num[i][js];
|
if(mag > tol) {
|
||||||
mat.A.num[i][js] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a 1 as the leading entry in the row we're working on.
|
|
||||||
double v = mat.A.num[i][j];
|
|
||||||
for(js = 0; js < mat.n; js++) {
|
|
||||||
mat.A.num[i][js] /= v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eliminate this column from rows except this one.
|
|
||||||
int is;
|
|
||||||
for(is = 0; is < mat.m; is++) {
|
|
||||||
if(is == i) continue;
|
|
||||||
|
|
||||||
// We're trying to drive A[is][j] to zero. We know
|
|
||||||
// that A[i][j] is 1, so we want to subtract off
|
|
||||||
// A[is][j] times our present row.
|
|
||||||
double v = mat.A.num[is][j];
|
|
||||||
for(js = 0; js < mat.n; js++) {
|
|
||||||
mat.A.num[is][js] -= v*mat.A.num[i][js];
|
|
||||||
}
|
|
||||||
mat.A.num[is][j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And this is a bound variable, so rank goes up by one.
|
|
||||||
rank++;
|
rank++;
|
||||||
|
|
||||||
// Move on to the next row, since we just used this one to
|
|
||||||
// eliminate from column j.
|
|
||||||
i++;
|
|
||||||
if(i >= mat.m) break;
|
|
||||||
}
|
}
|
||||||
|
rowMag[i] = mag;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rank;
|
return rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +375,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
||||||
WriteJacobian(0);
|
WriteJacobian(0);
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
|
|
||||||
int rank = GaussJordan();
|
int rank = CalculateRank();
|
||||||
if(rank == mat.m) {
|
if(rank == mat.m) {
|
||||||
// We fixed it by removing this constraint
|
// We fixed it by removing this constraint
|
||||||
(g->solved.remove).Add(&(c->h));
|
(g->solved.remove).Add(&(c->h));
|
||||||
|
@ -455,7 +436,7 @@ void System::Solve(Group *g) {
|
||||||
|
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
|
|
||||||
int rank = GaussJordan();
|
int rank = CalculateRank();
|
||||||
if(rank != mat.m) {
|
if(rank != mat.m) {
|
||||||
FindWhichToRemoveToFixJacobian(g);
|
FindWhichToRemoveToFixJacobian(g);
|
||||||
g->solved.how = Group::SINGULAR_JACOBIAN;
|
g->solved.how = Group::SINGULAR_JACOBIAN;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user