コード例 #1
0
ファイル: GSLFunctions.cpp プロジェクト: spaceyatom/mantid
/** Fit GSL derivative function wrapper
* @param x :: Input function arguments
* @param params :: Input data
* @param J :: Output derivatives
* @return A GSL status information
*/
int gsl_df(const gsl_vector *x, void *params, gsl_matrix *J) {

  struct GSL_FitData *p = (struct GSL_FitData *)params;

  p->J.setJ(J);

  // update function parameters
  if (x->data) {
    size_t ia = 0;
    for (size_t i = 0; i < p->function->nParams(); ++i) {
      if (p->function->isActive(i)) {
        p->function->setActiveParameter(i, x->data[ia]);
        ++ia;
      }
    }
  }
  p->function->applyTies();

  // calculate the Jacobian
  p->function->functionDeriv(*p->costFunction->getDomain(), p->J);

  // p->function->addPenaltyDeriv(&p->J);
  // add penalty
  size_t n = p->costFunction->getDomain()->size() - 1;
  size_t ia = 0;
  for (size_t i = 0; i < p->function->nParams(); ++i) {
    if (!p->function->isActive(i))
      continue;
    API::IConstraint *c = p->function->getConstraint(i);
    if (c) {
      double penalty = c->checkDeriv2();
      if (penalty != 0.0) {
        double deriv = p->J.get(0, ia);
        p->J.set(0, ia, deriv + penalty);
        deriv = p->J.get(n, ia);
        p->J.set(n, ia, deriv + penalty);

        for (size_t j = 9; j < n; j += 10) {
          deriv = p->J.get(j, ia);
          p->J.set(j, ia, deriv + penalty);
        }
      }
    } // if (c)
    ++ia;
  }

  // functionDeriv() return derivatives of calculated data values. Need to
  // convert this values into
  // derivatives of calculated-observed divided by error values used by GSL
  auto values = boost::dynamic_pointer_cast<API::FunctionValues>(
      p->costFunction->getValues());
  if (!values) {
    throw std::invalid_argument("FunctionValues expected");
  }
  for (size_t iY = 0; iY < p->n; iY++)
    for (size_t iP = 0; iP < p->p; iP++) {
      J->data[iY * p->p + iP] *= values->getFitWeight(iY);
      // std::cerr << iY << ' ' << iP << ' ' << J->data[iY*p->p + iP] <<
      // std::endl;
    }

  return GSL_SUCCESS;
}
コード例 #2
0
/** Calculate the value and the first and second derivatives of the cost function
 *  @param evalFunction :: If false cost function isn't evaluated and returned value (0.0) should be ignored.
 *    It is for efficiency reasons.
 *  @param evalDeriv :: flag for evaluation of the first derivatives
 *  @param evalHessian :: flag for evaluation of the second derivatives
 */
double CostFuncLeastSquares::valDerivHessian(bool evalFunction, bool evalDeriv, bool evalHessian) const
{
  if (m_pushed || !evalDeriv)
  {
    return val();
  }

  if (!m_dirtyVal && !m_dirtyDeriv && !m_dirtyHessian) return m_value;
  if (m_dirtyVal) evalFunction = true;

  checkValidity();

  if (evalFunction)
  {
    m_value = 0.0;
  }
  if (evalDeriv)
  {
    m_der.resize(nParams());
    m_der.zero();
  }
  if (evalHessian)
  {
    m_hessian.resize(nParams(),nParams());
    m_hessian.zero();
  }

  auto seqDomain = boost::dynamic_pointer_cast<SeqDomain>(m_domain);

  if (seqDomain)
  {
    seqDomain->leastSquaresValDerivHessian(*this,evalFunction,evalDeriv,evalHessian);
  }
  else
  {
    auto simpleValues = boost::dynamic_pointer_cast<API::FunctionValues>(m_values);
    if (!simpleValues)
    {
      throw std::runtime_error("LeastSquares: unsupported IFunctionValues.");
    }
    addValDerivHessian(m_function,m_domain,simpleValues,evalFunction,evalDeriv,evalHessian);
  }

  // Add constraints penalty
  size_t np = m_function->nParams();
  if (evalFunction)
  {
    for(size_t i = 0; i < np; ++i)
    {
      API::IConstraint* c = m_function->getConstraint(i);
      if (c)
      {
        m_value += c->check();
      }
    }
    m_dirtyVal = false;
  }

  if (evalDeriv)
  {
    size_t i = 0;
    for(size_t ip = 0; ip < np; ++ip)
    {
      if ( !m_function->isActive(ip) ) continue;
      API::IConstraint* c = m_function->getConstraint(ip);
      if (c)
      {
        double d =  m_der.get(i) + c->checkDeriv();
        m_der.set(i,d);
      }
      ++i;
    }
    m_dirtyDeriv = false;
  }

  if (evalDeriv)
  {
    size_t i = 0;
    for(size_t ip = 0; ip < np; ++ip)
    {
      if ( !m_function->isActive(ip) ) continue;
      API::IConstraint* c = m_function->getConstraint(ip);
      if (c)
      {
        double d =  m_hessian.get(i,i) + c->checkDeriv2();
        m_hessian.set(i,i,d);
      }
      ++i;
    }
    // clear the dirty flag if hessian was actually calculated
    m_dirtyHessian = m_hessian.isEmpty();
  }

  return m_value;
}