/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include #include "testing.h" #ifdef dDOUBLE static const dReal tol = 1.0e-9; #else static const dReal tol = 1.0e-5f; #endif // matrix header on the stack struct dMatrixComparison::dMatInfo { int n,m; // size of matrix char name[128]; // name of the matrix dReal *data; // matrix data int size; // size of `data' }; dMatrixComparison::dMatrixComparison() { afterfirst = 0; index = 0; } dMatrixComparison::~dMatrixComparison() { reset(); } dReal dMatrixComparison::nextMatrix (dReal *A, int n, int m, int lower_tri, char *name, ...) { if (A==0 || n < 1 || m < 1 || name==0) dDebug (0,"bad args to nextMatrix"); int num = n*dPAD(m); if (afterfirst==0) { dMatInfo *mi = (dMatInfo*) dAlloc (sizeof(dMatInfo)); mi->n = n; mi->m = m; mi->size = num * sizeof(dReal); mi->data = (dReal*) dAlloc (mi->size); memcpy (mi->data,A,mi->size); va_list ap; va_start (ap,name); vsprintf (mi->name,name,ap); if (strlen(mi->name) >= sizeof (mi->name)) dDebug (0,"name too long"); mat.push (mi); return 0; } else { if (lower_tri && n != m) dDebug (0,"dMatrixComparison, lower triangular matrix must be square"); if (index >= mat.size()) dDebug (0,"dMatrixComparison, too many matrices"); dMatInfo *mp = mat[index]; index++; dMatInfo mi; va_list ap; va_start (ap,name); vsprintf (mi.name,name,ap); if (strlen(mi.name) >= sizeof (mi.name)) dDebug (0,"name too long"); if (strcmp(mp->name,mi.name) != 0) dDebug (0,"dMatrixComparison, name mismatch (\"%s\" and \"%s\")", mp->name,mi.name); if (mp->n != n || mp->m != m) dDebug (0,"dMatrixComparison, size mismatch (%dx%d and %dx%d)", mp->n,mp->m,n,m); dReal maxdiff; if (lower_tri) { maxdiff = dMaxDifferenceLowerTriangle (A,mp->data,n); } else { maxdiff = dMaxDifference (A,mp->data,n,m); } if (maxdiff > tol) dDebug (0,"dMatrixComparison, matrix error (size=%dx%d, name=\"%s\", " "error=%.4e)",n,m,mi.name,maxdiff); return maxdiff; } } void dMatrixComparison::end() { if (mat.size() <= 0) dDebug (0,"no matrices in sequence"); afterfirst = 1; index = 0; } void dMatrixComparison::reset() { for (int i=0; idata,mat[i]->size); dFree (mat[i],sizeof(dMatInfo)); } mat.setSize (0); afterfirst = 0; index = 0; } void dMatrixComparison::dump() { for (int i=0; iname,mat[i]->n,mat[i]->m); } //**************************************************************************** // unit test #include static jmp_buf jump_buffer; static void myDebug (int num, const char *msg, va_list ap) { // printf ("(Error %d: ",num); // vprintf (msg,ap); // printf (")\n"); longjmp (jump_buffer,1); } extern "C" ODE_API void dTestMatrixComparison() { volatile int i; printf ("dTestMatrixComparison()\n"); dMessageFunction *orig_debug = dGetDebugHandler(); dMatrixComparison mc; dReal A[50*50]; // make first sequence unsigned long seed = dRandGetSeed(); for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); //mc.dump(); // test identical sequence dSetDebugHandler (&myDebug); dRandSetSeed (seed); if (setjmp (jump_buffer)) { printf ("\tFAILED (1)\n"); } else { for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); printf ("\tpassed (1)\n"); } dSetDebugHandler (orig_debug); // test broken sequences (with matrix error) dRandSetSeed (seed); volatile int passcount = 0; for (i=1; i<49; i++) { if (setjmp (jump_buffer)) { passcount++; } else { dSetDebugHandler (&myDebug); dMakeRandomMatrix (A,i,i+1,1.0); A[(i-1)*dPAD(i+1)+i] += REAL(0.01); mc.nextMatrix (A,i,i+1,0,"A%d",i); dSetDebugHandler (orig_debug); } } mc.end(); printf ("\t%s (2)\n",(passcount == 48) ? "passed" : "FAILED"); // test broken sequences (with name error) dRandSetSeed (seed); passcount = 0; for (i=1; i<49; i++) { if (setjmp (jump_buffer)) { passcount++; } else { dSetDebugHandler (&myDebug); dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"B%d",i); dSetDebugHandler (orig_debug); } } mc.end(); printf ("\t%s (3)\n",(passcount == 48) ? "passed" : "FAILED"); // test identical sequence again dSetDebugHandler (&myDebug); dRandSetSeed (seed); if (setjmp (jump_buffer)) { printf ("\tFAILED (4)\n"); } else { for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); printf ("\tpassed (4)\n"); } dSetDebugHandler (orig_debug); }