Example #1
0
static double pmean_of_triangle_corner_hessians( double inner_power,
                                                 double outer_power,
                                                 const double* v,
                                                 const Vector3D* cg,
                                                 const Matrix3D* ch,
                                                 Vector3D* tg,
                                                 Matrix3D* th,
                                                 bool scale )
{
  Matrix3D op;
  double gf[3], hf[3];
  double nm, m = 0;
  double den = scale ? 3.0: 1.0;
  for (unsigned i = 0; i < 3; ++i) {
	  nm = pow(v[i], inner_power);
	  m += nm;

	  gf[i] = inner_power*nm / v[i] / den;
	  hf[i] = (inner_power-1)*gf[i] / v[i];
  }

  nm = m / den;

  tg[0] = gf[0] * cg[0] + gf[1] * cg[5] + gf[2] * cg[7];
  tg[1] = gf[0] * cg[1] + gf[1] * cg[3] + gf[2] * cg[8];
  tg[2] = gf[0] * cg[2] + gf[1] * cg[4] + gf[2] * cg[6];

  th[0] = hf[0]*op.outer_product( cg[0], cg[0] ) + gf[0]*ch[ 0]
        + hf[1]*op.outer_product( cg[5], cg[5] ) + gf[1]*ch[11]
        + hf[2]*op.outer_product( cg[7], cg[7] ) + gf[2]*ch[15];
  th[3] = hf[0]*op.outer_product( cg[1], cg[1] ) + gf[0]*ch[ 3]
        + hf[1]*op.outer_product( cg[3], cg[3] ) + gf[1]*ch[ 6]
        + hf[2]*op.outer_product( cg[8], cg[8] ) + gf[2]*ch[17];
  th[5] = hf[0]*op.outer_product( cg[2], cg[2] ) + gf[0]*ch[ 5]
        + hf[1]*op.outer_product( cg[4], cg[4] ) + gf[1]*ch[ 9]
        + hf[2]*op.outer_product( cg[6], cg[6] ) + gf[2]*ch[12];
  th[1] = hf[0]*op.outer_product( cg[0], cg[1] ) + gf[0]*ch[ 1]
        + hf[1]*op.outer_product( cg[5], cg[3] ) + gf[1]*transpose(ch[ 8])
        + hf[2]*op.outer_product( cg[7], cg[8] ) + gf[2]*ch[16];
  th[2] = hf[0]*op.outer_product( cg[0], cg[2] ) + gf[0]*ch[ 2]
        + hf[1]*op.outer_product( cg[5], cg[4] ) + gf[1]*transpose(ch[10])
        + hf[2]*op.outer_product( cg[7], cg[6] ) + gf[2]*transpose(ch[13]);
  th[4] = hf[0]*op.outer_product( cg[1], cg[2] ) + gf[0]*ch[ 4]
        + hf[1]*op.outer_product( cg[3], cg[4] ) + gf[1]*ch[ 7]
        + hf[2]*op.outer_product( cg[8], cg[6] ) + gf[2]*transpose(ch[14]);
 

  m = pow(nm, outer_power);
  double g = m * outer_power / nm;
  double h = (outer_power - 1.0) * g / nm;
  for (unsigned r = 0; r < 3; ++r) {
    for (unsigned c = r; c < 3; ++c) {
      *th = g * *th + h * op.outer_product( tg[r], tg[c] );
      ++th;
    }
    tg[r] *= g;
  }

  return m;
}
Example #2
0
bool PowerQualityMetric::evaluate_with_Hessian( PatchData& pd,
                                                size_t handle,
                                                double& value,
                                                std::vector<size_t>& indices,
                                                std::vector<Vector3D>& gradient,
                                                std::vector<Matrix3D>& Hessian,
                                                MsqError& err )
{
  indices.clear();
  bool rval = mMetric.evaluate_with_Hessian( pd, handle, value, indices, gradient, Hessian, err );
  const double v = mPower.raise(value);
  const double g = fabs(value) > DBL_EPSILON ? mPower.value() * v / value : 0.0;
  const double h = fabs(value) > DBL_EPSILON ? g * (mPower.value() - 1) / value : 0.0;
  value = v;
  Matrix3D op;
  unsigned idx = 0;
  unsigned n = indices.size();
  for (unsigned r = 0; r < n; ++r) {
    for (unsigned c = r; c < n; ++c) {
      Hessian[idx] *= g;
      op.outer_product( gradient[r], gradient[c] );
      op *= h;
      Hessian[idx] += op;
      ++idx;
    }
    gradient[r] *= g;
  }
  return !MSQ_CHKERR(err) && rval;
}
Example #3
0
    void test_outer_product()
  {
    Matrix3D mat;
    Vector3D vec1(2, 7, 3);
    Vector3D vec2(5, 8, 9);
    mat.outer_product(vec1, vec2);
    Matrix3D correct(" 10    16    18 "
                     " 35    56    63 "
                     " 15    24    27 ");

    CPPUNIT_ASSERT( mat == correct );
  }
Example #4
0
void CompositeOFTest::test_multiply_hess_diagonal()
{
    CompositeOFMultiply OF( &LP1, &LP2 );
    std::vector<SymMatrix3D> hess1, hess2, hess;

    MsqPrintError err(cout);
    PatchData pd;
    create_twelve_hex_patch( pd, err );
    ASSERT_NO_ERROR( err );

    std::vector<Vector3D> grad1, grad2, grad;
    bool rval;
    double value1, value2, value;
    rval = LP1.evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, value1, grad1, hess1, err );
    ASSERT_NO_ERROR(err);
    CPPUNIT_ASSERT(rval);
    rval = LP2.evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, value2, grad2, hess2, err );
    ASSERT_NO_ERROR(err);
    CPPUNIT_ASSERT(rval);
    rval = OF .evaluate_with_Hessian_diagonal( ObjectiveFunction::CALCULATE, pd, value, grad, hess , err );
    ASSERT_NO_ERROR(err);
    CPPUNIT_ASSERT(rval);

    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), grad1.size() );
    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), grad2.size() );
    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), grad .size() );

    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess1.size() );
    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess2.size() );
    CPPUNIT_ASSERT_EQUAL( pd.num_free_vertices(), hess .size() );

    CPPUNIT_ASSERT_DOUBLES_EQUAL( value1 * value2, value, 1e-6 );

    for (size_t i = 0; i < pd.num_free_vertices(); ++i) {
        const Vector3D expected_grad = value2 * grad1[i] + value1 * grad2[i];
        CPPUNIT_ASSERT_VECTORS_EQUAL( expected_grad, grad[i], 1e-6 );

        Matrix3D o;
        o.outer_product( grad1[i], grad2[i] );
        Matrix3D expect = o + transpose(o);
        expect += value2 * hess1[i];
        expect += value1 * hess2[i];
        CPPUNIT_ASSERT_MATRICES_EQUAL( expect, Matrix3D(hess[i]), 1e-6 );
    }
}
Example #5
0
void PMeanPMetricTest::test_hessian()
{
  MsqError err;
  FauxMetric m;
  ElementPMeanP m1( 1.0, &m );
  ElementPMeanP m2( 2.0, &m );
  
    // get vertices for later
  std::vector<size_t> vertices;
  pd.element_by_index(0).get_vertex_indices( vertices );
  
    // evaluate gradient
  double v1, v2, v3, v4;
  std::vector<size_t> indices1, indices2, indices3, indices4, tmpi;
  std::vector<Vector3D> grad1, grad2, grad3, grad4;
  std::vector<Matrix3D> hess3, hess4;
  m1.evaluate_with_gradient( pd, 0, v1, indices1, grad1, err );
  CPPUNIT_ASSERT(!err);
  m2.evaluate_with_gradient( pd, 0, v2, indices2, grad2, err );
  CPPUNIT_ASSERT(!err);
  
    // evaluate with Hessian
  m1.evaluate_with_Hessian( pd, 0, v3, indices3, grad3, hess3, err );
  CPPUNIT_ASSERT(!err);
  m2.evaluate_with_Hessian( pd, 0, v4, indices4, grad4, hess4, err );
  CPPUNIT_ASSERT(!err);
  
    // compare value and indices to eval w/out gradient
  CPPUNIT_ASSERT_DOUBLES_EQUAL( v1, v3, 1e-6 );
  CPPUNIT_ASSERT_DOUBLES_EQUAL( v2, v4, 1e-6 );
    // It isn't a requirement that the index order remain the same
    // for both eval_with_grad and eval_with_Hess, but assuming it 
    // does simplifies a lot of stuff in this test.  Check that the 
    // assumption remains valid.
  CPPUNIT_ASSERT( indices3 == indices1 );
  CPPUNIT_ASSERT( indices4 == indices2 );
    // It isn't a requirement that the index order remain the same
    // for any value of P, but assuming it does simplifies a lot
    // of stuff in this test, so check that the assumption is valid.
  CPPUNIT_ASSERT( indices1 == indices2 ); 
  
    // check that gradient values match
  for (size_t i = 0; i < indices1.size(); ++i) {
    CPPUNIT_ASSERT_VECTORS_EQUAL( grad1[i], grad3[i], 1e-5 );
    CPPUNIT_ASSERT_VECTORS_EQUAL( grad2[i], grad4[i], 1e-5 );
  }
  
    // setup evaluation of underying metric
  std::vector<size_t> handles;
  m.get_element_evaluations( pd, 0, handles, err );
  CPPUNIT_ASSERT(!err);
  
    // calculate expected Hessians
  std::vector<Vector3D> g;
  std::vector<Matrix3D> expected1, expected2, h;
  std::vector<Matrix3D>::iterator h_iter;
  const unsigned N = vertices.size();
  expected1.resize( N*(N+1)/2, Matrix3D(0,0,0,0,0,0,0,0,0) );
  expected2 = expected1;
  Matrix3D outer;
  for (unsigned i = 0; i < handles.size(); ++i) {
    double v;
    m.evaluate_with_Hessian( pd, handles[i], v, tmpi, g, h, err );
    CPPUNIT_ASSERT(!err);
    h_iter = h.begin();
    for (unsigned r = 0; r < tmpi.size(); ++r) {
      unsigned R = index_of( vertices, tmpi[r] );
      CPPUNIT_ASSERT( R < N );
      for (unsigned c = r; c < tmpi.size(); ++c ,++h_iter) {
        unsigned C = index_of( vertices, tmpi[c] );
        CPPUNIT_ASSERT( C < N );
        if (R <= C) {
          unsigned idx = N*R - R*(R+1)/2 + C;
          expected1[idx] += 1.0 / handles.size() * *h_iter;
          expected2[idx] += 2.0 * v / handles.size() * *h_iter;
          outer.outer_product( g[r], g[c] );
          expected2[idx] += 2.0 / handles.size() * outer;
        }
        else {
          unsigned idx = N*C - C*(C+1)/2 + R;
          expected1[idx] += 1.0 / handles.size() * transpose(*h_iter);
          expected2[idx] += 2.0 * v / handles.size() * transpose(*h_iter);
          outer.outer_product( g[c], g[r] );
          expected2[idx] += 2.0 / handles.size() * outer;
        }
      }
    }
  }
  
    // compare Hessians
  unsigned H_idx = 0;
  for (unsigned R = 0; R < vertices.size(); ++R) {
    if (vertices[R] >= pd.num_free_vertices())
      continue;
    unsigned r = index_of( indices3, vertices[R] );
    CPPUNIT_ASSERT(r < indices3.size() );
    for (unsigned C = R; C < vertices.size(); ++C, ++H_idx) {
      if (vertices[C] >= pd.num_free_vertices())
        continue;
      unsigned c = index_of( indices3, vertices[C] );
      CPPUNIT_ASSERT( c < indices3.size() );
      if (r <= c) {
        unsigned idx = indices3.size()*r - r*(r+1)/2 + c;
        CPPUNIT_ASSERT_MATRICES_EQUAL( expected1[H_idx], hess3[idx], 1e-5 );
        CPPUNIT_ASSERT_MATRICES_EQUAL( expected2[H_idx], hess4[idx], 1e-5 );
      }
      else {
        unsigned idx = indices3.size()*c - c*(c+1)/2 + r;
        CPPUNIT_ASSERT_MATRICES_EQUAL( transpose(expected1[H_idx]), hess3[idx], 1e-5 );
        CPPUNIT_ASSERT_MATRICES_EQUAL( transpose(expected2[H_idx]), hess4[idx], 1e-5 );
      }
    }
  }
}
bool MultiplyQualityMetric::evaluate_with_Hessian( PatchData& pd,
                                              size_t handle,
                                              double& value,
                                              std::vector<size_t>& indices,
                                              std::vector<Vector3D>& gradient,
                                              std::vector<Matrix3D>& Hessian,
                                              MsqError& err )
{
  std::vector<size_t>::iterator i;
  size_t j, r, c, n, h;
  double val1, val2;
  bool rval1, rval2;
  rval1 = metric1.evaluate_with_Hessian( pd, handle, val1, indices1, grad1, Hess1, err ); MSQ_ERRZERO(err);
  rval2 = metric2.evaluate_with_Hessian( pd, handle, val2, indices2, grad2, Hess2, err ); MSQ_ERRZERO(err);
    // merge index lists
  indices.resize( indices1.size() + indices2.size() );
  i = std::copy( indices1.begin(), indices1.end(), indices.begin() );
  std::copy( indices2.begin(), indices2.end(), i );
  std::sort( indices.begin(), indices.end() );
  indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
    // calculate grads and convert index lists to indices into output list
  gradient.clear();
  gradient.resize( indices.size(), Vector3D(0.0) );
  for (j = 0; j < indices1.size(); ++j)
  {
    i = std::lower_bound( indices.begin(), indices.end(), indices1[j] );
    indices1[j] = i - indices.begin();
    gradient[indices1[j]] += val2 * grad1[j];
  }
  for (j = 0; j < indices2.size(); ++j)
  {
    i = std::lower_bound( indices.begin(), indices.end(), indices2[j] );
    indices2[j] = i - indices.begin();
    gradient[indices2[j]] += val1 * grad2[j];
  }
    // allocate space for hessians, and zero it
  const size_t N = indices.size();
  Hessian.clear();
  Hessian.resize( N * (N+1) / 2, Matrix3D(0.0) );
    // add hessian terms from first metric
  n = indices1.size();
  h = 0; 
  for (r = 0; r < n; ++r) 
  {
    const size_t nr = indices1[r];
    for (c = r; c < n; ++c)
    {
      const size_t nc = indices1[c];
      Hess1[h] *= val2;
      if (nr <= nc)
        Hessian[N*nr - nr*(nr+1)/2 + nc] += Hess1[h];
      else
        Hessian[N*nc - nc*(nc+1)/2 + nr].plus_transpose_equal( Hess1[h] );
      ++h;
    }
  }
    // add hessian terms from second metric
  n = indices2.size();
  h = 0; 
  for (r = 0; r < n; ++r) 
  {
    const size_t nr = indices2[r];
    for (c = r; c < n; ++c)
    {
      const size_t nc = indices2[c];
      Hess2[h] *= val1;
      if (nr <= nc)
        Hessian[N*nr - nr*(nr+1)/2 + nc] += Hess2[h];
      else
        Hessian[N*nc - nc*(nc+1)/2 + nr].plus_transpose_equal( Hess2[h] );
      ++h;
    }
  }
    // add gradient outer products
  n = indices1.size();
  size_t m = indices2.size();
  Matrix3D outer;
  for (r = 0; r < n; ++r)
  {
    const size_t nr = indices1[r];
    for (c = 0; c < m; ++c)
    {
      const size_t nc = indices2[c];
      outer.outer_product( grad1[r], grad2[c] );
      if (nr == nc) 
        Hessian[N*nr - nr*(nr+1)/2 + nc] += outer.plus_transpose_equal(outer);
      else if (nr < nc)
        Hessian[N*nr - nr*(nr+1)/2 + nc] += outer;
      else
        Hessian[N*nc - nc*(nc+1)/2 + nr].plus_transpose_equal(outer);
    }
  }
  
  value = val1 * val2;
  return rval1 && rval2;
}
Example #7
0
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;
}