int ObjectiveFunctionTemplate::min_patch_layers() const { if (!get_quality_metric()) return 0; else if (get_quality_metric()->get_metric_type() == QualityMetric::VERTEX_BASED) return 2; else return 1; }
bool LInfTemplate::evaluate( EvalType type, PatchData& pd, double& value_out, bool free, MsqError& err ) { if (type != ObjectiveFunction::CALCULATE) { MSQ_SETERR(err)( "LInfTemplate does not support block coodinate descent algoritms", MsqError::INVALID_STATE ); return false; } QualityMetric* qm = get_quality_metric(); qm->get_evaluations( pd, qmHandles, free, err ); MSQ_ERRFALSE(err); const double negate = qm->get_negate_flag(); // calculate OF value for just the patch std::vector<size_t>::const_iterator i; double value; value_out = -HUGE_VAL; for (i = qmHandles.begin(); i != qmHandles.end(); ++i) { bool result = qm->evaluate( pd, *i, value, err ); if (MSQ_CHKERR(err) || !result) return false; value = negate * fabs(value); if (value > value_out) value_out = value; } return true; }
bool ElementMaxQM::evaluate( PatchData& pd, size_t handle, double& value, MsqError& err ) { ElemSampleQM* qm = get_quality_metric(); mHandles.clear(); qm->get_element_evaluations( pd, handle, mHandles, err ); MSQ_ERRFALSE(err); bool valid = true; double tmpval; bool tmpvalid; value = -1.e+100; // initialize max computation for (std::vector<size_t>::iterator h = mHandles.begin(); h != mHandles.end(); ++h) { tmpvalid = qm->evaluate( pd, *h, tmpval, err ); // MSQ_ERRZERO(err); if (!tmpvalid) { value = +1.e+100; return false; // if any handle within the element makes tmpvalid false, then valid is false, no matter what the other handles say } else if (tmpval > value) value = tmpval; } return valid; }
bool PMeanPTemplate::evaluate( EvalType type, PatchData& pd, double& value_out, bool free, MsqError& err ) { QualityMetric* qm = get_quality_metric(); if (type == ObjectiveFunction::ACCUMULATE) qm->get_single_pass( pd, qmHandles, free, err ); else qm->get_evaluations( pd, qmHandles, free, err ); MSQ_ERRFALSE(err); // calculate OF value for just the patch std::vector<size_t>::const_iterator i; double value, working_sum = 0.0; for (i = qmHandles.begin(); i != qmHandles.end(); ++i) { bool result = qm->evaluate( pd, *i, value, err ); if (MSQ_CHKERR(err) || !result) return false; working_sum += mPower.raise( value ); } // get overall OF value, update member data, etc. size_t global_count; value_out = qm->get_negate_flag() * get_value( working_sum, qmHandles.size(), type, global_count ); return true; }
bool ElementAvgQM::evaluate( PatchData& pd, size_t handle, double& value, MsqError& err ) { ElemSampleQM* qm = get_quality_metric(); mHandles.clear(); qm->get_element_evaluations( pd, handle, mHandles, err ); MSQ_ERRFALSE(err); bool valid = true; double tmpval; double accumulate = 0.0; int num_values = 0; bool tmpvalid; value = -std::numeric_limits<double>::infinity(); for (std::vector<size_t>::iterator h = mHandles.begin(); h != mHandles.end(); ++h) { tmpvalid = qm->evaluate( pd, *h, tmpval, err ); MSQ_ERRZERO(err); if (!tmpvalid) { valid = false; break; } else { accumulate += tmpval; num_values++; } } if (valid) value = accumulate/num_values; return valid; }
bool ElementPMeanP::evaluate( PatchData& pd, size_t handle, double& value, MsqError& err ) { ElemSampleQM* qm = get_quality_metric(); mHandles.clear(); qm->get_element_evaluations( pd, handle, mHandles, err ); MSQ_ERRFALSE(err); bool result = average( pd, qm, mHandles, value, err ); return !MSQ_CHKERR(err) && result; }
bool ElementPMeanP::evaluate_with_gradient( PatchData& pd, size_t handle, double& value, std::vector<size_t>& indices, std::vector<Vector3D>& gradient, MsqError& err ) { ElemSampleQM* qm = get_quality_metric(); mHandles.clear(); qm->get_element_evaluations( pd, handle, mHandles, err ); MSQ_ERRFALSE(err); bool result = average_with_gradient( pd, qm, mHandles, value, indices, gradient, err ); return !MSQ_CHKERR(err) && result; }
bool PMeanPTemplate::evaluate_with_gradient( EvalType type, PatchData& pd, double& value_out, std::vector<Vector3D>& grad_out, MsqError& err ) { QualityMetric* qm = get_quality_metric(); qm->get_evaluations( pd, qmHandles, OF_FREE_EVALS_ONLY, err ); MSQ_ERRFALSE(err); // zero gradient grad_out.clear(); grad_out.resize( pd.num_free_vertices(), Vector3D(0.0,0.0,0.0) ); // calculate OF value and gradient for just the patch std::vector<size_t>::const_iterator i; double value, working_sum = 0.0; const double f = qm->get_negate_flag() * mPower.value(); for (i = qmHandles.begin(); i != qmHandles.end(); ++i) { bool result = qm->evaluate_with_gradient( pd, *i, value, mIndices, mGradient, err ); if (MSQ_CHKERR(err) || !result) return false; if (fabs(value) < DBL_EPSILON) continue; const double r1 = mPowerMinus1.raise( value ); const double qmp = r1 * value; working_sum += qmp; value = f * r1; for (size_t j = 0; j < mIndices.size(); ++j) { mGradient[j] *= value; grad_out[mIndices[j]] += mGradient[j]; } } // get overall OF value, update member data, etc. size_t global_count; value_out = qm->get_negate_flag() * get_value( working_sum, qmHandles.size(), type, global_count ); const double inv_n = 1.0 / global_count; std::vector<Vector3D>::iterator g; for (g = grad_out.begin(); g != grad_out.end(); ++g) *g *= inv_n; return true; }
bool ObjectiveFunctionTemplate::initialize_block_coordinate_descent( Mesh* mesh, MeshDomain* domain, const Settings* settings, PatchSet* , MsqError& err ) { std::auto_ptr<PatchSet> patch_set; switch (get_quality_metric()->get_metric_type()) { case QualityMetric::VERTEX_BASED: patch_set = std::auto_ptr<PatchSet>(new VertexPatches( 1, false )); break; case QualityMetric::ELEMENT_BASED: patch_set = std::auto_ptr<PatchSet>(new ElementPatches); break; default: MSQ_SETERR(err)("Cannot initialize for BCD for unknown metric type", MsqError::INVALID_STATE); return false; } clear(); patch_set->set_mesh( mesh ); PatchIterator patches( patch_set.get() ); PatchData pd; pd.set_mesh( mesh ); pd.set_domain( domain ); if (settings) pd.attach_settings( settings ); bool result = true; while (patches.get_next_patch( pd, err ) && !MSQ_CHKERR(err)) { double value; bool b = evaluate( ObjectiveFunction::ACCUMULATE, pd, value, false, err ); MSQ_ERRZERO(err); result = result && b; } return result; }
ObjectiveFunction* LInfTemplate::clone() const { return new LInfTemplate(get_quality_metric()); }
int ElementMaxQM::get_negate_flag() const { return get_quality_metric()->get_negate_flag(); }
bool PMeanPTemplate::evaluate_with_Hessian( EvalType type, PatchData& pd, double& value_out, std::vector<Vector3D>& grad_out, MsqHessian& Hessian_out, MsqError& err ) { QualityMetric* qm = get_quality_metric(); qm->get_evaluations( pd, qmHandles, OF_FREE_EVALS_ONLY, err ); MSQ_ERRFALSE(err); // zero gradient and hessian grad_out.clear(); grad_out.resize( pd.num_free_vertices(), 0.0 ); Hessian_out.zero_out(); // calculate OF value and gradient for just the patch std::vector<size_t>::const_iterator i; size_t j, k, n; double value, working_sum = 0.0; const double f1 = qm->get_negate_flag() * mPower.value(); const double f2 = f1 * (mPower.value() - 1); Matrix3D m; for (i = qmHandles.begin(); i != qmHandles.end(); ++i) { bool result = qm->evaluate_with_Hessian( pd, *i, value, mIndices, mGradient, mHessian, err ); if (MSQ_CHKERR(err) || !result) return false; if (fabs(value) < DBL_EPSILON) continue; const size_t nfree = mIndices.size(); n = 0; if (mPower.value() == 1.0) { working_sum += mPower.raise( value ); for (j = 0; j < nfree; ++j) { mGradient[j] *= f1; grad_out[mIndices[j]] += mGradient[j]; for (k = j; k < nfree; ++k) { mHessian[n] *= f1; Hessian_out.add( mIndices[j], mIndices[k], mHessian[n], err ); MSQ_ERRFALSE(err); ++n; } } } else { const double r2 = mPowerMinus2.raise( value ); const double r1 = r2 * value; working_sum += r1 * value; const double hf = f2 * r2; const double gf = f1 * r1; for (j = 0; j < nfree; ++j) { for (k = j; k < nfree; ++k) { m.outer_product( mGradient[j], mGradient[k] ); m *= hf; mHessian[n] *= gf; m += mHessian[n]; Hessian_out.add( mIndices[j], mIndices[k], m, err ); MSQ_ERRFALSE(err); ++n; } } for (j = 0; j < nfree; ++j) { mGradient[j] *= gf; grad_out[mIndices[j]] += mGradient[j]; } } } // get overall OF value, update member data, etc. size_t global_count; value_out = qm->get_negate_flag() * get_value( working_sum, qmHandles.size(), type, global_count ); const double inv_n = 1.0 / global_count; std::vector<Vector3D>::iterator g; for (g = grad_out.begin(); g != grad_out.end(); ++g) *g *= inv_n; Hessian_out.scale( inv_n ); return true; }
bool PMeanPTemplate::evaluate_with_Hessian_diagonal( EvalType type, PatchData& pd, double& value_out, std::vector<Vector3D>& grad_out, std::vector<SymMatrix3D>& hess_diag_out, MsqError& err ) { QualityMetric* qm = get_quality_metric(); qm->get_evaluations( pd, qmHandles, OF_FREE_EVALS_ONLY, err ); MSQ_ERRFALSE(err); // zero gradient and hessian const size_t s = pd.num_free_vertices(); grad_out.clear(); grad_out.resize( s, 0.0 ); hess_diag_out.clear(); hess_diag_out.resize( s, 0.0 ); // calculate OF value and gradient for just the patch std::vector<size_t>::const_iterator i; size_t j; double value, working_sum = 0.0; const double f1 = qm->get_negate_flag() * mPower.value(); const double f2 = f1 * (mPower.value() - 1); for (i = qmHandles.begin(); i != qmHandles.end(); ++i) { bool result = qm->evaluate_with_Hessian_diagonal( pd, *i, value, mIndices, mGradient, mDiag, err ); if (MSQ_CHKERR(err) || !result) return false; if (fabs(value) < DBL_EPSILON) continue; const size_t nfree = mIndices.size(); if (mPower.value() == 1.0) { working_sum += mPower.raise( value ); for (j = 0; j < nfree; ++j) { const size_t idx = mIndices[j]; hess_diag_out[idx] += f1 * mDiag[j]; mGradient[j] *= f1; grad_out[idx] += mGradient[j]; } } else { const double r2 = mPowerMinus2.raise( value ); const double r1 = r2 * value; working_sum += r1 * value; const double hf = f2 * r2; const double gf = f1 * r1; for (j = 0; j < nfree; ++j) { const size_t idx = mIndices[j]; hess_diag_out[idx] += hf * outer( mGradient[j] ); hess_diag_out[idx] += gf * mDiag[j]; mGradient[j] *= gf; grad_out[idx] += mGradient[j]; } } } // get overall OF value, update member data, etc. size_t global_count; value_out = qm->get_negate_flag() * get_value( working_sum, qmHandles.size(), type, global_count ); const double inv_n = 1.0 / global_count; for (j = 0; j < s; ++j) { grad_out[j] *= inv_n; hess_diag_out[j] *= inv_n; } return true; }