Files
opennurbs/tests/TestQuotientRule.cpp
Bozo the Builder 9988ac106a Sync changes from upstream repository
Co-authored-by: Bozo <bozo@mcneel.com>
Co-authored-by: croudyj <croudyj@gmail.com>
Co-authored-by: Dale Fugier <dale@mcneel.com>
Co-authored-by: Dale Lear <dalelear@mcneel.com>
Co-authored-by: Joshua Kennedy <joshuakennedy102@gmail.com>
Co-authored-by: Jussi Aaltonen <jussi@mcneel.com>
Co-authored-by: kike-garbo <kike@mcneel.com>
Co-authored-by: Luis Fraguada <luis@mcneel.com>
Co-authored-by: piac <giulio@mcneel.com>
Co-authored-by: Pierre Cuvilliers <pierre@mcneel.com>
2023-12-12 03:17:38 -08:00

452 lines
9.9 KiB
C++

#include "../opennurbs.h"
#include "Tests.h"
class CF
{
public:
CF() {r = ON_UNSET_VALUE; s = ON_UNSET_VALUE; t = ON_UNSET_VALUE;}
double r, s, t;
double f[6]; // = x/wr
double g[6]; // = y/ws
double h[6]; // = z/wt
double x[6];
double y[6];
double z[6];
double wr[6];
double ws[6];
double wt[6];
};
class CV
{
public:
double F, X, W;
};
static class CV func(double r, double s, double t,
ON_3dex ijk)
{
static CF ev;
if ( r != ev.r )
{
ev.x[0] = tan(r);
ev.x[1] = 1.0+ev.x[0]*ev.x[0];
ev.x[2] = 2.0*ev.x[0]*ev.x[1];
ev.x[3] = 2.0*(ev.x[1]*ev.x[1] + ev.x[0]*ev.x[2]);
ev.x[4] = 2.0*(3.0*ev.x[1]*ev.x[2] + ev.x[0]*ev.x[3]);
ev.x[5] = 2.0*(3.0*ev.x[2]*ev.x[2] + 4.0*ev.x[1]*ev.x[3] + ev.x[0]*ev.x[4]);
ev.r = r;
ev.wr[0] = 1.0/cos(r);
ev.wr[1] = ev.wr[0]*ev.x[0];
ev.wr[2] = ev.wr[1]*ev.x[0] + ev.wr[0]*ev.x[1];
ev.wr[3] = ev.wr[2]*ev.x[0] + 2.0*ev.wr[1]*ev.x[1] + ev.wr[0]*ev.x[2];
ev.wr[4] = ev.wr[3]*ev.x[0] + 3.0*ev.wr[2]*ev.x[1] + 3.0*ev.wr[1]*ev.x[2] + ev.wr[0]*ev.x[3];
ev.wr[5] = ev.wr[4]*ev.x[0] + 4.0*ev.wr[3]*ev.x[1] + 6.0*ev.wr[2]*ev.x[2] + 4.0*ev.wr[1]*ev.x[3] + ev.wr[0]*ev.x[4];
ev.f[0] = sin(r);
ev.f[1] = cos(r);
ev.f[2] = -ev.f[0];
ev.f[3] = -ev.f[1];
ev.f[4] = -ev.f[2];
ev.f[5] = -ev.f[3];
}
if ( s != ev.s )
{
ev.y[0] = exp(3.0*s);
ev.y[1] = 3.0*ev.y[0];
ev.y[2] = 9.0*ev.y[0];
ev.y[3] = 27.0*ev.y[0];
ev.y[4] = 81.0*ev.y[0];
ev.y[5] = 243.0*ev.y[0];
ev.ws[0] = exp(2.0*s);
ev.ws[1] = 2.0*ev.ws[0];
ev.ws[2] = 4.0*ev.ws[0];
ev.ws[3] = 8.0*ev.ws[0];
ev.ws[4] = 16.0*ev.ws[0];
ev.ws[5] = 32.0*ev.ws[0];
ev.g[0] = exp(s);
ev.g[1] = ev.g[0];
ev.g[2] = ev.g[0];
ev.g[3] = ev.g[0];
ev.g[4] = ev.g[0];
ev.g[5] = ev.g[0];
ev.s = s;
}
if ( t != ev.t )
{
double t2 = t*t;
double t3 = t*t2;
double t4 = t*t3;
double t5 = t*t4;
double t6 = t*t5;
double t7 = t*t6;
ev.z[0] = t7;
ev.z[1] = 7.0*t6;
ev.z[2] = 42.0*t5;
ev.z[3] = 210.0*t4;
ev.z[4] = 840.0*t3;
ev.z[5] = 2520.0*t2;
ev.wt[0] = t5;
ev.wt[1] = 5.0*t4;
ev.wt[2] = 20.0*t3;
ev.wt[3] = 60.0*t2;
ev.wt[4] = 120.0*t;
ev.wt[5] = 120.0;
ev.h[0] = t2;
ev.h[1] = 2.0*t;
ev.h[2] = 2.0;
ev.h[3] = 0.0;
ev.h[4] = 0.0;
ev.h[5] = 0.0;
ev.t = t;
}
CV V;
V.X = ev.x[ijk.i]*ev.y[ijk.j]*ev.z[ijk.k];
V.W = ev.wr[ijk.i]*ev.ws[ijk.j]*ev.wt[ijk.k];
V.F = ev.f[ijk.i]*ev.g[ijk.j]*ev.h[ijk.k];
return V;
}
struct TEST_INPUT
{
int err_count;
int pass_count;
double der_tol[6];
int der_count; // 0 <= der_count <= 5
int dim; // dim > 0
int n; // 0 <= n < dim
int v_stride; // dim < v_stride <= 7
double v[6*7*8*7]; // >= (dc+1)*(dc+2)*(dc+3)&v_stride dc = max der_count, vs = max v_stride
double a[6*7*8]; // >= (dc+1)*(dc+2)*(dc+3)
ON_3dex ijk[6*7*8]; // >= (dc+1)*(dc+2)*(dc+3)
double maxe1;
double maxe2;
double maxe3;
};
static void TestQR1(double r, double s, double t,
int coord,
TEST_INPUT& TI
)
{
CV V;
double e;
int err_count = 0;
int ii = (coord==0)?1:0;
int jj = (coord==1)?1:0;
int kk = (coord==2)?1:0;
int dc;
for (dc = 0; dc <= TI.der_count; dc++ )
{
TI.ijk[dc].i = ii*dc;
TI.ijk[dc].j = jj*dc;
TI.ijk[dc].k = kk*dc;
V = func(r,s,t, TI.ijk[dc]);
TI.v[dc*TI.v_stride+TI.n] = V.X;
TI.v[dc*TI.v_stride+TI.dim] = V.W;
TI.a[dc] = V.F;
}
if ( !ON_EvaluateQuotientRule(TI.dim,TI.der_count,TI.v_stride,TI.v) )
{
ON_ERROR("ON_EvaluateQuotientRule - error");
TI.err_count += (TI.der_count+1);
}
else
{
for ( dc = 0; dc <= TI.der_count; dc++ )
{
e = fabs(TI.a[dc] - TI.v[dc*TI.v_stride+TI.n]);
if ( e > TI.der_tol[dc] && e > ON_SQRT_EPSILON*fabs(TI.a[dc]) )
{
ON_ERROR("ON_EvaluateQuotientRule - error");
TI.err_count++;
}
else
{
if ( e > TI.maxe1 )
TI.maxe1 = e;
TI.pass_count++;
}
}
}
}
static void TestQR2(double r, double s, double t,
int coord,
TEST_INPUT& TI
)
{
CV V;
double e;
int imax = (coord==0)?0:1;
int jmax = (coord==1)?0:1;
int kmax = (coord==2)?0:1;
int i=0;
int j=0;
int k=0;
int mmax=0;
int m,der_count;
for ( der_count = 0; der_count <= TI.der_count; der_count++ )
{
for (m = 0; m <= der_count; m++ )
{
if ( 0 == coord )
{
TI.ijk[mmax].i = 0;
TI.ijk[mmax].j = der_count-m;
TI.ijk[mmax].k = m;
}
else if ( 1 == coord )
{
TI.ijk[mmax].i = der_count-m;
TI.ijk[mmax].j = 0;
TI.ijk[mmax].k = m;
}
else
{
TI.ijk[mmax].i = der_count-m;
TI.ijk[mmax].j = m;
TI.ijk[mmax].k = 0;
}
V = func(r,s,t, TI.ijk[mmax]);
TI.v[mmax*TI.v_stride+TI.n] = V.X;
TI.v[mmax*TI.v_stride+TI.dim] = V.W;
TI.a[mmax] = V.F;
mmax++;
}
}
if ( !ON_EvaluateQuotientRule2(TI.dim,TI.der_count,TI.v_stride,TI.v) )
{
ON_ERROR("ON_EvaluateQuotientRule2 - error");
TI.err_count += mmax;
}
else
{
for ( m = 0; m < mmax; m++ )
{
e = fabs(TI.a[m] - TI.v[m*TI.v_stride+TI.n]);
der_count = TI.ijk[m].i+TI.ijk[m].j+TI.ijk[m].k;
if ( e > TI.der_tol[der_count] && e > ON_SQRT_EPSILON*fabs(TI.a[m]) )
{
ON_ERROR("ON_EvaluateQuotientRule2 - error");
TI.err_count++;
}
else
{
if ( e > TI.maxe2 )
TI.maxe2 = e;
TI.pass_count++;
}
}
}
}
static void TestQR3(double r, double s, double t,
TEST_INPUT& TI
)
{
CV V;
double e;
int i=0;
int j=0;
int k=0;
int mmax=0;
int m,der_count;
for ( der_count = 0; der_count <= TI.der_count; der_count++ )
{
for ( i = der_count; i >= 0; i-- )
{
for ( j = der_count-i; j >= 0; j-- )
{
k = der_count-i-j;
TI.ijk[mmax].i = i;
TI.ijk[mmax].j = j;
TI.ijk[mmax].k = k;
V = func(r,s,t, TI.ijk[mmax]);
TI.v[mmax*TI.v_stride+TI.n] = V.X;
TI.v[mmax*TI.v_stride+TI.dim] = V.W;
TI.a[mmax] = V.F;
mmax++;
}
}
}
if ( !ON_EvaluateQuotientRule3(TI.dim,TI.der_count,TI.v_stride,TI.v) )
{
ON_ERROR("ON_EvaluateQuotientRule3 - error");
TI.err_count += mmax;
}
else
{
for ( m = 0; m < mmax; m++ )
{
e = fabs(TI.a[m] - TI.v[m*TI.v_stride+TI.n]);
der_count = TI.ijk[m].i+TI.ijk[m].j+TI.ijk[m].k;
if ( e > TI.der_tol[der_count] && e > ON_SQRT_EPSILON*fabs(TI.a[m]) )
{
ON_ERROR("ON_EvaluateQuotientRule3 - error");
TI.err_count++;
}
else
{
if ( e > TI.maxe3 )
TI.maxe3 = e;
TI.pass_count++;
}
}
}
}
bool TestQuotientRule( ON_TextLog& text_log )
{
double r,s,t;
struct TEST_INPUT TI;
memset(&TI,0,sizeof(TI));
TI.der_tol[0] = 1.0e-12;
TI.der_tol[1] = 1.0e-11;
TI.der_tol[2] = 1.0e-10;
TI.der_tol[3] = 1.0e-9;
TI.der_tol[4] = 1.0e-8;
TI.der_tol[5] = 5.0e-7;
TI.der_count = 0;
TI.dim = 1;
TI.n = 0;
TI.v_stride = TI.dim+1;
bool ok = true;
for (TI.der_count=0; TI.der_count<=5 && ok; TI.der_count++)
for (TI.dim = 1; TI.dim <= 4 && ok; TI.dim++ )
for (TI.n= 0; TI.n < TI.dim && ok; TI.n++)
for (TI.v_stride=TI.dim+1; TI.v_stride<=7 && ok; TI.v_stride++)
{
memset(TI.v,0,sizeof(TI.v));
// one paramter tests
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( r = -ON_PI/3.0; r <= ON_PI/3.0 && ok; r += ON_PI/120.0)
{
TestQR1(r,s,t,0,TI);
if (TI.err_count > 100 )
ok = false;
}
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( s = -2.0; s <= 2.0 && ok; s += 0.1 )
{
TestQR1(r,s,t,1,TI);
if (TI.err_count > 100 )
ok = false;
}
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( t = 0.1; t < 2.5 && ok; t += 0.1 )
{
TestQR1(r,s,t,2,TI);
if (TI.err_count > 100 )
ok = false;
}
// two paramter tests
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( r = -ON_PI/3.0; r <= ON_PI/3.0 && ok; r += ON_PI/120.0)
{
for ( s = -2.0; s <= 2.0 && ok; s += 0.1 )
{
TestQR2(r,s,t, 2, TI);
if (TI.err_count > 100 )
ok = false;
}
}
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( r = -ON_PI/3.0; r <= ON_PI/3.0 && ok; r += ON_PI/120.0)
{
for ( t = 0.1; t < 2.5 && ok; t += 0.1 )
{
TestQR2(r,s,t, 1, TI);
if (TI.err_count > 100 )
ok = false;
}
}
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( s = -2.0; s <= 2.0 && ok; s += 0.1 )
{
for ( t = 0.1; t < 2.5 && ok; t += 0.1 )
{
TestQR2(r,s,t, 1, TI);
if (TI.err_count > 100 )
ok = false;
}
}
// three paramter tests
r = 0.25*ON_PI;
s = 0.0;
t = 1.0;
for ( r = -ON_PI/3.0; r <= ON_PI/3.0 && ok; r += ON_PI/120.0)
{
for ( s = -2.0; s <= 2.0 && ok; s += 0.1 )
{
for ( t = 0.1; t < 2.5 && ok; t += 0.1 )
{
TestQR3(r,s,t, TI);
if (TI.err_count > 100 )
ok = false;
}
}
}
}
text_log.Print("pass_count = %d err_count = %d maxe1 = %g maxe2 = %g maxe3 = %g\n",
TI.pass_count,TI.err_count,TI.maxe1,TI.maxe2,TI.maxe3);
return (TI.err_count == 0);
}