MOAB: Mesh Oriented datABase  (version 5.4.0)
ObjectiveFunctionTests.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     (2006) kraftche@cae.wisc.edu
00024 
00025   ***************************************************************** */
00026 
00027 /** \file ObjectiveFunctionTests.hpp
00028  *  \brief
00029  *  \author Jason Kraftcheck
00030  */
00031 
00032 #ifndef MSQ_OBJECTIVE_FUNCTION_TESTS_HPP
00033 #define MSQ_OBJECTIVE_FUNCTION_TESTS_HPP
00034 
00035 #include "Mesquite.hpp"
00036 #include "PatchDataInstances.hpp"
00037 #include "IdealWeightInverseMeanRatio.hpp"
00038 #include "ObjectiveFunctionTemplate.hpp"
00039 #include "UnitUtil.hpp"
00040 #include "MsqHessian.hpp"
00041 
00042 #include <memory>
00043 
00044 using namespace MBMesquite;
00045 using namespace std;
00046 
00047 class ObjectiveFunctionTests
00048 {
00049 
00050   public:
00051     /** Which function to call */
00052     enum OFTestMode
00053     {
00054         EVAL,
00055         GRAD,
00056         DIAG,
00057         HESS
00058     };
00059 
00060     /** Test eval type support for OF templates that provide
00061      *  block coordinate descent functionality.
00062      *
00063      *  Note: If OF does not support BCD, this test will fail,
00064      *        even for the ObjectiveFunction::CALCULATE eval type.
00065      */
00066     static void test_eval_type( ObjectiveFunction::EvalType, OFTestMode test_mode, ObjectiveFunctionTemplate* of );
00067 
00068     /** Verify that if QualityMetric returns invalid but not error
00069      *  from evaluate, that the ObjectiveFunction does the same */
00070     static void test_handles_invalid_qm( OFTestMode test_mode, ObjectiveFunctionTemplate* of );
00071 
00072     /** Verify that OF correctly handles error in QM::evaluate() */
00073     static void test_handles_qm_error( OFTestMode test_mode, ObjectiveFunctionTemplate* of );
00074 
00075     /** Test the behavior of the clone() method */
00076     static void test_clone( ObjectiveFunctionTemplate* of );
00077 
00078     /** Test correct handling of QM negate flag */
00079     static void test_negate_flag( OFTestMode test_mode, ObjectiveFunctionTemplate* of );
00080 
00081     /** Test OF value */
00082     static void test_value( const double* input_values,
00083                             unsigned num_input_values,
00084                             double expected_value,
00085                             OFTestMode test_mode,
00086                             ObjectiveFunctionTemplate* of );
00087 
00088     /** Compare numerical and analytical gradient values */
00089     static inline void compare_numerical_gradient( ObjectiveFunctionTemplate* of );
00090     static void compare_numerical_gradient( ObjectiveFunction* of );
00091 
00092     /** Compare gradients from evaluate_with_gradient with gradient
00093      *  from evaluate_with_Hessian
00094      */
00095     static inline void compare_hessian_gradient( ObjectiveFunctionTemplate* of );
00096     static void compare_hessian_gradient( ObjectiveFunction* of );
00097 
00098     /** Compare gradients from evaluate_with_gradient with gradient
00099      *  from evaluate_with_Hessian_diagonal
00100      */
00101     static inline void compare_diagonal_gradient( ObjectiveFunctionTemplate* of );
00102     static void compare_diagonal_gradient( ObjectiveFunction* of );
00103 
00104     /** Compare gradient and diagonal terms from evaluate_with_Hessian
00105      *  and evaluate_with_Hessian_diagonal
00106      */
00107     static inline void compare_hessian_diagonal( ObjectiveFunctionTemplate* of );
00108     static void compare_hessian_diagonal( ObjectiveFunction* of );
00109 
00110     static void compare_numerical_hessian( ObjectiveFunctionTemplate* of );
00111     static void compare_numerical_hessian_diagonal( ObjectiveFunctionTemplate* of );
00112     static void compare_numerical_hessian( ObjectiveFunction* of, bool diagonal_only );
00113 
00114     static PatchData& patch();
00115 
00116   private:
00117     static double evaluate_internal( ObjectiveFunction::EvalType type, OFTestMode test_mode, ObjectiveFunction* of );
00118 };
00119 
00120 /** The QualityMetric to use for testing purposes
00121  *
00122  *  Just pass a specified list of values to the OF
00123  */
00124 class OFTestQM : public QualityMetric
00125 {
00126   public:
00127     OFTestQM() : negateFlag( 1 ) {}
00128 
00129     OFTestQM( const double* values, unsigned num_values ) : mValues( num_values ), negateFlag( 1 )
00130     {
00131         copy( values, values + num_values, mValues.begin() );
00132     }
00133 
00134     void set_values( const double* values, unsigned num_values )
00135     {
00136         mValues.resize( num_values );
00137         copy( values, values + num_values, mValues.begin() );
00138     }
00139 
00140     void append_values( const double* values, unsigned num_values )
00141     {
00142         copy( values, values + num_values, back_inserter( mValues ) );
00143     }
00144 
00145     virtual MetricType get_metric_type() const
00146     {
00147         return ELEMENT_BASED;
00148     }
00149 
00150     virtual string get_name() const
00151     {
00152         return "ObjectiveFunctionTests";
00153     }
00154 
00155     virtual int get_negate_flag() const
00156     {
00157         return negateFlag;
00158     }
00159 
00160     void set_negate_flag( int value )
00161     {
00162         negateFlag = value;
00163     }
00164 
00165     virtual void get_evaluations( PatchData&, vector< size_t >& h, bool, MsqError& )
00166     {
00167         h.resize( mValues.size() );
00168         for( unsigned i = 0; i < mValues.size(); ++i )
00169             h[i] = i;
00170     }
00171 
00172     virtual bool evaluate( PatchData&, size_t h, double& v, MsqError& err )
00173     {
00174         if( h >= mValues.size() )
00175         {
00176             MSQ_SETERR( err )( "handle out of range", MsqError::INVALID_ARG );
00177             return false;
00178         }
00179         v = mValues[h];
00180         return true;
00181     }
00182 
00183     virtual bool evaluate_with_indices( PatchData& pd, size_t h, double& v, vector< size_t >& i, MsqError& err )
00184     {
00185         i.clear();
00186         for( unsigned j = 0; j < pd.num_free_vertices(); ++j )
00187             i.push_back( j );
00188         return evaluate( pd, h, v, err );
00189     }
00190 
00191     virtual bool evaluate_with_gradient( PatchData& pd,
00192                                          size_t h,
00193                                          double& v,
00194                                          vector< size_t >& i,
00195                                          vector< Vector3D >& g,
00196                                          MsqError& err )
00197     {
00198         g.clear();
00199         bool rval = evaluate_with_indices( pd, h, v, i, err );
00200         // grad values are just used to test negate flag, so just
00201         // pass back an arbitrary value for each free vertex
00202         for( unsigned j = 0; j < i.size(); ++j )
00203             g.push_back( Vector3D( 1, 0, 2 ) );
00204         return rval;
00205     }
00206 
00207     virtual bool evaluate_with_Hessian( PatchData& pd,
00208                                         size_t h,
00209                                         double& v,
00210                                         vector< size_t >& i,
00211                                         vector< Vector3D >& g,
00212                                         vector< Matrix3D >& H,
00213                                         MsqError& err )
00214     {
00215         H.clear();
00216         bool rval = evaluate_with_gradient( pd, h, v, i, g, err );
00217         // Hessian values are just used to test negate flag, so
00218         // pass back arbirary values.
00219         for( unsigned r = 0; r < i.size(); ++r )
00220             for( unsigned c = r; c < i.size(); ++c )
00221                 H.push_back( Matrix3D( 1.0 ) );
00222         return rval;
00223     }
00224 
00225   private:
00226     vector< double > mValues;
00227     int negateFlag;
00228 };
00229 
00230 inline void ObjectiveFunctionTests::compare_numerical_gradient( ObjectiveFunctionTemplate* of )
00231 {
00232     MsqPrintError err( std::cout );
00233     IdealWeightInverseMeanRatio metric( err );
00234     ASSERT_NO_ERROR( err );
00235     of->set_quality_metric( &metric );
00236     compare_numerical_gradient( (ObjectiveFunction*)of );
00237 }
00238 
00239 inline void ObjectiveFunctionTests::compare_hessian_gradient( ObjectiveFunctionTemplate* of )
00240 {
00241     MsqPrintError err( std::cout );
00242     IdealWeightInverseMeanRatio metric( err );
00243     ASSERT_NO_ERROR( err );
00244     of->set_quality_metric( &metric );
00245     compare_hessian_gradient( (ObjectiveFunction*)of );
00246 }
00247 
00248 inline void ObjectiveFunctionTests::compare_diagonal_gradient( ObjectiveFunctionTemplate* of )
00249 {
00250     MsqPrintError err( std::cout );
00251     IdealWeightInverseMeanRatio metric( err );
00252     ASSERT_NO_ERROR( err );
00253     of->set_quality_metric( &metric );
00254     compare_diagonal_gradient( (ObjectiveFunction*)of );
00255 }
00256 
00257 inline void ObjectiveFunctionTests::compare_hessian_diagonal( ObjectiveFunctionTemplate* of )
00258 {
00259     MsqPrintError err( std::cout );
00260     IdealWeightInverseMeanRatio metric( err );
00261     ASSERT_NO_ERROR( err );
00262     of->set_quality_metric( &metric );
00263     compare_hessian_diagonal( (ObjectiveFunction*)of );
00264 }
00265 
00266 inline void ObjectiveFunctionTests::compare_numerical_hessian( ObjectiveFunctionTemplate* of )
00267 {
00268     MsqPrintError err( std::cout );
00269     IdealWeightInverseMeanRatio metric( err );
00270     ASSERT_NO_ERROR( err );
00271     of->set_quality_metric( &metric );
00272     compare_numerical_hessian( (ObjectiveFunction*)of, false );
00273 }
00274 
00275 inline void ObjectiveFunctionTests::compare_numerical_hessian_diagonal( ObjectiveFunctionTemplate* of )
00276 {
00277     MsqPrintError err( std::cout );
00278     IdealWeightInverseMeanRatio metric( err );
00279     ASSERT_NO_ERROR( err );
00280     of->set_quality_metric( &metric );
00281     compare_numerical_hessian( (ObjectiveFunction*)of, true );
00282 }
00283 
00284 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines