Ejemplo n.º 1
0
/** Fit GSL function wrapper
* @param x :: Input function parameters
* @param params :: Input data
* @param f :: Output function values = (y_cal-y_data)/sigma for each data point
* @return A GSL status information
*/
int gsl_f(const gsl_vector *x, void *params, gsl_vector *f) {

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

  // 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();

  auto values = boost::dynamic_pointer_cast<API::FunctionValues>(
      p->costFunction->getValues());
  if (!values) {
    throw std::invalid_argument("FunctionValues expected");
  }
  p->function->function(*p->costFunction->getDomain(), *values);

  // Add penalty
  double penalty = 0.;
  for (size_t i = 0; i < p->function->nParams(); ++i) {
    API::IConstraint *c = p->function->getConstraint(i);
    if (c) {
      penalty += c->checkDeriv();
    }
  }

  size_t n = values->size() - 1;
  // add penalty to first and last point and every 10th point in between
  if (penalty != 0.0) {
    values->addToCalculated(0, penalty);
    values->addToCalculated(n, penalty);

    for (size_t i = 9; i < n; i += 10) {
      values->addToCalculated(i, penalty);
    }
  }

  // function() return calculated data values. Need to convert this values into
  // calculated-observed devided by error values used by GSL

  for (size_t i = 0; i < p->n; i++) {
    f->data[i] = (values->getCalculated(i) - values->getFitData(i)) *
                 values->getFitWeight(i);
    // std::cerr << values.getCalculated(i) << ' ' << values.getFitData(i) << '
    // ' << values.getFitWeight(i) << std::endl;
  }

  return GSL_SUCCESS;
}
Ejemplo n.º 2
0
/** Set fitting function, domain it will operate on, and container for values.
 * @param function :: The fitting function.
 * @param domain :: The domain for the function.
 * @param values :: The FunctionValues object which receives the calculated
 * values and
 *  also contains the data to fit to and the fitting weights (reciprocal
 * errors).
 */
void CostFuncFitting::setFittingFunction(API::IFunction_sptr function,
                                         API::FunctionDomain_sptr domain,
                                         API::FunctionValues_sptr values) {
  if (domain->size() != values->size()) {
    throw std::runtime_error(
        "Function domain and values objects are incompatible.");
  }
  m_function = function;
  m_domain = domain;
  m_values = values;
  m_indexMap.clear();
  for (size_t i = 0; i < m_function->nParams(); ++i) {
    if (m_function->isActive(i)) {
      m_indexMap.push_back(i);
    }
    API::IConstraint *c = m_function->getConstraint(i);
    if (c) {
      c->setParamToSatisfyConstraint();
    }
  }
}
Ejemplo n.º 3
0
/** 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;
}
Ejemplo n.º 4
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;
}