void ObjectiveFunctionTests::compare_hessian_diagonal( ObjectiveFunction* of ) { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR( err ); std::vector<Vector3D> diag_grad, hess_grad; std::vector<SymMatrix3D> diag; MsqHessian hess; double diag_val, hess_val; bool valid; valid = of->evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, diag_val, diag_grad, diag, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), diag_grad.size() ); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), diag.size() ); hess.initialize( pd, err ); ASSERT_NO_ERROR( err ); valid = of->evaluate_with_Hessian( ObjectiveFunction::CALCULATE, pd, hess_val, hess_grad, hess, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess_grad.size() ); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess.size() ); CPPUNIT_ASSERT_DOUBLES_EQUAL( hess_val, diag_val, 1e-6 ); for (size_t i = 0; i < pd.num_free_vertices(); ++i) { CPPUNIT_ASSERT_VECTORS_EQUAL( hess_grad[i], diag_grad[i], 1e-6 ); CPPUNIT_ASSERT_MATRICES_EQUAL( *hess.get_block(i,i), diag[i], 1e-6 ); } }
/** Internal helper function for test_eval_type */ double ObjectiveFunctionTests::evaluate_internal( ObjectiveFunction::EvalType type, OFTestMode test_mode, ObjectiveFunction* of ) { MsqPrintError err(cout); vector<Vector3D> grad; vector<SymMatrix3D> diag; MsqHessian hess; bool valid = false; double result; switch (test_mode) { case EVAL: valid = of->evaluate( type, patch(), result, OF_FREE_EVALS_ONLY, err ); break; case GRAD: valid = of->evaluate_with_gradient( type, patch(), result, grad, err ); break; case DIAG: valid = of->evaluate_with_Hessian_diagonal( type, patch(), result, grad, diag, err ); break; case HESS: hess.initialize( patch(), err ); ASSERT_NO_ERROR( err ); valid = of->evaluate_with_Hessian( type, patch(), result, grad, hess, err ); break; default: CPPUNIT_ASSERT(false); } ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); return result; }
void ObjectiveFunctionTests::compare_diagonal_gradient( ObjectiveFunction* of ) { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR( err ); std::vector<Vector3D> grad, hess_grad; std::vector<SymMatrix3D> hess; double grad_val, hess_val; bool valid; valid = of->evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, grad_val, grad, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), grad.size() ); valid = of->evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, hess_val, hess_grad, hess, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess_grad.size() ); CPPUNIT_ASSERT_DOUBLES_EQUAL( grad_val, hess_val, 1e-6 ); for (size_t i = 0; i < pd.num_free_vertices(); ++i) { CPPUNIT_ASSERT_VECTORS_EQUAL( grad[i], hess_grad[i], 1e-6 ); } }
void ObjectiveFunctionTests::compare_numerical_gradient( ObjectiveFunction* of ) { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR( err ); std::vector<Vector3D> num_grad, ana_grad; double num_val, ana_val; bool valid; valid = of->evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, ana_val, ana_grad, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), ana_grad.size() ); valid = of->ObjectiveFunction::evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, num_val, num_grad, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(valid); CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), num_grad.size() ); CPPUNIT_ASSERT_DOUBLES_EQUAL( ana_val, num_val, 1e-6 ); for (size_t i = 0; i < pd.num_free_vertices(); ++i) { CPPUNIT_ASSERT_VECTORS_EQUAL( num_grad[i], ana_grad[i], 1e-3 ); } }
/** * Test that lists can be created and items can be added and reference counting works. */ int test001_list( void ) { struct MIDIList * list = MIDIListCreate( TestType ); ASSERT_NOT_EQUAL( list, NULL, "Could not create list!" ); ASSERT_NO_ERROR( MIDIListAdd( list, &_testitem ), "Could not add item." ); ASSERT_EQUAL( _testitem.refs, 2, "Item was not retained." ); ASSERT_NO_ERROR( MIDIListRemove( list, &_testitem ), "Could not add item." ); ASSERT_EQUAL( _testitem.refs, 1, "Item was not released." ); ASSERT_NO_ERROR( MIDIListAdd( list, &_testitem ), "Could not add item." ); ASSERT_EQUAL( _testitem.refs, 2, "Item was not retained." ); MIDIListRelease( list ); ASSERT_EQUAL( _testitem.refs, 1, "Item was not released on destruction." ); return 0; }
void CircleDomainTest::test_position_from_length() { MsqPrintError err(std::cerr); Vector3D origin(0,0,0); Vector3D z(0,0,1); double rad1 = 4.0/3.0; CircleDomain dom1( origin, z, rad1 ); Vector3D xp = Vector3D(1,0,0); Vector3D xn = Vector3D(-1,0,0); Vector3D yp = Vector3D(0,1,0); const double qc = 0.5 * rad1 * M_PI; Vector3D result; dom1.position_from_length( xp.to_array(), qc, result.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_VECTORS_EQUAL( yp*rad1, result, 1e-6 ); dom1.position_from_length( xp.to_array(), 2*qc, result.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_VECTORS_EQUAL( xn*rad1, result, 1e-6 ); dom1.position_from_length( yp.to_array(), -qc, result.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_VECTORS_EQUAL( xp*rad1, result, 1e-6 ); dom1.position_from_length( (xp+z).to_array(), qc, result.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_VECTORS_EQUAL( yp*rad1, result, 1e-6 ); Vector3D center(-1,-2,-1); Vector3D normal(-2,-1,-2); double rad2 = 1.5; CircleDomain dom2( center, normal, rad2 ); Vector3D v(1,0,0); v = v * normal; v *= rad2 / v.length(); v += center; dom2.position_from_length( v.to_array(), 0.0, result.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_VECTORS_EQUAL( v, result, 1e-6 ); }
/** * Test that apply functionality works. */ int test002_list( void ) { int a, b, c; int v = 123; struct MIDIList * list = MIDIListCreate( TestType ); ASSERT_NOT_EQUAL( list, NULL, "Could not create list!" ); ASSERT_NO_ERROR( MIDIListAdd( list, &a ), "Could not add item." ); ASSERT_NO_ERROR( MIDIListAdd( list, &b ), "Could not add item." ); ASSERT_NO_ERROR( MIDIListAdd( list, &c ), "Could not add item." ); ASSERT_NO_ERROR( MIDIListApply( list, &v, &_apply_set ), "Could not apply set function." ); ASSERT_EQUAL( a, v, "Setter did not set list item a." ); ASSERT_EQUAL( b, v, "Setter did not set list item b." ); ASSERT_EQUAL( c, v, "Setter did not set list item c." ); MIDIListRelease( list ); return 0; }
void ObjectiveFunctionTests::test_handles_invalid_qm( OFTestMode test_mode, ObjectiveFunctionTemplate* of ) { OFTestBadQM metric(false); of->set_quality_metric( &metric ); MsqPrintError err(cout); vector<Vector3D> grad; vector<SymMatrix3D> diag; MsqHessian hess; double result; bool valid = false; switch (test_mode) { case EVAL: valid = of->evaluate( ObjectiveFunction::CALCULATE, patch(), result, OF_FREE_EVALS_ONLY, err ); break; case GRAD: valid = of->evaluate_with_gradient( ObjectiveFunction::CALCULATE, patch(), result, grad, err ); break; case DIAG: valid = of->evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, patch(), result, grad, diag, err ); break; case HESS: hess.initialize( patch(), err ); ASSERT_NO_ERROR( err ); valid = of->evaluate_with_Hessian( ObjectiveFunction::CALCULATE, patch(), result, grad, hess, err ); break; default: CPPUNIT_ASSERT(false); } ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(!valid); }
void CircleDomainTest::test_arc_length() { MsqPrintError err(std::cerr); Vector3D origin(0,0,0); Vector3D z(0,0,1); double rad1 = 4.0/3.0; CircleDomain dom1( origin, z, rad1 ); Vector3D xp = Vector3D(1,0,0); Vector3D xn = Vector3D(-1,0,0); Vector3D yp = Vector3D(0,1,0); double len = dom1.arc_length( xp.to_array(), yp.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( rad1 * M_PI * 0.5, len, 1e-6 ); len = dom1.arc_length( xp.to_array(), xn.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( rad1 * M_PI, len, 1e-6 ); len = dom1.arc_length( yp.to_array(), xp.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( -rad1 * M_PI * 0.5, len, 1e-6 ); len = dom1.arc_length( (xp+z).to_array(), yp.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( rad1 * M_PI * 0.5, len, 1e-6 ); len = dom1.arc_length( xp.to_array(), (yp+z).to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( rad1 * M_PI * 0.5, len, 1e-6 ); Vector3D center(-1,-2,-1); Vector3D normal(-2,-1,-2); double rad = 1.5; CircleDomain dom2( center, normal, rad ); Vector3D v(1,0,0); v = v * normal; v *= rad / v.length(); v += center; len = dom2.arc_length( v.to_array(), v.to_array(), err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, len, 1e-6 ); }
/** Test correct handling of QM negate flag */ void ObjectiveFunctionTests::test_negate_flag( OFTestMode test_mode, ObjectiveFunctionTemplate* of ) { const double some_vals[] = { 1, 2, 3, 4, 5, 6, 0.5 }; const unsigned num_vals = sizeof(some_vals)/sizeof(some_vals[0]); OFTestQM metric( some_vals, num_vals ); of->set_quality_metric(&metric); MsqPrintError err(cout); bool rval = false; double value[2]; vector<Vector3D> grad[2]; vector<SymMatrix3D> diag[2]; MsqHessian hess[2]; // Do twice, once w/out negate flag set and then once // with negate flag == -1. ObjectiveFunction::EvalType type = ObjectiveFunction::CALCULATE; for (unsigned i = 0; i < 2; ++i ) { switch (test_mode) { case EVAL: rval = of->evaluate( type, patch(), value[i], false, err ); break; case GRAD: rval = of->evaluate_with_gradient( type, patch(), value[i], grad[i], err ); break; case DIAG: rval = of->evaluate_with_Hessian_diagonal( type, patch(), value[i], grad[i], diag[i], err ); break; case HESS: hess[i].initialize(patch(),err); ASSERT_NO_ERROR( err ); rval = of->evaluate_with_Hessian( type, patch(), value[i], grad[i], hess[i], err ); break; default: CPPUNIT_ASSERT_MESSAGE("Invalid enum value in test code",false); break; } ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT(rval); metric.set_negate_flag(-1); } switch (test_mode) { case HESS: CPPUNIT_ASSERT_EQUAL( hess[0].size(), hess[1].size() ); for (size_t r = 0; r < hess[0].size(); ++r) for (size_t c = r; c < hess[0].size(); ++c) if (hess[0].get_block(r,c)) CPPUNIT_ASSERT_MATRICES_EQUAL( -*hess[0].get_block(r,c), *hess[1].get_block(r,c), 1e-6 ); case DIAG: // NOTE: When case HESS: falls through to here, diag[0] and diag[1] // will be empty, making this a no-op. CPPUNIT_ASSERT_EQUAL( diag[0].size(), diag[1].size() ); for (size_t j = 0; j < diag[0].size(); ++j) CPPUNIT_ASSERT_MATRICES_EQUAL( -diag[0][j], diag[1][j], 1e-6 ); case GRAD: CPPUNIT_ASSERT_EQUAL( grad[0].size(), grad[1].size() ); for (size_t j = 0; j < grad[0].size(); ++j) CPPUNIT_ASSERT_VECTORS_EQUAL( -grad[0][j], grad[1][j], 1e-6 ); default: CPPUNIT_ASSERT_DOUBLES_EQUAL( -value[0], value[1], 1e-6 ); } }
void ObjectiveFunctionTests::compare_numerical_hessian( ObjectiveFunction* of, bool diagonal_only ) { const double delta = 0.0001; MsqPrintError err(std::cout); PatchData pd; create_qm_two_tet_patch( pd, err ); ASSERT_NO_ERROR( err ); CPPUNIT_ASSERT( pd.num_free_vertices() != 0 ); // get analytical Hessian from objective function std::vector<Vector3D> grad; std::vector<SymMatrix3D> diag; MsqHessian hess; hess.initialize( pd, err ); ASSERT_NO_ERROR( err ); double value; bool valid; if (diagonal_only) valid = of->evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, value, grad, diag, err ); else valid = of->evaluate_with_Hessian( ObjectiveFunction::CALCULATE, pd, value, grad, hess, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(valid); // do numerical approximation of each block and compare to analytical value for (size_t i = 0; i < pd.num_free_vertices(); ++i) { const size_t j_end = diagonal_only ? i+1 : pd.num_free_vertices(); for (size_t j = i; j < j_end; ++j) { // do numerical approximation for block corresponding to // coorindates for ith and jth vertices. Matrix3D block; for (int k = 0; k < 3; ++k) { for (int m = 0; m < 3; ++m) { double dk, dm, dkm; Vector3D ik = pd.vertex_by_index(i); Vector3D im = pd.vertex_by_index(j); Vector3D delta_k(0.0); delta_k[k] = delta; pd.move_vertex( delta_k, i, err ); ASSERT_NO_ERROR(err); valid = of->evaluate( ObjectiveFunction::CALCULATE, pd, dk, true, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(valid); Vector3D delta_m(0.0); delta_m[m] = delta; pd.move_vertex( delta_m, j, err ); ASSERT_NO_ERROR(err); valid = of->evaluate( ObjectiveFunction::CALCULATE, pd, dkm, true, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(valid); // be careful here that we do the right thing if i==j pd.set_vertex_coordinates( ik, i, err ); ASSERT_NO_ERROR(err); pd.set_vertex_coordinates( im, j, err ); ASSERT_NO_ERROR(err); pd.move_vertex( delta_m, j, err ); ASSERT_NO_ERROR(err); valid = of->evaluate( ObjectiveFunction::CALCULATE, pd, dm, true, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(valid); pd.set_vertex_coordinates( ik, i, err ); ASSERT_NO_ERROR(err); pd.set_vertex_coordinates( im, j, err ); ASSERT_NO_ERROR(err); block[k][m] = (dkm - dk - dm + value)/(delta*delta); } } // compare to analytical value if (diagonal_only) { CPPUNIT_ASSERT(i == j); // see j_end above CPPUNIT_ASSERT(i < diag.size()); CHECK_EQUAL_MATRICES( block, Matrix3D(diag[i]) ); } else { Matrix3D* m = hess.get_block( i, j ); Matrix3D* mt = hess.get_block( j, i ); if (NULL != m) { CHECK_EQUAL_MATRICES( block, *m ); } if (NULL != mt) { CHECK_EQUAL_MATRICES( transpose(block), *m ); } if (NULL == mt && NULL == m) { CHECK_EQUAL_MATRICES( Matrix3D(0.0), block ); } } } } }
/** * Test that items can be pushed and popped to and from * the MIDIMessageQueue. */ int test001_message_queue( void ) { struct MIDIMessageQueue * queue = MIDIMessageQueueCreate(); struct MIDIMessage * message[3] = { MIDIMessageCreate( MIDI_STATUS_NOTE_ON ), MIDIMessageCreate( MIDI_STATUS_POLYPHONIC_KEY_PRESSURE ), MIDIMessageCreate( MIDI_STATUS_NOTE_OFF ) }; struct MIDIMessage * m; size_t length; MIDIKey key = 60; ASSERT_NOT_EQUAL( queue, NULL, "Could not create message queue." ); ASSERT_NOT_EQUAL( message[0], NULL, "Could not create message 0." ); ASSERT_NOT_EQUAL( message[1], NULL, "Could not create message 1." ); ASSERT_NOT_EQUAL( message[2], NULL, "Could not create message 2." ); ASSERT_NO_ERROR( MIDIMessageSet( message[0], MIDI_KEY, sizeof(MIDIKey), &key ), "Could not set key for message 0." ); ASSERT_NO_ERROR( MIDIMessageSet( message[1], MIDI_KEY, sizeof(MIDIKey), &key ), "Could not set key for message 1." ); ASSERT_NO_ERROR( MIDIMessageSet( message[2], MIDI_KEY, sizeof(MIDIKey), &key ), "Could not set key for message 2." ); ASSERT_NO_ERROR( MIDIMessageQueuePush( queue, message[0] ), "Could not enqueue message 0." ); ASSERT_NO_ERROR( MIDIMessageQueuePush( queue, message[1] ), "Could not enqueue message 1." ); ASSERT_NO_ERROR( MIDIMessageQueuePush( queue, message[2] ), "Could not enqueue message 2." ); ASSERT_NO_ERROR( MIDIMessageQueuePeek( queue, &m ), "Could not peek into queue." ); ASSERT_EQUAL( m, message[0], "Queue returned wrong message." ); ASSERT_NO_ERROR( MIDIMessageQueueGetLength( queue, &length), "Could not determine queue length." ); ASSERT_EQUAL( length, 3, "Message queue returned wrong length." ); ASSERT_NO_ERROR( MIDIMessageQueuePop( queue, &m), "Could not pop message." ); ASSERT_EQUAL( m, message[0], "Queue returned wrong message." ); MIDIMessageRelease( m ); ASSERT_NO_ERROR( MIDIMessageQueuePop( queue, &m), "Could not pop message." ); ASSERT_EQUAL( m, message[1], "Queue returned wrong message." ); MIDIMessageRelease( m ); ASSERT_NO_ERROR( MIDIMessageQueueGetLength( queue, &length), "Could not determine queue length." ); ASSERT_EQUAL( length, 1, "Message queue returned wrong length." ); MIDIMessageRelease( message[0] ); MIDIMessageRelease( message[1] ); MIDIMessageRelease( message[2] ); MIDIMessageQueueRelease( queue ); return 0; }