MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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) [email protected] 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