| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163 |
- /*************************************************************************
- * *
- * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
- * All rights reserved. Email: [email protected] 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 <setjmp.h>
- #include <ode/ode.h>
- #ifdef _MSC_VER
- #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
- #endif
- //****************************************************************************
- // matrix accessors
- #define _A(i,j) A[(i)*4+(j)]
- #define _I(i,j) I[(i)*4+(j)]
- #define _R(i,j) R[(i)*4+(j)]
- //****************************************************************************
- // tolerances
- #ifdef dDOUBLE
- const double tol = 1e-10;
- #endif
- #ifdef dSINGLE
- const double tol = 1e-5;
- #endif
- //****************************************************************************
- // misc messages and error handling
- #ifdef __GNUC__
- #define HEADER printf ("%s()\n", __FUNCTION__);
- #else
- #define HEADER printf ("%s:%d\n",__FILE__,__LINE__);
- #endif
- static jmp_buf jump_buffer;
- void myMessageFunction (int num, const char *msg, va_list ap)
- {
- printf ("(Message %d: ",num);
- vprintf (msg,ap);
- printf (")");
- dSetMessageHandler (0);
- longjmp (jump_buffer,1);
- }
- #define TRAP_MESSAGE(do,ifnomsg,ifmsg) \
- dSetMessageHandler (&myMessageFunction); \
- if (setjmp (jump_buffer)) { \
- dSetMessageHandler (0); \
- ifmsg ; \
- } \
- else { \
- dSetMessageHandler (&myMessageFunction); \
- do ; \
- ifnomsg ; \
- } \
- dSetMessageHandler (0);
- //****************************************************************************
- // utility stuff
- // compare two numbers, within a threshhold, return 1 if approx equal
- int cmp (dReal a, dReal b)
- {
- return (fabs(a-b) < tol);
- }
- //****************************************************************************
- // matrix utility stuff
- // compare a 3x3 matrix with the identity
- int cmpIdentityMat3 (dMatrix3 A)
- {
- return
- (cmp(_A(0,0),1.0) && cmp(_A(0,1),0.0) && cmp(_A(0,2),0.0) &&
- cmp(_A(1,0),0.0) && cmp(_A(1,1),1.0) && cmp(_A(1,2),0.0) &&
- cmp(_A(2,0),0.0) && cmp(_A(2,1),0.0) && cmp(_A(2,2),1.0));
- }
- // transpose a 3x3 matrix in-line
- void transpose3x3 (dMatrix3 A)
- {
- dReal tmp;
- tmp=A[4]; A[4]=A[1]; A[1]=tmp;
- tmp=A[8]; A[8]=A[2]; A[2]=tmp;
- tmp=A[9]; A[9]=A[6]; A[6]=tmp;
- }
- //****************************************************************************
- // test miscellaneous math functions
- void testRandomNumberGenerator()
- {
- HEADER;
- if (dTestRand()) printf ("\tpassed\n");
- else printf ("\tFAILED\n");
- }
- void testInfinity()
- {
- HEADER;
- if (1e10 < dInfinity && -1e10 > -dInfinity && -dInfinity < dInfinity)
- printf ("\tpassed\n");
- else printf ("\tFAILED\n");
- }
- void testPad()
- {
- HEADER;
- char s[100];
- s[0]=0;
- for (int i=0; i<=16; i++) sprintf (s+strlen(s),"%d ",dPAD(i));
- printf ("\t%s\n", strcmp(s,"0 1 4 4 4 8 8 8 8 12 12 12 12 16 16 16 16 ") ?
- "FAILED" : "passed");
- }
- void testCrossProduct()
- {
- HEADER;
- dVector3 a1,a2,b,c;
- dMatrix3 B;
- dMakeRandomVector (b,3,1.0);
- dMakeRandomVector (c,3,1.0);
- dCalcVectorCross3(a1,b,c);
- dSetZero (B,12);
- dSetCrossMatrixPlus(B,b,4);
- dMultiply0 (a2,B,c,3,3,1);
- dReal diff = dMaxDifference(a1,a2,3,1);
- printf ("\t%s\n", diff > tol ? "FAILED" : "passed");
- }
- void testSetZero()
- {
- HEADER;
- dReal a[100];
- dMakeRandomVector (a,100,1.0);
- dSetZero (a,100);
- for (int i=0; i<100; i++) if (a[i] != 0.0) {
- printf ("\tFAILED\n");
- return;
- }
- printf ("\tpassed\n");
- }
- void testNormalize3()
- {
- HEADER;
- int i,j,bad=0;
- dVector3 n1,n2;
- for (i=0; i<1000; i++) {
- dMakeRandomVector (n1,3,1.0);
- for (j=0; j<3; j++) n2[j]=n1[j];
- dNormalize3 (n2);
- if (dFabs(dCalcVectorDot3(n2,n2) - 1.0) > tol) bad |= 1;
- if (dFabs(n2[0]/n1[0] - n2[1]/n1[1]) > tol) bad |= 2;
- if (dFabs(n2[0]/n1[0] - n2[2]/n1[2]) > tol) bad |= 4;
- if (dFabs(n2[1]/n1[1] - n2[2]/n1[2]) > tol) bad |= 8;
- if (dFabs(dCalcVectorDot3(n2,n1) - dSqrt(dCalcVectorDot3(n1,n1))) > tol) bad |= 16;
- if (bad) {
- printf ("\tFAILED (code=%x)\n",bad);
- return;
- }
- }
- printf ("\tpassed\n");
- }
- /*
- void testReorthonormalize()
- {
- HEADER;
- dMatrix3 R,I;
- dMakeRandomMatrix (R,3,3,1.0);
- for (int i=0; i<30; i++) dReorthonormalize (R);
- dMultiply2 (I,R,R,3,3,3);
- printf ("\t%s\n",cmpIdentityMat3 (I) ? "passed" : "FAILED");
- }
- */
- void testPlaneSpace()
- {
- HEADER;
- dVector3 n,p,q;
- int bad = 0;
- for (int i=0; i<1000; i++) {
- dMakeRandomVector (n,3,1.0);
- dNormalize3 (n);
- dPlaneSpace (n,p,q);
- if (fabs(dCalcVectorDot3(n,p)) > tol) bad = 1;
- if (fabs(dCalcVectorDot3(n,q)) > tol) bad = 1;
- if (fabs(dCalcVectorDot3(p,q)) > tol) bad = 1;
- if (fabs(dCalcVectorDot3(p,p)-1) > tol) bad = 1;
- if (fabs(dCalcVectorDot3(q,q)-1) > tol) bad = 1;
- }
- printf ("\t%s\n", bad ? "FAILED" : "passed");
- }
- //****************************************************************************
- // test matrix functions
- #define MSIZE 21
- #define MSIZE4 24 // MSIZE rounded up to 4
- void testMatrixMultiply()
- {
- // A is 2x3, B is 3x4, B2 is B except stored columnwise, C is 2x4
- dReal A[8],B[12],A2[12],B2[16],C[8];
- int i;
- HEADER;
- dSetZero (A,8);
- for (i=0; i<3; i++) A[i] = i+2;
- for (i=0; i<3; i++) A[i+4] = i+3+2;
- for (i=0; i<12; i++) B[i] = i+8;
- dSetZero (A2,12);
- for (i=0; i<6; i++) A2[i+2*(i/2)] = A[i+i/3];
- dSetZero (B2,16);
- for (i=0; i<12; i++) B2[i+i/3] = B[i];
- dMultiply0 (C,A,B,2,3,4);
- if (C[0] != 116 || C[1] != 125 || C[2] != 134 || C[3] != 143 ||
- C[4] != 224 || C[5] != 242 || C[6] != 260 || C[7] != 278)
- printf ("\tFAILED (1)\n"); else printf ("\tpassed (1)\n");
- dMultiply1 (C,A2,B,2,3,4);
- if (C[0] != 160 || C[1] != 172 || C[2] != 184 || C[3] != 196 ||
- C[4] != 196 || C[5] != 211 || C[6] != 226 || C[7] != 241)
- printf ("\tFAILED (2)\n"); else printf ("\tpassed (2)\n");
- dMultiply2 (C,A,B2,2,3,4);
- if (C[0] != 83 || C[1] != 110 || C[2] != 137 || C[3] != 164 ||
- C[4] != 164 || C[5] != 218 || C[6] != 272 || C[7] != 326)
- printf ("\tFAILED (3)\n"); else printf ("\tpassed (3)\n");
- }
- void testSmallMatrixMultiply()
- {
- dMatrix3 A,B,C,A2;
- dVector3 a,a2,x;
- HEADER;
- dMakeRandomMatrix (A,3,3,1.0);
- dMakeRandomMatrix (B,3,3,1.0);
- dMakeRandomMatrix (C,3,3,1.0);
- dMakeRandomMatrix (x,3,1,1.0);
- // dMultiply0_331()
- dMultiply0_331 (a,B,x);
- dMultiply0 (a2,B,x,3,3,1);
- printf ("\t%s (1)\n",(dMaxDifference (a,a2,3,1) > tol) ? "FAILED" :
- "passed");
- // dMultiply1_331()
- dMultiply1_331 (a,B,x);
- dMultiply1 (a2,B,x,3,3,1);
- printf ("\t%s (2)\n",(dMaxDifference (a,a2,3,1) > tol) ? "FAILED" :
- "passed");
- // dMultiply0_133
- dMultiply0_133 (a,x,B);
- dMultiply0 (a2,x,B,1,3,3);
- printf ("\t%s (3)\n",(dMaxDifference (a,a2,1,3) > tol) ? "FAILED" :
- "passed");
- // dMultiply0_333()
- dMultiply0_333 (A,B,C);
- dMultiply0 (A2,B,C,3,3,3);
- printf ("\t%s (4)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" :
- "passed");
- // dMultiply1_333()
- dMultiply1_333 (A,B,C);
- dMultiply1 (A2,B,C,3,3,3);
- printf ("\t%s (5)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" :
- "passed");
- // dMultiply2_333()
- dMultiply2_333 (A,B,C);
- dMultiply2 (A2,B,C,3,3,3);
- printf ("\t%s (6)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" :
- "passed");
- }
- void testCholeskyFactorization()
- {
- dReal A[MSIZE4*MSIZE], B[MSIZE4*MSIZE], C[MSIZE4*MSIZE], diff;
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (B,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,B,MSIZE4*MSIZE*sizeof(dReal));
- if (dFactorCholesky (B,MSIZE)) printf ("\tpassed (1)\n");
- else printf ("\tFAILED (1)\n");
- dClearUpperTriangle (B,MSIZE);
- dMultiply2 (C,B,B,MSIZE,MSIZE,MSIZE);
- diff = dMaxDifference(A,C,MSIZE,MSIZE);
- printf ("\tmaximum difference = %.6e - %s (2)\n",diff,
- diff > tol ? "FAILED" : "passed");
- }
- void testCholeskySolve()
- {
- dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], b[MSIZE],x[MSIZE],btest[MSIZE],diff;
- HEADER;
- // get A,L = PD matrix
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal));
- // get b,x = right hand side
- dMakeRandomMatrix (b,MSIZE,1,1.0);
- memcpy (x,b,MSIZE*sizeof(dReal));
- // factor L
- if (dFactorCholesky (L,MSIZE)) printf ("\tpassed (1)\n");
- else printf ("\tFAILED (1)\n");
- dClearUpperTriangle (L,MSIZE);
- // solve A*x = b
- dSolveCholesky (L,x,MSIZE);
- // compute A*x and compare it with b
- dMultiply2 (btest,A,x,MSIZE,MSIZE,1);
- diff = dMaxDifference(b,btest,MSIZE,1);
- printf ("\tmaximum difference = %.6e - %s (2)\n",diff,
- diff > tol ? "FAILED" : "passed");
- }
- void testInvertPDMatrix()
- {
- int i,j,ok;
- dReal A[MSIZE4*MSIZE], Ainv[MSIZE4*MSIZE], I[MSIZE4*MSIZE];
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (Ainv,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,Ainv,MSIZE4*MSIZE*sizeof(dReal));
- dSetZero (Ainv,MSIZE4*MSIZE);
- if (dInvertPDMatrix (A,Ainv,MSIZE))
- printf ("\tpassed (1)\n"); else printf ("\tFAILED (1)\n");
- dMultiply0 (I,A,Ainv,MSIZE,MSIZE,MSIZE);
- // compare with identity
- ok = 1;
- for (i=0; i<MSIZE; i++) {
- for (j=0; j<MSIZE; j++) {
- if (i != j) if (cmp (I[i*MSIZE4+j],0.0)==0) ok = 0;
- }
- }
- for (i=0; i<MSIZE; i++) {
- if (cmp (I[i*MSIZE4+i],1.0)==0) ok = 0;
- }
- if (ok) printf ("\tpassed (2)\n"); else printf ("\tFAILED (2)\n");
- }
- void testIsPositiveDefinite()
- {
- dReal A[MSIZE4*MSIZE], B[MSIZE4*MSIZE];
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (B,A,A,MSIZE,MSIZE,MSIZE);
- printf ("\t%s\n",dIsPositiveDefinite(A,MSIZE) ? "FAILED (1)":"passed (1)");
- printf ("\t%s\n",dIsPositiveDefinite(B,MSIZE) ? "passed (2)":"FAILED (2)");
- }
- void testFastLDLTFactorization()
- {
- int i,j;
- dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], DL[MSIZE4*MSIZE],
- ATEST[MSIZE4*MSIZE], d[MSIZE], diff;
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal));
- dFactorLDLT (L,d,MSIZE,MSIZE4);
- dClearUpperTriangle (L,MSIZE);
- for (i=0; i<MSIZE; i++) L[i*MSIZE4+i] = 1.0;
- dSetZero (DL,MSIZE4*MSIZE);
- for (i=0; i<MSIZE; i++) {
- for (j=0; j<MSIZE; j++) DL[i*MSIZE4+j] = L[i*MSIZE4+j] / d[j];
- }
- dMultiply2 (ATEST,L,DL,MSIZE,MSIZE,MSIZE);
- diff = dMaxDifference(A,ATEST,MSIZE,MSIZE);
- printf ("\tmaximum difference = %.6e - %s\n",diff,
- diff > tol ? "FAILED" : "passed");
- }
- void testSolveLDLT()
- {
- dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE], x[MSIZE],
- b[MSIZE], btest[MSIZE], diff;
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal));
- dMakeRandomMatrix (b,MSIZE,1,1.0);
- memcpy (x,b,MSIZE*sizeof(dReal));
- dFactorLDLT (L,d,MSIZE,MSIZE4);
- dSolveLDLT (L,d,x,MSIZE,MSIZE4);
- dMultiply2 (btest,A,x,MSIZE,MSIZE,1);
- diff = dMaxDifference(b,btest,MSIZE,1);
- printf ("\tmaximum difference = %.6e - %s\n",diff,
- diff > tol ? "FAILED" : "passed");
- }
- void testLDLTAddTL()
- {
- int i,j;
- dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE], a[MSIZE],
- DL[MSIZE4*MSIZE], ATEST[MSIZE4*MSIZE], diff;
- HEADER;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal));
- dFactorLDLT (L,d,MSIZE,MSIZE4);
- // delete first row and column of factorization
- for (i=0; i<MSIZE; i++) a[i] = -A[i*MSIZE4];
- a[0] += 1;
- dLDLTAddTL (L,d,a,MSIZE,MSIZE4);
- for (i=1; i<MSIZE; i++) L[i*MSIZE4] = 0;
- d[0] = 1;
- // get modified L*D*L'
- dClearUpperTriangle (L,MSIZE);
- for (i=0; i<MSIZE; i++) L[i*MSIZE4+i] = 1.0;
- dSetZero (DL,MSIZE4*MSIZE);
- for (i=0; i<MSIZE; i++) {
- for (j=0; j<MSIZE; j++) DL[i*MSIZE4+j] = L[i*MSIZE4+j] / d[j];
- }
- dMultiply2 (ATEST,L,DL,MSIZE,MSIZE,MSIZE);
- // compare it to A with its first row/column removed
- for (i=1; i<MSIZE; i++) A[i*MSIZE4] = A[i] = 0;
- A[0] = 1;
- diff = dMaxDifference(A,ATEST,MSIZE,MSIZE);
- printf ("\tmaximum difference = %.6e - %s\n",diff,
- diff > tol ? "FAILED" : "passed");
- }
- void testLDLTRemove()
- {
- int i,j,r,p[MSIZE];
- dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE],
- L2[MSIZE4*MSIZE], d2[MSIZE], DL2[MSIZE4*MSIZE],
- Atest1[MSIZE4*MSIZE], Atest2[MSIZE4*MSIZE], diff, maxdiff;
- HEADER;
- // make array of A row pointers
- dReal *Arows[MSIZE];
- for (i=0; i<MSIZE; i++) Arows[i] = A+i*MSIZE4;
- // fill permutation vector
- for (i=0; i<MSIZE; i++) p[i]=i;
- dMakeRandomMatrix (A,MSIZE,MSIZE,1.0);
- dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE);
- memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal));
- dFactorLDLT (L,d,MSIZE,MSIZE4);
- maxdiff = 1e10;
- for (r=0; r<MSIZE; r++) {
- // get Atest1 = A with row/column r removed
- memcpy (Atest1,A,MSIZE4*MSIZE*sizeof(dReal));
- dRemoveRowCol (Atest1,MSIZE,MSIZE4,r);
- // test that the row/column removal worked
- int bad = 0;
- for (i=0; i<MSIZE; i++) {
- for (j=0; j<MSIZE; j++) {
- if (i != r && j != r) {
- int ii = i;
- int jj = j;
- if (ii >= r) ii--;
- if (jj >= r) jj--;
- if (A[i*MSIZE4+j] != Atest1[ii*MSIZE4+jj]) bad = 1;
- }
- }
- }
- if (bad) printf ("\trow/col removal FAILED for row %d\n",r);
- // zero out last row/column of Atest1
- for (i=0; i<MSIZE; i++) {
- Atest1[(MSIZE-1)*MSIZE4+i] = 0;
- Atest1[i*MSIZE4+MSIZE-1] = 0;
- }
- // get L2*D2*L2' = adjusted factorization to remove that row
- memcpy (L2,L,MSIZE4*MSIZE*sizeof(dReal));
- memcpy (d2,d,MSIZE*sizeof(dReal));
- dLDLTRemove (/*A*/ Arows,p,L2,d2,MSIZE,MSIZE,r,MSIZE4);
- // get Atest2 = L2*D2*L2'
- dClearUpperTriangle (L2,MSIZE);
- for (i=0; i<(MSIZE-1); i++) L2[i*MSIZE4+i] = 1.0;
- for (i=0; i<MSIZE; i++) L2[(MSIZE-1)*MSIZE4+i] = 0;
- d2[MSIZE-1] = 1;
- dSetZero (DL2,MSIZE4*MSIZE);
- for (i=0; i<(MSIZE-1); i++) {
- for (j=0; j<MSIZE-1; j++) DL2[i*MSIZE4+j] = L2[i*MSIZE4+j] / d2[j];
- }
- dMultiply2 (Atest2,L2,DL2,MSIZE,MSIZE,MSIZE);
- diff = dMaxDifference(Atest1,Atest2,MSIZE,MSIZE);
- if (diff < maxdiff) maxdiff = diff;
- /*
- dPrintMatrix (Atest1,MSIZE,MSIZE);
- printf ("\n");
- dPrintMatrix (Atest2,MSIZE,MSIZE);
- printf ("\n");
- */
- }
- printf ("\tmaximum difference = %.6e - %s\n",maxdiff,
- maxdiff > tol ? "FAILED" : "passed");
- }
- //****************************************************************************
- // test mass stuff
- #define NUMP 10 // number of particles
- void printMassParams (dMass *m)
- {
- printf ("mass = %.4f\n",m->mass);
- printf ("com = (%.4f,%.4f,%.4f)\n",m->c[0],m->c[1],m->c[2]);
- printf ("I = [ %10.4f %10.4f %10.4f ]\n"
- " [ %10.4f %10.4f %10.4f ]\n"
- " [ %10.4f %10.4f %10.4f ]\n",
- m->_I(0,0),m->_I(0,1),m->_I(0,2),
- m->_I(1,0),m->_I(1,1),m->_I(1,2),
- m->_I(2,0),m->_I(2,1),m->_I(2,2));
- }
- void compareMassParams (dMass *m1, dMass *m2, const char *msg)
- {
- int i,j,ok = 1;
- if (!(cmp(m1->mass,m2->mass) && cmp(m1->c[0],m2->c[0]) &&
- cmp(m1->c[1],m2->c[1]) && cmp(m1->c[2],m2->c[2])))
- ok = 0;
- for (i=0; i<3; i++) for (j=0; j<3; j++)
- if (cmp (m1->_I(i,j),m2->_I(i,j))==0) ok = 0;
- if (ok) printf ("\tpassed (%s)\n",msg); else printf ("\tFAILED (%s)\n",msg);
- }
- // compute the mass parameters of a particle set
- void computeMassParams (dMass *m, dReal q[NUMP][3], dReal pm[NUMP])
- {
- int i,j;
- dMassSetZero (m);
- for (i=0; i<NUMP; i++) {
- m->mass += pm[i];
- for (j=0; j<3; j++) m->c[j] += pm[i]*q[i][j];
- m->_I(0,0) += pm[i]*(q[i][1]*q[i][1] + q[i][2]*q[i][2]);
- m->_I(1,1) += pm[i]*(q[i][0]*q[i][0] + q[i][2]*q[i][2]);
- m->_I(2,2) += pm[i]*(q[i][0]*q[i][0] + q[i][1]*q[i][1]);
- m->_I(0,1) -= pm[i]*(q[i][0]*q[i][1]);
- m->_I(0,2) -= pm[i]*(q[i][0]*q[i][2]);
- m->_I(1,2) -= pm[i]*(q[i][1]*q[i][2]);
- }
- for (j=0; j<3; j++) m->c[j] /= m->mass;
- m->_I(1,0) = m->_I(0,1);
- m->_I(2,0) = m->_I(0,2);
- m->_I(2,1) = m->_I(1,2);
- }
- void testMassFunctions()
- {
- dMass m;
- int i,j;
- dReal q[NUMP][3]; // particle positions
- dReal pm[NUMP]; // particle masses
- dMass m1,m2;
- dMatrix3 R;
- HEADER;
- printf ("\t");
- dMassSetZero (&m);
- TRAP_MESSAGE (dMassSetParameters (&m,10, 0,0,0, 1,2,3, 4,5,6),
- printf (" FAILED (1)\n"), printf (" passed (1)\n"));
- printf ("\t");
- dMassSetZero (&m);
- TRAP_MESSAGE (dMassSetParameters (&m,10, 0.1,0.2,0.15, 3,5,14, 3.1,3.2,4),
- printf ("passed (2)\n") , printf (" FAILED (2)\n"));
- if (m.mass==10 && m.c[0]==REAL(0.1) && m.c[1]==REAL(0.2) &&
- m.c[2]==REAL(0.15) && m._I(0,0)==3 && m._I(1,1)==5 && m._I(2,2)==14 &&
- m._I(0,1)==REAL(3.1) && m._I(0,2)==REAL(3.2) && m._I(1,2)==4 &&
- m._I(1,0)==REAL(3.1) && m._I(2,0)==REAL(3.2) && m._I(2,1)==4)
- printf ("\tpassed (3)\n"); else printf ("\tFAILED (3)\n");
- dMassSetZero (&m);
- dMassSetSphere (&m,1.4, 0.86);
- if (cmp(m.mass,3.73002719949386) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 &&
- cmp(m._I(0,0),1.10349124669826) &&
- cmp(m._I(1,1),1.10349124669826) &&
- cmp(m._I(2,2),1.10349124669826) &&
- m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 &&
- m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0)
- printf ("\tpassed (4)\n"); else printf ("\tFAILED (4)\n");
- dMassSetZero (&m);
- dMassSetCapsule (&m,1.3,1,0.76,1.53);
- if (cmp(m.mass,5.99961928996029) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 &&
- cmp(m._I(0,0),1.59461986077384) &&
- cmp(m._I(1,1),4.21878433864904) &&
- cmp(m._I(2,2),4.21878433864904) &&
- m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 &&
- m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0)
- printf ("\tpassed (5)\n"); else printf ("\tFAILED (5)\n");
- dMassSetZero (&m);
- dMassSetBox (&m,0.27,3,4,5);
- if (cmp(m.mass,16.2) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 &&
- cmp(m._I(0,0),55.35) && cmp(m._I(1,1),45.9) && cmp(m._I(2,2),33.75) &&
- m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 &&
- m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0)
- printf ("\tpassed (6)\n"); else printf ("\tFAILED (6)\n");
- // test dMassAdjust?
- // make random particles and compute the mass, COM and inertia, then
- // translate and repeat.
- for (i=0; i<NUMP; i++) {
- pm[i] = dRandReal()+0.5;
- for (j=0; j<3; j++) {
- q[i][j] = 2.0*(dRandReal()-0.5);
- }
- }
- computeMassParams (&m1,q,pm);
- memcpy (&m2,&m1,sizeof(dMass));
- dMassTranslate (&m2,1,2,-3);
- for (i=0; i<NUMP; i++) {
- q[i][0] += 1;
- q[i][1] += 2;
- q[i][2] -= 3;
- }
- computeMassParams (&m1,q,pm);
- compareMassParams (&m1,&m2,"7");
- // rotate the masses
- _R(0,0) = -0.87919618797635;
- _R(0,1) = 0.15278881840384;
- _R(0,2) = -0.45129772879842;
- _R(1,0) = -0.47307856232664;
- _R(1,1) = -0.39258064912909;
- _R(1,2) = 0.78871864932708;
- _R(2,0) = -0.05666336483842;
- _R(2,1) = 0.90693771059546;
- _R(2,2) = 0.41743652473765;
- dMassRotate (&m2,R);
- for (i=0; i<NUMP; i++) {
- dReal a[3];
- dMultiply0 (a,&_R(0,0),&q[i][0],3,3,1);
- q[i][0] = a[0];
- q[i][1] = a[1];
- q[i][2] = a[2];
- }
- computeMassParams (&m1,q,pm);
- compareMassParams (&m1,&m2,"8");
- }
- //****************************************************************************
- // test rotation stuff
- void makeRandomRotation (dMatrix3 R)
- {
- dReal *u1 = R, *u2=R+4, *u3=R+8;
- dMakeRandomVector (u1,3,1.0);
- dNormalize3 (u1);
- dMakeRandomVector (u2,3,1.0);
- dReal d = dCalcVectorDot3(u1,u2);
- u2[0] -= d*u1[0];
- u2[1] -= d*u1[1];
- u2[2] -= d*u1[2];
- dNormalize3(u2);
- dCalcVectorCross3(u3,u1,u2);
- }
- void testRtoQandQtoR()
- {
- HEADER;
- dMatrix3 R,I,R2;
- dQuaternion q;
- int i;
- // test makeRandomRotation()
- makeRandomRotation (R);
- dMultiply2 (I,R,R,3,3,3);
- printf ("\tmakeRandomRotation() - %s (1)\n",
- cmpIdentityMat3(I) ? "passed" : "FAILED");
- // test QtoR() on random normalized quaternions
- int ok = 1;
- for (i=0; i<100; i++) {
- dMakeRandomVector (q,4,1.0);
- dNormalize4 (q);
- dQtoR (q,R);
- dMultiply2 (I,R,R,3,3,3);
- if (cmpIdentityMat3(I)==0) ok = 0;
- }
- printf ("\tQtoR() orthonormality %s (2)\n", ok ? "passed" : "FAILED");
- // test R -> Q -> R works
- dReal maxdiff=0;
- for (i=0; i<100; i++) {
- makeRandomRotation (R);
- dRtoQ (R,q);
- dQtoR (q,R2);
- dReal diff = dMaxDifference (R,R2,3,3);
- if (diff > maxdiff) maxdiff = diff;
- }
- printf ("\tmaximum difference = %e - %s (3)\n",maxdiff,
- (maxdiff > tol) ? "FAILED" : "passed");
- }
- void testQuaternionMultiply()
- {
- HEADER;
- dMatrix3 RA,RB,RC,Rtest;
- dQuaternion qa,qb,qc;
- dReal diff,maxdiff=0;
- for (int i=0; i<100; i++) {
- makeRandomRotation (RB);
- makeRandomRotation (RC);
- dRtoQ (RB,qb);
- dRtoQ (RC,qc);
- dMultiply0 (RA,RB,RC,3,3,3);
- dQMultiply0 (qa,qb,qc);
- dQtoR (qa,Rtest);
- diff = dMaxDifference (Rtest,RA,3,3);
- if (diff > maxdiff) maxdiff = diff;
- dMultiply1 (RA,RB,RC,3,3,3);
- dQMultiply1 (qa,qb,qc);
- dQtoR (qa,Rtest);
- diff = dMaxDifference (Rtest,RA,3,3);
- if (diff > maxdiff) maxdiff = diff;
- dMultiply2 (RA,RB,RC,3,3,3);
- dQMultiply2 (qa,qb,qc);
- dQtoR (qa,Rtest);
- diff = dMaxDifference (Rtest,RA,3,3);
- if (diff > maxdiff) maxdiff = diff;
- dMultiply0 (RA,RC,RB,3,3,3);
- transpose3x3 (RA);
- dQMultiply3 (qa,qb,qc);
- dQtoR (qa,Rtest);
- diff = dMaxDifference (Rtest,RA,3,3);
- if (diff > maxdiff) maxdiff = diff;
- }
- printf ("\tmaximum difference = %e - %s\n",maxdiff,
- (maxdiff > tol) ? "FAILED" : "passed");
- }
- void testRotationFunctions()
- {
- dMatrix3 R1;
- HEADER;
- printf ("\tdRSetIdentity - ");
- dMakeRandomMatrix (R1,3,3,1.0);
- dRSetIdentity (R1);
- if (cmpIdentityMat3(R1)) printf ("passed\n"); else printf ("FAILED\n");
- printf ("\tdRFromAxisAndAngle - ");
- printf ("\n");
- printf ("\tdRFromEulerAngles - ");
- printf ("\n");
- printf ("\tdRFrom2Axes - ");
- printf ("\n");
- }
- //****************************************************************************
- #include <assert.h>
- template<class T>
- class simplevector
- {
- private:
- int n;
- int max;
- T* data;
- public:
- simplevector() { initialize(); }
- ~simplevector() { finalize(); }
- T& operator[](int i) { assert(i>=0 && i<n); return data[i]; }
- const T& operator[](int i) const { assert(i>=0 && i<n); return data[i]; }
- void push_back(const T& elem)
- {
- if (n == max)
- {
- max *= 2;
- T* newdata = new T[max];
- memcpy(newdata, data, sizeof(T)*n);
- delete[] data;
- data = newdata;
- }
- data[n++] = elem;
- }
- int size() const { return n; }
- void clear() { finalize(); initialize(); }
- private:
- void finalize() { delete[] data; }
- void initialize() { data = new T[32]; max = 32; n = 0; }
- };
- // matrix header on the stack
- class dMatrixComparison {
- struct dMatInfo;
- simplevector<dMatInfo*> mat;
- int afterfirst,index;
- public:
- dMatrixComparison();
- ~dMatrixComparison();
- dReal nextMatrix (dReal *A, int n, int m, int lower_tri, const char *name, ...);
- // add a new n*m matrix A to the sequence. the name of the matrix is given
- // by the printf-style arguments (name,...). if this is the first sequence
- // then this object will simply record the matrices and return 0.
- // if this the second or subsequent sequence then this object will compare
- // the matrices with the first sequence, and report any differences.
- // the matrix error will be returned. if `lower_tri' is 1 then only the
- // lower triangle of the matrix (including the diagonal) will be compared
- // (the matrix must be square).
- void end();
- // end a sequence.
- void reset();
- // restarts the object, so the next sequence will be the first sequence.
- void dump();
- // print out info about all the matrices in the sequence
- };
- 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,
- const 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);
- va_end (ap);
- if (strlen(mi->name) >= sizeof (mi->name)) dDebug (0,"name too long");
- mat.push_back(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);
- va_end (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; i<mat.size(); i++) {
- dFree (mat[i]->data,mat[i]->size);
- dFree (mat[i],sizeof(dMatInfo));
- }
- mat.clear();
- afterfirst = 0;
- index = 0;
- }
- void dMatrixComparison::dump()
- {
- for (int i=0; i<mat.size(); i++)
- printf ("%d: %s (%dx%d)\n",i,mat[i]->name,mat[i]->n,mat[i]->m);
- }
- //****************************************************************************
- // unit test
- #include <setjmp.h>
- // 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" 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);
- }
- //****************************************************************************
- // internal unit tests
- extern "C" void dTestDataStructures();
- extern "C" void dTestMatrixComparison();
- extern "C" int dTestSolveLCP();
- int main()
- {
- dInitODE();
- testRandomNumberGenerator();
- testInfinity();
- testPad();
- testCrossProduct();
- testSetZero();
- testNormalize3();
- //testReorthonormalize(); ... not any more
- testPlaneSpace();
- testMatrixMultiply();
- testSmallMatrixMultiply();
- testCholeskyFactorization();
- testCholeskySolve();
- testInvertPDMatrix();
- testIsPositiveDefinite();
- testFastLDLTFactorization();
- testSolveLDLT();
- testLDLTAddTL();
- testLDLTRemove();
- testMassFunctions();
- testRtoQandQtoR();
- testQuaternionMultiply();
- testRotationFunctions();
- dTestMatrixComparison();
- dTestSolveLCP();
- // dTestDataStructures();
- dCloseODE();
- return 0;
- }
|