MOAB: Mesh Oriented datABase  (version 5.2.1)
TargetMetricTest.hpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2006 Sandia National Laboratories.  Developed at the
00005     University of Wisconsin--Madison under SNL contract number
00006     624796.  The U.S. Government and the University of Wisconsin
00007     retain certain rights to this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2010) kraftche@cae.wisc.edu
00024 
00025   ***************************************************************** */
00026 
00027 /** \file TargetMetricTest.hpp
00028  *  \brief Templatized common code for testing various target metric
00029  *         implementation types.
00030  *  \author Jason Kraftcheck
00031  */
00032 
00033 #include "UnitUtil.hpp"
00034 #include "MsqError.hpp"
00035 #include "MsqMatrix.hpp"
00036 
00037 #include "TMetric.hpp"
00038 #include "TMetricBarrier.hpp"
00039 #include "AWMetric.hpp"
00040 #include "AWMetricBarrier.hpp"
00041 
00042 // NOTE: Caller must define TARGET_TEST_GROUP to be a quoted string,
00043 //       typically the base file name of the file containing the
00044 //       calls to TEST_METRIC_*
00045 
00046 // Macro arguments:
00047 //  shape_invariant
00048 //  size_invariant
00049 //  orient_invariant
00050 //  barrier
00051 
00052 #define REGISTER_BASE_TESTS              \
00053     CPPUNIT_TEST( test_ideal_eval );     \
00054     CPPUNIT_TEST( test_ideal_gradient ); \
00055     CPPUNIT_TEST( test_inverted );       \
00056     CPPUNIT_TEST( test_shape );          \
00057     CPPUNIT_TEST( test_scale );          \
00058     CPPUNIT_TEST( test_orient )
00059 
00060 #define REGISTER_GRAD_TESTS                          \
00061     CPPUNIT_TEST( compare_eval_and_eval_with_grad ); \
00062     CPPUNIT_TEST( compare_anaytic_and_numeric_grads )
00063 
00064 #define REGISTER_HESS_TESTS                                    \
00065     CPPUNIT_TEST( compare_eval_with_grad_and_eval_with_hess ); \
00066     CPPUNIT_TEST( compare_anaytic_and_numeric_hess )
00067 
00068 #define BEGIN_TEST_DECL( METRIC, DIM, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )                     \
00069     class METRIC##_##DIM##DTest : public TMetricTest< METRIC, DIM >                                               \
00070     {                                                                                                             \
00071       public:                                                                                                     \
00072         METRIC##_##DIM##DTest()                                                                                   \
00073             : TMetricTest< METRIC, DIM >( ( SHAPE_INVAR ), ( SIZE_INVAR ), ( ORIENT_INVAR ), ( BARRIER ), IDEAL ) \
00074         {                                                                                                         \
00075         }                                                                                                         \
00076         CPPUNIT_TEST_SUITE( METRIC##_##DIM##DTest )
00077 
00078 #define END_TEST_DECL( SUITE, DIM, METRIC )                                                                     \
00079     CPPUNIT_TEST_SUITE_END();                                                                                   \
00080     }                                                                                                           \
00081     ;                                                                                                           \
00082     CPPUNIT_NS::AutoRegisterSuite< METRIC##_##DIM##DTest > METRIC##_##DIM##D_UnitRegister( "Unit" );            \
00083     CPPUNIT_NS::AutoRegisterSuite< METRIC##_##DIM##DTest > METRIC##_##DIM##D_FileRegister( TARGET_TEST_GROUP ); \
00084     CPPUNIT_NS::AutoRegisterSuite< METRIC##_##DIM##DTest > METRIC##_##DIM##D_BaseRegister( #SUITE "Test" )
00085 
00086 /** Register tests for metric with no derivative implementations */
00087 #define TEST_METRIC_NO_DERIVS_2D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00088     BEGIN_TEST_DECL( METRIC, 2, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL );          \
00089     REGISTER_BASE_TESTS;                                                                          \
00090     END_TEST_DECL( METRIC, 2, METRIC )
00091 
00092 /** Register tests for metric with no derivative implementations */
00093 #define TEST_METRIC_NO_DERIVS_3D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00094     BEGIN_TEST_DECL( METRIC, 3, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIE, IDEALR );          \
00095     REGISTER_BASE_TESTS;                                                                          \
00096     END_TEST_DECL( METRIC, 3, METRIC )
00097 
00098 /** Register tests for metric with no derivative implementations */
00099 #define TEST_METRIC_NO_DERIVS( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00100     TEST_METRIC_NO_DERIVS_2D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ); \
00101     TEST_METRIC_NO_DERIVS_3D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00102 
00103 /** Register tests for metric with implementation of analytic gradient */
00104 #define TEST_METRIC_WITH_GRAD_2D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00105     BEGIN_TEST_DECL( METRIC, 2, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL );          \
00106     REGISTER_BASE_TESTS;                                                                          \
00107     REGISTER_GRAD_TESTS;                                                                          \
00108     END_TEST_DECL( METRIC, 2, METRIC )
00109 
00110 /** Register tests for metric with implementation of analytic gradient */
00111 #define TEST_METRIC_WITH_GRAD_3D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00112     BEGIN_TEST_DECL( METRIC, 3, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL );          \
00113     REGISTER_BASE_TESTS;                                                                          \
00114     REGISTER_GRAD_TESTS;                                                                          \
00115     END_TEST_DECL( METRIC, 3, METRIC )
00116 
00117 /** Register tests for metric with implementation of analytic gradient */
00118 #define TEST_METRIC_WITH_GRAD( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00119     TEST_METRIC_WITH_GRAD_2D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ); \
00120     TEST_METRIC_WITH_GRAD_3D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00121 
00122 #define TEST_NAMED_METRIC_WITH_HESS_2D( METRIC, NAME, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00123     BEGIN_TEST_DECL( METRIC, 2, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL );                      \
00124     REGISTER_BASE_TESTS;                                                                                      \
00125     REGISTER_GRAD_TESTS;                                                                                      \
00126     REGISTER_HESS_TESTS;                                                                                      \
00127     END_TEST_DECL( NAME, 2, METRIC )
00128 
00129 #define TEST_NAMED_METRIC_WITH_HESS_3D( METRIC, NAME, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00130     BEGIN_TEST_DECL( METRIC, 3, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL );                      \
00131     REGISTER_BASE_TESTS;                                                                                      \
00132     REGISTER_GRAD_TESTS;                                                                                      \
00133     REGISTER_HESS_TESTS;                                                                                      \
00134     END_TEST_DECL( NAME, 3, METRIC )
00135 
00136 /** Register tests for metric with implementation of analytic gradient and Hessian */
00137 #define TEST_NAMED_METRIC_WITH_HESS( METRIC, NAME, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00138     TEST_NAMED_METRIC_WITH_HESS_2D( METRIC, NAME, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ); \
00139     TEST_NAMED_METRIC_WITH_HESS_3D( METRIC, NAME, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00140 
00141 /** Register tests for metric with implementation of analytic gradient and Hessian */
00142 #define TEST_METRIC_WITH_HESS_2D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00143     TEST_NAMED_METRIC_WITH_HESS_2D( METRIC, METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00144 
00145 /** Register tests for metric with implementation of analytic gradient and Hessian */
00146 #define TEST_METRIC_WITH_HESS_3D( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ) \
00147     TEST_NAMED_METRIC_WITH_HESS_3D( METRIC, METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00148 
00149 /** Register tests for metric with implementation of analytic gradient and Hessian */
00150 #define TEST_METRIC_WITH_HESS( METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )               \
00151     TEST_NAMED_METRIC_WITH_HESS_2D( METRIC, METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL ); \
00152     TEST_NAMED_METRIC_WITH_HESS_3D( METRIC, METRIC, SHAPE_INVAR, SIZE_INVAR, ORIENT_INVAR, BARRIER, IDEAL )
00153 
00154 #define TEST_NON_QUALITY_METRIC_WITH_HESS_2D( METRIC )         \
00155     BEGIN_TEST_DECL( METRIC, 2, true, true, true, true, 0.0 ); \
00156     REGISTER_GRAD_TESTS;                                       \
00157     REGISTER_HESS_TESTS;                                       \
00158     END_TEST_DECL( NAME, 2, METRIC )
00159 
00160 #define TEST_NON_QUALITY_METRIC_WITH_HESS_3D( METRIC )         \
00161     BEGIN_TEST_DECL( METRIC, 3, true, true, true, true, 0.0 ); \
00162     REGISTER_GRAD_TESTS;                                       \
00163     REGISTER_HESS_TESTS;                                       \
00164     END_TEST_DECL( NAME, 3, METRIC )
00165 
00166 /** Regsiter tests for a metric that doesn't really measure quality */
00167 #define TEST_NON_QUALITY_METRIC_WITH_HESS( METRIC ) \
00168     TEST_NON_QUALITY_METRIC_WITH_HESS_2D( METRIC ); \
00169     TEST_NON_QUALITY_METRIC_WITH_HESS_3D( METRIC );
00170 
00171 using namespace MBMesquite;
00172 
00173 const double Avals[][9] = { { 0 },
00174                             { 2 },
00175                             { 2, 1,  // 2x2 values
00176                               1, 2 },
00177                             { 2, 1, 1,  // 3x3 values
00178                               1, 2, 1, 1, 1, 2 } };
00179 const double Bvals[][9] = { { 0 },
00180                             { -0.1 },
00181                             { -0.1, -0.15,  // 2x2 values
00182                               -0.25, -0.8 },
00183                             { 1.5, -0.7, -0.8,  // 3x3 values
00184                               0.8, -1.3, -0.7, 0.6, -0.9, -2.0 } };
00185 const double Cvals[][9] = { { 0 },
00186                             { 0.5 },
00187                             { -1.0, 0.5,  // 2x2 values
00188                               0.0, 1.0 },
00189                             { 0.5, 0.0, 0.1,  // 3x3 values
00190                               0.5, 1.0, 0.1, 0.0, 0.0, -1.5 } };
00191 
00192 /**\brief Common tests for all target metric types
00193  *
00194  * Commont test framework for implementations of the following types:
00195  * \c TMetric , \c AWMetric
00196  */
00197 template < class Metric, unsigned DIM >
00198 class TMetricTest : public CppUnit::TestFixture
00199 {
00200 
00201   private:
00202     Metric testMetric;
00203     const double idealVal;
00204     const bool shapeInvariant, sizeInvariant, orientInvariant, Barrier;
00205 
00206   public:
00207     typedef MsqMatrix< DIM, DIM > Matrix;
00208 
00209     TMetricTest( bool shape_invariant, bool size_invariant, bool orient_invariant, bool barrier, double ideal_val )
00210         : idealVal( ideal_val ), shapeInvariant( shape_invariant ), sizeInvariant( size_invariant ),
00211           orientInvariant( orient_invariant ), Barrier( barrier ), Zero( 0.0 ), I( 1.0 ), A( Avals[DIM] ),
00212           B( Bvals[DIM] ), C( Cvals[DIM] )
00213     {
00214     }
00215 
00216     // Some initial matrix values used in many tests
00217     const Matrix Zero, I, A, B, C;
00218 
00219     void test_ideal_eval();
00220     void test_ideal_gradient();
00221     void test_inverted();
00222     void test_shape();
00223     void test_scale();
00224     void test_orient();
00225 
00226     void compare_anaytic_and_numeric_grads();
00227     void compare_anaytic_and_numeric_hess();
00228     void compare_eval_and_eval_with_grad();
00229     void compare_eval_with_grad_and_eval_with_hess();
00230 
00231   private:
00232     /**\brief Test if metric is or is not sensitive to difference between A and W
00233      *
00234      * Given an active matrix A and a target matrix W, test whether or
00235      * not the metric is sensitive to the difference.  Fail if actual
00236      * sensitivity to difference is not equal to expected sensitivity
00237      * passed as the first argument
00238      */
00239     void test_non_ideal( bool sensitive, Matrix A, Matrix W );
00240 
00241     /*************************************************************************
00242      *               Use overloaded function names to do the stuff
00243      *               that is different for different base metric types
00244      *************************************************************************/
00245 
00246     // TMetric
00247     inline bool eval( TMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value, MsqError& err )
00248     {
00249         return metric.evaluate( A * inverse( W ), value, err );
00250     }
00251     inline bool grad( TMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00252                       MsqMatrix< DIM, DIM >& dmdA, MsqError& err )
00253     {
00254         bool rval = metric.evaluate_with_grad( A * inverse( W ), value, dmdA, err );
00255         dmdA      = dmdA * transpose( inverse( W ) );
00256         return rval;
00257     }
00258     inline bool num_grad( TMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00259                           MsqMatrix< DIM, DIM >& dmdA, MsqError& err )
00260     {
00261         bool rval = metric.evaluate_with_grad( A * inverse( W ), value, dmdA, err );
00262         dmdA      = dmdA * transpose( inverse( W ) );
00263         return rval;
00264     }
00265     inline bool hess( TMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00266                       MsqMatrix< DIM, DIM >& dmdA, MsqMatrix< DIM, DIM > d2mdA2[3], MsqError& err )
00267     {
00268         bool rval = metric.evaluate_with_hess( A * inverse( W ), value, dmdA, d2mdA2, err );
00269         dmdA      = dmdA * transpose( inverse( W ) );
00270         for( unsigned i = 0; i < DIM * ( DIM + 1 ) / 2; ++i )
00271             d2mdA2[i] = inverse( W ) * d2mdA2[i] * transpose( inverse( W ) );
00272         return rval;
00273     }
00274     inline bool num_hess( TMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00275                           MsqMatrix< DIM, DIM >& dmdA, MsqMatrix< DIM, DIM > d2mdA2[3], MsqError& err )
00276     {
00277         bool rval = metric.evaluate_with_hess( A * inverse( W ), value, dmdA, d2mdA2, err );
00278         dmdA      = dmdA * transpose( inverse( W ) );
00279         for( unsigned i = 0; i < DIM * ( DIM + 1 ) / 2; ++i )
00280             d2mdA2[i] = inverse( W ) * d2mdA2[i] * transpose( inverse( W ) );
00281         return rval;
00282     }
00283 
00284     // AWMetric
00285     inline bool eval( AWMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value, MsqError& err )
00286     {
00287         bool rval = metric.evaluate( A, W, value, err );
00288         return rval;
00289     }
00290     inline bool grad( AWMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00291                       MsqMatrix< DIM, DIM >& dmdA, MsqError& err )
00292     {
00293         bool rval = metric.evaluate_with_grad( A, W, value, dmdA, err );
00294         return rval;
00295     }
00296     inline bool num_grad( AWMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00297                           MsqMatrix< DIM, DIM >& dmdA, MsqError& err )
00298     {
00299         bool rval = metric.evaluate_with_grad( A, W, value, dmdA, err );
00300         return rval;
00301     }
00302     inline bool hess( AWMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00303                       MsqMatrix< DIM, DIM >& dmdA, MsqMatrix< DIM, DIM > d2mdA2[3], MsqError& err )
00304     {
00305         bool rval = metric.evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00306         return rval;
00307     }
00308     inline bool num_hess( AWMetric& metric, MsqMatrix< DIM, DIM > A, MsqMatrix< DIM, DIM > W, double& value,
00309                           MsqMatrix< DIM, DIM >& dmdA, MsqMatrix< DIM, DIM > d2mdA2[3], MsqError& err )
00310     {
00311         bool rval = metric.evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00312         return rval;
00313     }
00314 };
00315 
00316 #define TMETRIC_FUNC                        \
00317     template < class Metric, unsigned DIM > \
00318     void TMetricTest< Metric, DIM >
00319 #define MAT_TYPE TMetricTest< Metric, DIM >::Matrix
00320 
00321 /*************************************************************************
00322  *          Implement actual (templatized) test code
00323  *************************************************************************/
00324 
00325 TMETRIC_FUNC::test_ideal_eval()
00326 {
00327     MsqPrintError err( std::cerr );
00328     double val, eps = 5e-5;
00329     bool valid;
00330 
00331     valid = eval( testMetric, I, I, val, err );
00332     ASSERT_NO_ERROR( err );
00333     CPPUNIT_ASSERT( valid );
00334     CPPUNIT_ASSERT_DOUBLES_EQUAL( idealVal, val, eps );
00335 
00336     valid = eval( testMetric, A, A, val, err );
00337     ASSERT_NO_ERROR( err );
00338     CPPUNIT_ASSERT( valid );
00339     CPPUNIT_ASSERT_DOUBLES_EQUAL( idealVal, val, eps );
00340 
00341     valid = eval( testMetric, B, B, val, err );
00342     ASSERT_NO_ERROR( err );
00343     CPPUNIT_ASSERT( valid );
00344     CPPUNIT_ASSERT_DOUBLES_EQUAL( idealVal, val, eps );
00345 }
00346 
00347 TMETRIC_FUNC::test_ideal_gradient()
00348 {
00349     MsqPrintError err( std::cerr );
00350     MsqMatrix< DIM, DIM > g;
00351     double val, eps = 5e-3;
00352     bool valid;
00353 
00354     valid = grad( testMetric, I, I, val, g, err );
00355     ASSERT_NO_ERROR( err );
00356     CPPUNIT_ASSERT( valid );
00357     ASSERT_MATRICES_EQUAL( Zero, g, eps );
00358 
00359     valid = grad( testMetric, A, A, val, g, err );
00360     ASSERT_NO_ERROR( err );
00361     CPPUNIT_ASSERT( valid );
00362     ASSERT_MATRICES_EQUAL( Zero, g, eps );
00363 
00364     valid = grad( testMetric, B, B, val, g, err );
00365     ASSERT_NO_ERROR( err );
00366     CPPUNIT_ASSERT( valid );
00367     ASSERT_MATRICES_EQUAL( Zero, g, eps );
00368 }
00369 
00370 TMETRIC_FUNC::test_inverted()
00371 {
00372     MsqPrintError err( std::cerr );
00373     MsqMatrix< DIM, DIM > V( 1.0 ), W( 1.0 ), g, h[6];
00374     V( DIM - 1, DIM - 1 ) = -1.0;
00375     double val;
00376     bool valid;
00377 
00378     if( Barrier )
00379     {
00380         valid = eval( testMetric, V, W, val, err );
00381         if( err.error_code() == err.BARRIER_VIOLATED ) err.clear();
00382         ASSERT_NO_ERROR( err );
00383         CPPUNIT_ASSERT( !valid );
00384 
00385         valid = grad( testMetric, V, W, val, g, err );
00386         if( err.error_code() == err.BARRIER_VIOLATED ) err.clear();
00387         ASSERT_NO_ERROR( err );
00388         CPPUNIT_ASSERT( !valid );
00389 
00390         valid = hess( testMetric, V, W, val, g, h, err );
00391         if( err.error_code() == err.BARRIER_VIOLATED ) err.clear();
00392         ASSERT_NO_ERROR( err );
00393         CPPUNIT_ASSERT( !valid );
00394     }
00395     else
00396     {
00397         valid = eval( testMetric, V, W, val, err );
00398         ASSERT_NO_ERROR( err );
00399         CPPUNIT_ASSERT( valid );
00400         CPPUNIT_ASSERT( val > idealVal );
00401 
00402         valid = grad( testMetric, V, W, val, g, err );
00403         ASSERT_NO_ERROR( err );
00404         CPPUNIT_ASSERT( valid );
00405         CPPUNIT_ASSERT( val > idealVal );
00406         CPPUNIT_ASSERT( sqr_Frobenius( g ) > 1e-6 );
00407     }
00408 }
00409 
00410 TMETRIC_FUNC::test_non_ideal( bool sensitive, Matrix J, Matrix W )
00411 {
00412     MsqPrintError err( std::cerr );
00413     MsqMatrix< DIM, DIM > g;
00414     double val, eps = 1e-5;
00415     bool valid;
00416     if( !sensitive )
00417     {
00418         valid = eval( testMetric, J, W, val, err );
00419         ASSERT_NO_ERROR( err );
00420         CPPUNIT_ASSERT( valid );
00421         CPPUNIT_ASSERT_DOUBLES_EQUAL( idealVal, val, eps );
00422 
00423         valid = grad( testMetric, J, W, val, g, err );
00424         ASSERT_NO_ERROR( err );
00425         CPPUNIT_ASSERT( valid );
00426         CPPUNIT_ASSERT_DOUBLES_EQUAL( idealVal, val, eps );
00427         ASSERT_MATRICES_EQUAL( ( MsqMatrix< DIM, DIM >( 0.0 ) ), g, eps );
00428     }
00429     else
00430     {
00431         valid = eval( testMetric, J, W, val, err );
00432         ASSERT_NO_ERROR( err );
00433         CPPUNIT_ASSERT( valid );
00434         CPPUNIT_ASSERT( val > idealVal );
00435     }
00436 }
00437 
00438 TMETRIC_FUNC::test_shape()
00439 {
00440     const double r3          = sqrt( 3.0 );
00441     const double U_vals[][9] = { { 2 / r3, 1 / r3, 1 / r3, 2 / r3 },
00442                                  { 2 / r3, 1 / r3, 0, 1 / r3, 2 / r3, 0, 0, 0, 1 } };
00443     Matrix U( U_vals[DIM - 2] ), W( 1.0 );
00444     test_non_ideal( !shapeInvariant, U, W );
00445 }
00446 
00447 TMETRIC_FUNC::test_scale()
00448 {
00449     Matrix L( 2.0 ), W( 1.0 );
00450     test_non_ideal( !sizeInvariant, L, W );
00451 }
00452 
00453 TMETRIC_FUNC::test_orient()
00454 {
00455     const double V_vals[][9] = { { 0, -1, 1, 0 }, { 0, -1, 0, 1, 0, 0, 0, 0, 1 } };
00456     Matrix V( V_vals[DIM - 2] ), W( 1.0 );
00457     test_non_ideal( !orientInvariant, V, W );
00458 }
00459 
00460 static double releps( double a )
00461 {
00462     return std::max( 1e-6, 1e-8 * fabs( a ) );
00463 }
00464 
00465 TMETRIC_FUNC::compare_eval_and_eval_with_grad()
00466 {
00467     MsqError err;
00468     Matrix g;
00469     bool valid;
00470     double gv, v;
00471 
00472     valid = grad( testMetric, I, A, gv, g, err );
00473     ASSERT_NO_ERROR( err );
00474     CPPUNIT_ASSERT( valid );
00475     valid = eval( testMetric, I, A, v, err );
00476     ASSERT_NO_ERROR( err );
00477     CPPUNIT_ASSERT( valid );
00478     CPPUNIT_ASSERT_DOUBLES_EQUAL( v, gv, releps( v ) );
00479 
00480     valid = grad( testMetric, A, B, gv, g, err );
00481     ASSERT_NO_ERROR( err );
00482     CPPUNIT_ASSERT( valid );
00483     valid = eval( testMetric, A, B, v, err );
00484     ASSERT_NO_ERROR( err );
00485     CPPUNIT_ASSERT( valid );
00486     CPPUNIT_ASSERT_DOUBLES_EQUAL( v, gv, releps( v ) );
00487 
00488     // also test inverted for non-barrier metrics
00489     if( Barrier ) return;
00490 
00491     valid = grad( testMetric, C, I, gv, g, err );
00492     ASSERT_NO_ERROR( err );
00493     CPPUNIT_ASSERT( valid );
00494     valid = eval( testMetric, C, I, v, err );
00495     ASSERT_NO_ERROR( err );
00496     CPPUNIT_ASSERT( valid );
00497     CPPUNIT_ASSERT_DOUBLES_EQUAL( v, gv, releps( v ) );
00498 }
00499 
00500 TMETRIC_FUNC::compare_eval_with_grad_and_eval_with_hess()
00501 {
00502     MsqError err;
00503     Matrix g, h, H[DIM * ( DIM + 1 ) / 2];
00504     bool valid;
00505     double gv, hv;
00506 
00507     valid = grad( testMetric, I, A, gv, g, err );
00508     ASSERT_NO_ERROR( err );
00509     CPPUNIT_ASSERT( valid );
00510     valid = hess( testMetric, I, A, hv, h, H, err );
00511     ASSERT_NO_ERROR( err );
00512     CPPUNIT_ASSERT( valid );
00513     CPPUNIT_ASSERT_DOUBLES_EQUAL( gv, hv, releps( gv ) );
00514     ASSERT_MATRICES_EQUAL( g, h, 1e-5 );
00515 
00516     valid = grad( testMetric, A, B, gv, g, err );
00517     ASSERT_NO_ERROR( err );
00518     CPPUNIT_ASSERT( valid );
00519     valid = hess( testMetric, A, B, hv, h, H, err );
00520     ASSERT_NO_ERROR( err );
00521     CPPUNIT_ASSERT( valid );
00522     CPPUNIT_ASSERT_DOUBLES_EQUAL( gv, hv, releps( gv ) );
00523     ASSERT_MATRICES_EQUAL( g, h, 1e-5 );
00524 
00525     // also test inverted for non-barrier metrics
00526     if( Barrier ) return;
00527 
00528     valid = grad( testMetric, C, I, gv, g, err );
00529     ASSERT_NO_ERROR( err );
00530     CPPUNIT_ASSERT( valid );
00531     valid = hess( testMetric, C, I, hv, h, H, err );
00532     ASSERT_NO_ERROR( err );
00533     CPPUNIT_ASSERT( valid );
00534     CPPUNIT_ASSERT_DOUBLES_EQUAL( gv, hv, releps( gv ) );
00535     ASSERT_MATRICES_EQUAL( g, h, 1e-5 );
00536 }
00537 
00538 template < typename M >
00539 double eps_mat( const M& mu )
00540 {
00541     return std::max( Frobenius( mu ) * 1e-2, 1e-4 );
00542 }
00543 
00544 TMETRIC_FUNC::compare_anaytic_and_numeric_grads()
00545 {
00546     const double EPS_VAL = 1e-6;
00547 
00548     MsqError err;
00549     Matrix num, ana;
00550     bool valid;
00551     double nval, aval;
00552 
00553     Matrix D( I );
00554     D( 0, 0 ) += 1e-5;
00555     valid = num_grad( testMetric, D, I, nval, num, err );
00556     ASSERT_NO_ERROR( err );
00557     CPPUNIT_ASSERT( valid );
00558     valid = grad( testMetric, D, I, aval, ana, err );
00559     ASSERT_NO_ERROR( err );
00560     CPPUNIT_ASSERT( valid );
00561     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00562     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00563 
00564     valid = num_grad( testMetric, I, A, nval, num, err );
00565     ASSERT_NO_ERROR( err );
00566     CPPUNIT_ASSERT( valid );
00567     valid = grad( testMetric, I, A, aval, ana, err );
00568     ASSERT_NO_ERROR( err );
00569     CPPUNIT_ASSERT( valid );
00570     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00571     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00572 
00573     valid = num_grad( testMetric, A, I, nval, num, err );
00574     ASSERT_NO_ERROR( err );
00575     CPPUNIT_ASSERT( valid );
00576     valid = grad( testMetric, A, I, aval, ana, err );
00577     ASSERT_NO_ERROR( err );
00578     CPPUNIT_ASSERT( valid );
00579     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00580     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00581 
00582     valid = num_grad( testMetric, I, B, nval, num, err );
00583     ASSERT_NO_ERROR( err );
00584     CPPUNIT_ASSERT( valid );
00585     valid = grad( testMetric, I, B, aval, ana, err );
00586     ASSERT_NO_ERROR( err );
00587     CPPUNIT_ASSERT( valid );
00588     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00589     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00590 
00591     valid = num_grad( testMetric, B, I, nval, num, err );
00592     ASSERT_NO_ERROR( err );
00593     CPPUNIT_ASSERT( valid );
00594     valid = grad( testMetric, B, I, aval, ana, err );
00595     ASSERT_NO_ERROR( err );
00596     CPPUNIT_ASSERT( valid );
00597     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00598     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00599 
00600     valid = num_grad( testMetric, A, B, nval, num, err );
00601     ASSERT_NO_ERROR( err );
00602     CPPUNIT_ASSERT( valid );
00603     valid = grad( testMetric, A, B, aval, ana, err );
00604     ASSERT_NO_ERROR( err );
00605     CPPUNIT_ASSERT( valid );
00606     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00607     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00608 
00609     valid = num_grad( testMetric, A, I, nval, num, err );
00610     ASSERT_NO_ERROR( err );
00611     CPPUNIT_ASSERT( valid );
00612     valid = grad( testMetric, A, I, aval, ana, err );
00613     ASSERT_NO_ERROR( err );
00614     CPPUNIT_ASSERT( valid );
00615     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00616     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00617 
00618     // also test inverted for non-barrier metrics
00619     if( Barrier ) return;
00620 
00621     valid = num_grad( testMetric, C, I, nval, num, err );
00622     ASSERT_NO_ERROR( err );
00623     CPPUNIT_ASSERT( valid );
00624     valid = grad( testMetric, C, I, aval, ana, err );
00625     ASSERT_NO_ERROR( err );
00626     CPPUNIT_ASSERT( valid );
00627     CPPUNIT_ASSERT_DOUBLES_EQUAL( nval, aval, EPS_VAL );
00628     ASSERT_MATRICES_EQUAL( num, ana, eps_mat( num ) );
00629 }
00630 
00631 TMETRIC_FUNC::compare_anaytic_and_numeric_hess()
00632 {
00633     const double EPS_VAL = 1e-6;
00634 
00635     MsqError err;
00636     Matrix dmdA_num, dmdA_ana, d2mdA2_num[DIM * ( DIM + 1 ) / 2], d2mdA2_ana[DIM * ( DIM + 1 ) / 2];
00637     bool valid;
00638     double val_num, val_ana;
00639 
00640     valid = num_hess( testMetric, I, I, val_num, dmdA_num, d2mdA2_num, err );
00641     ASSERT_NO_ERROR( err );
00642     CPPUNIT_ASSERT( valid );
00643     valid = hess( testMetric, I, I, val_ana, dmdA_ana, d2mdA2_ana, err );
00644     ASSERT_NO_ERROR( err );
00645     CPPUNIT_ASSERT( valid );
00646     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00647     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00648 
00649     switch( DIM )
00650     {
00651         default:
00652             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00653             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00654             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00655         case 2:
00656             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00657             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00658             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00659     }
00660 
00661     valid = num_hess( testMetric, I, A, val_num, dmdA_num, d2mdA2_num, err );
00662     ASSERT_NO_ERROR( err );
00663     CPPUNIT_ASSERT( valid );
00664     valid = hess( testMetric, I, A, val_ana, dmdA_ana, d2mdA2_ana, err );
00665     ASSERT_NO_ERROR( err );
00666     CPPUNIT_ASSERT( valid );
00667     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00668     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00669     switch( DIM )
00670     {
00671         default:
00672             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00673             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00674             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00675         case 2:
00676             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00677             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00678             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00679     }
00680 
00681     valid = num_hess( testMetric, A, I, val_num, dmdA_num, d2mdA2_num, err );
00682     ASSERT_NO_ERROR( err );
00683     CPPUNIT_ASSERT( valid );
00684     valid = hess( testMetric, A, I, val_ana, dmdA_ana, d2mdA2_ana, err );
00685     ASSERT_NO_ERROR( err );
00686     CPPUNIT_ASSERT( valid );
00687     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00688     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00689     switch( DIM )
00690     {
00691         default:
00692             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00693             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00694             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00695         case 2:
00696             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00697             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00698             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00699     }
00700 
00701     valid = num_hess( testMetric, B, I, val_num, dmdA_num, d2mdA2_num, err );
00702     ASSERT_NO_ERROR( err );
00703     CPPUNIT_ASSERT( valid );
00704     valid = hess( testMetric, B, I, val_ana, dmdA_ana, d2mdA2_ana, err );
00705     ASSERT_NO_ERROR( err );
00706     CPPUNIT_ASSERT( valid );
00707     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00708     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00709     switch( DIM )
00710     {
00711         default:
00712             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00713             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00714             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00715         case 2:
00716             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00717             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00718             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00719     }
00720 
00721     valid = num_hess( testMetric, I, B, val_num, dmdA_num, d2mdA2_num, err );
00722     ASSERT_NO_ERROR( err );
00723     CPPUNIT_ASSERT( valid );
00724     valid = hess( testMetric, I, B, val_ana, dmdA_ana, d2mdA2_ana, err );
00725     ASSERT_NO_ERROR( err );
00726     CPPUNIT_ASSERT( valid );
00727     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00728     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00729     switch( DIM )
00730     {
00731         default:
00732             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00733             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00734             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00735         case 2:
00736             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00737             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00738             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00739     }
00740 
00741     valid = num_hess( testMetric, A, B, val_num, dmdA_num, d2mdA2_num, err );
00742     ASSERT_NO_ERROR( err );
00743     CPPUNIT_ASSERT( valid );
00744     valid = hess( testMetric, A, B, val_ana, dmdA_ana, d2mdA2_ana, err );
00745     ASSERT_NO_ERROR( err );
00746     CPPUNIT_ASSERT( valid );
00747     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00748     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00749     switch( DIM )
00750     {
00751         default:
00752             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00753             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00754             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00755         case 2:
00756             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00757             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00758             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00759     }
00760 
00761     valid = num_hess( testMetric, B, A, val_num, dmdA_num, d2mdA2_num, err );
00762     ASSERT_NO_ERROR( err );
00763     CPPUNIT_ASSERT( valid );
00764     valid = hess( testMetric, B, A, val_ana, dmdA_ana, d2mdA2_ana, err );
00765     ASSERT_NO_ERROR( err );
00766     CPPUNIT_ASSERT( valid );
00767     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00768     ASSERT_MATRICES_EQUAL( dmdA_num, dmdA_ana, eps_mat( dmdA_num ) );
00769     switch( DIM )
00770     {
00771         default:
00772             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00773             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00774             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00775         case 2:
00776             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00777             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00778             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00779     }
00780 
00781     // also test inverted for non-barrier metrics
00782     if( Barrier ) return;
00783 
00784     valid = num_hess( testMetric, C, I, val_num, dmdA_num, d2mdA2_num, err );
00785     ASSERT_NO_ERROR( err );
00786     CPPUNIT_ASSERT( valid );
00787     valid = hess( testMetric, C, I, val_ana, dmdA_ana, d2mdA2_ana, err );
00788     ASSERT_NO_ERROR( err );
00789     CPPUNIT_ASSERT( valid );
00790     CPPUNIT_ASSERT_DOUBLES_EQUAL( val_num, val_ana, EPS_VAL );
00791     switch( DIM )
00792     {
00793         default:
00794             ASSERT_MATRICES_EQUAL( d2mdA2_num[3], d2mdA2_ana[3], eps_mat( d2mdA2_num[3] ) );
00795             ASSERT_MATRICES_EQUAL( d2mdA2_num[4], d2mdA2_ana[4], eps_mat( d2mdA2_num[4] ) );
00796             ASSERT_MATRICES_EQUAL( d2mdA2_num[5], d2mdA2_ana[5], eps_mat( d2mdA2_num[5] ) );
00797         case 2:
00798             ASSERT_MATRICES_EQUAL( d2mdA2_num[0], d2mdA2_ana[0], eps_mat( d2mdA2_num[0] ) );
00799             ASSERT_MATRICES_EQUAL( d2mdA2_num[1], d2mdA2_ana[1], eps_mat( d2mdA2_num[1] ) );
00800             ASSERT_MATRICES_EQUAL( d2mdA2_num[2], d2mdA2_ana[2], eps_mat( d2mdA2_num[2] ) );
00801     }
00802 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines