Skip to content
Snippets Groups Projects
IFunction.cpp 50 KiB
Newer Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
//     NScD Oak Ridge National Laboratory, European Spallation Source
//     & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAPI/IFunction.h"
#include "MantidAPI/Axis.h"
#include "MantidAPI/ConstraintFactory.h"
#include "MantidAPI/Expression.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/IConstraint.h"
#include "MantidAPI/IFunctionWithLocation.h"
#include "MantidAPI/Jacobian.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/MultiDomainFunction.h"
#include "MantidAPI/ParameterTie.h"
#include "MantidAPI/SpectrumInfo.h"
#include "MantidGeometry/Instrument/Component.h"
#include "MantidGeometry/Instrument/DetectorGroup.h"
#include "MantidGeometry/Instrument/DetectorInfo.h"
#include "MantidGeometry/Instrument/FitParameter.h"
#include "MantidGeometry/Instrument/ParameterMap.h"
#include "MantidGeometry/muParser_Silent.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/IPropertyManager.h"
#include "MantidKernel/MultiThreaded.h"
#include "MantidKernel/ProgressBase.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/UnitFactory.h"
#include <boost/lexical_cast.hpp>

#include "MantidKernel/StringTokenizer.h"
#include <algorithm>
#include <limits>
namespace Mantid {
namespace API {
using namespace Geometry;
namespace {
/// static logger
Kernel::Logger g_log("IFunction");

/// Struct that helps sort ties in correct order of application.
struct TieNode {
  // Index of the tied parameter
  size_t left;
  // Indices of parameters on the right-hand-side of the expression
  std::vector<size_t> right;
  // This tie must be applied before the other if the RHS of the other
  // contains this (left) parameter.
  bool operator<(TieNode const &other) const {
    return std::find(other.right.begin(), other.right.end(), left) !=
           other.right.end();
  }
};
} // namespace
Sam Jenkins's avatar
Sam Jenkins committed
IFunction::~IFunction() { m_attrs.clear(); }
/**
 * Virtual copy constructor
 */
boost::shared_ptr<IFunction> IFunction::clone() const {
  auto clonedFunction =
      FunctionFactory::Instance().createInitialized(this->asString());
  for (size_t i = 0; i < this->nParams(); i++) {
    double error = this->getError(i);
    clonedFunction->setError(i, error);
  }
  return clonedFunction;
 * @param reporter :: A pointer to a progress reporter that can be called during
 * function evaluation
void IFunction::setProgressReporter(
    boost::shared_ptr<Kernel::ProgressBase> reporter) {
  m_progReporter = reporter;
  m_progReporter->setNotifyStep(0.01);
}

/**
 * If a reporter object is set, reports progress with an optional message
 * @param msg :: A message to display (default = "")
 */
void IFunction::reportProgress(const std::string &msg) const {
  if (m_progReporter) {
Roman Tolchenov's avatar
Roman Tolchenov committed
    const_cast<Kernel::ProgressBase *>(m_progReporter.get())->report(msg);
 * @returns true if a progress reporter is set & evalaution has been requested
 *to stop
bool IFunction::cancellationRequestReceived() const {
  if (m_progReporter)
    return m_progReporter->hasCancellationBeenRequested();
  else
    return false;
/** Base class implementation calculates the derivatives numerically.
 * @param domain :: The domain of the function
 * @param jacobian :: A Jacobian matrix. It is expected to have dimensions of
 * domain.size() by nParams().
void IFunction::functionDeriv(const FunctionDomain &domain,
                              Jacobian &jacobian) {
  calNumericalDeriv(domain, jacobian);
/** Check if an active parameter i is actually active
 * @param i :: Index of a parameter.
 */
bool IFunction::isActive(size_t i) const {
  return getParameterStatus(i) == Active;
}

/**
 * Query if the parameter is fixed
 * @param i :: The index of a declared parameter
 * @return true if parameter i is fixed
 */
bool IFunction::isFixed(size_t i) const {
  auto status = getParameterStatus(i);
  return status == Fixed || status == FixedByDefault;
/// Check if a parameter i is fixed by default (not by user).
/// @param i :: The index of a parameter
/// @return true if parameter i is fixed by default
bool IFunction::isFixedByDefault(size_t i) const {
  return getParameterStatus(i) == FixedByDefault;
}

/// This method doesn't create a tie
/// @param i :: A declared parameter index to be fixed
/// @param isDefault :: If true fix it by default
///
void IFunction::fix(size_t i, bool isDefault) {
  auto status = getParameterStatus(i);
  if (status == Tied) {
    throw std::runtime_error("Cannot fix parameter " + std::to_string(i) +
                             " (" + parameterName(i) + "): it has a tie.");
  }
  if (isDefault) {
    setParameterStatus(i, FixedByDefault);
  } else {
    setParameterStatus(i, Fixed);
  }
}

/** Makes a parameter active again. It doesn't change the parameter's tie.
 * @param i :: A declared parameter index to be restored to active
 */
void IFunction::unfix(size_t i) {
  auto status = getParameterStatus(i);
  if (status == Tied) {
    throw std::runtime_error("Cannot unfix parameter " + std::to_string(i) +
                             " (" + parameterName(i) + "): it has a tie.");
  }
  setParameterStatus(i, Active);
/**
 * Ties a parameter to other parameters
 * @param parName :: The name of the parameter to tie.
 * @param expr :: A math expression
 * @param isDefault :: Flag to mark as default the value of an object associated
 * with this reference: a tie or a constraint.
 * @return newly ties parameters
 */
void IFunction::tie(const std::string &parName, const std::string &expr,
                    bool isDefault) {
  auto ti = std::make_unique<ParameterTie>(this, parName, expr, isDefault);
  if (!isDefault && ti->isConstant()) {
    setParameter(parName, ti->eval());
    fix(getParameterIndex(*ti));
/**
 * Add ties to the function.
 * @param ties :: Comma-separated list of name=value pairs where name is a
 *parameter name and value
 *  is a math expression tying the parameter to other parameters or a constant.
 * @param isDefault :: Flag to mark as default the value of an object associated
 *with this reference: a tie or a constraint.
void IFunction::addTies(const std::string &ties, bool isDefault) {
  Expression list;
  list.parse(ties);
  list.toList();
  for (const auto &t : list) {
    if (t.name() == "=" && t.size() >= 2) {
      size_t n = t.size() - 1;
      const std::string value = t[n].str();
      for (size_t i = n; i != 0;) {
        this->tie(t[i].name(), value, isDefault);
/** Removes the tie off a parameter. The parameter becomes active
 * This method can be used when constructing and editing the IFunction in a GUI
 * @param parName :: The name of the parameter which ties will be removed.
 */
void IFunction::removeTie(const std::string &parName) {
  size_t i = parameterIndex(parName);
  this->removeTie(i);
}

/// Write all parameter ties owned by this function to a string
/// @return A tie string for the parameter.
std::string IFunction::writeTies() const {
  std::ostringstream tieStream;
  for (auto &tie : m_ties) {
    if (tie->isDefault())
      continue;
    if (!first) {
      tieStream << ',';
    } else {
      first = false;
    tieStream << tie->asString(this);
  return tieStream.str();
/**
 * Attaches a tie to this ParamFunction. The attached tie is owned by the
 * ParamFunction.
 * @param tie :: A pointer to a new tie
 */
void IFunction::addTie(std::unique_ptr<ParameterTie> tie) {
  auto iPar = getParameterIndex(*tie);
  bool found = false;
  for (auto &m_tie : m_ties) {
    auto mPar = getParameterIndex(*m_tie);
    if (mPar == iPar) {
      found = true;
      m_tie = std::move(tie);
      break;
    }
  }
  if (!found) {
    m_ties.emplace_back(std::move(tie));
    setParameterStatus(iPar, Tied);
bool IFunction::hasOrderedTies() const { return !m_orderedTies.empty(); }
void IFunction::applyOrderedTies() {
  for (auto &&tie : m_orderedTies) {
    tie->eval();
  }
}

/**
 * Apply the ties.
 */
void IFunction::applyTies() {
  if (hasOrderedTies()) {
    applyOrderedTies();
  } else {
    for (auto &tie : m_ties) {
      tie->eval();
    }
  }
}

/**
 * Used to find ParameterTie for a parameter i
 */
class ReferenceEqual {
  /// The function that has the tie
  const IFunction &m_fun;
  /// index to find
  const size_t m_i;

public:
  /// Constructor
  explicit ReferenceEqual(const IFunction &fun, size_t i)
      : m_fun(fun), m_i(i) {}
  /// Bracket operator
  /// @param p :: the element you are looking for
  /// @return True if found
  template <class T> bool operator()(const std::unique_ptr<T> &p) {
    return m_fun.getParameterIndex(*p) == m_i;
  }
};

/** Removes i-th parameter's tie if it is tied or does nothing.
 * @param i :: The index of the tied parameter.
 * @return True if successfull
 */
bool IFunction::removeTie(size_t i) {
  if (i >= nParams()) {
    throw std::out_of_range("Function parameter index out of range.");
  }
  auto it =
      std::find_if(m_ties.begin(), m_ties.end(), ReferenceEqual(*this, i));
  if (it != m_ties.end()) {
    m_ties.erase(it);
    setParameterStatus(i, Active);
    return true;
  }
  unfix(i);
  return false;
}

/** Get tie of parameter number i
 * @param i :: The index of a declared parameter.
 * @return A pointer to the tie
 */
ParameterTie *IFunction::getTie(size_t i) const {
  auto it =
      std::find_if(m_ties.cbegin(), m_ties.cend(), ReferenceEqual(*this, i));
  if (it != m_ties.cend()) {
    return it->get();
  }
  return nullptr;
}

/** Remove all ties
 */
void IFunction::clearTies() {
  for (size_t i = 0; i < nParams(); ++i) {
    setParameterStatus(i, Active);
  }
  m_ties.clear();
}

/** Add a constraint
 *  @param ic :: Pointer to a constraint.
 */
void IFunction::addConstraint(std::unique_ptr<IConstraint> ic) {
  size_t iPar = ic->parameterIndex();
  bool found = false;
  for (auto &constraint : m_constraints) {
    if (constraint->parameterIndex() == iPar) {
      found = true;
      constraint = std::move(ic);
      break;
    }
  }
  if (!found) {
    m_constraints.emplace_back(std::move(ic));
  }
}

/** Get constraint of parameter number i
 * @param i :: The index of a declared parameter.
 * @return A pointer to the constraint or NULL
 */
IConstraint *IFunction::getConstraint(size_t i) const {
  auto it = std::find_if(m_constraints.cbegin(), m_constraints.cend(),
                         ReferenceEqual(*this, i));
  if (it != m_constraints.cend()) {
    return it->get();
  }
  return nullptr;
}

/** Remove a constraint
 * @param parName :: The name of a parameter which constarint to remove.
 */
void IFunction::removeConstraint(const std::string &parName) {
  size_t iPar = parameterIndex(parName);
  for (auto it = m_constraints.begin(); it != m_constraints.end(); ++it) {
    if (iPar == (**it).getLocalIndex()) {
/** Set a constraint penalty
 * @param parName :: The name of a constraint
 * @param c :: The penalty
 */
void IFunction::setConstraintPenaltyFactor(const std::string &parName,
                                           const double &c) {
  size_t iPar = parameterIndex(parName);
  for (auto &constraint : m_constraints) {
    if (iPar == constraint->getLocalIndex()) {
      constraint->setPenaltyFactor(c);
  g_log.warning()
      << parName
      << " does not have constraint so setConstraintPenaltyFactor failed"
      << "\n";
/// Remove all constraints.
void IFunction::clearConstraints() { m_constraints.clear(); }

void IFunction::setUpForFit() {
  for (auto &constraint : m_constraints) {
    constraint->setParamToSatisfyConstraint();
  }
}

/// Write all parameter constraints owned by this function to a string
/// @return A constraint string for the parameter.
std::string IFunction::writeConstraints() const {
  std::ostringstream stream;
  bool first = true;
  for (auto &constrint : m_constraints) {
    if (constrint->isDefault())
      continue;
    if (!first) {
      stream << ',';
    } else {
      first = false;
    stream << constrint->asString();
 * Writes a string that can be used in FunctionFunctory to create a copy of this
 * IFunction
 * @return string representation of the function
 */
std::string IFunction::asString() const { return writeToString(); }

/**
 * Writes this function into a string.
 * @param parentLocalAttributesStr :: A preformatted string with local
 * attributes of a parent composite function. Can be passed in by a
 * CompositeFunction (eg MultiDomainFunction).
 * @return string representation of the function
 */
std::string
IFunction::writeToString(const std::string &parentLocalAttributesStr) const {
  std::ostringstream ostr;
  ostr << "name=" << this->name();
  // print the attributes
  std::vector<std::string> attr = this->getAttributeNames();
  for (const auto &attName : attr) {
    std::string attValue = this->getAttribute(attName).value();
    if (!attValue.empty() && attValue != "\"\"") {
      ostr << ',' << attName << '=' << attValue;
    }
  }
  std::vector<std::string> ties;
  for (size_t i = 0; i < nParams(); i++) {
    std::ostringstream paramOut;
    paramOut << parameterName(i) << '=' << getParameter(i);
    ostr << ',' << paramOut.str();
    // Output non-default ties only.
    if (getParameterStatus(i) == Fixed) {
      ties.emplace_back(paramOut.str());

  // collect non-default constraints
  std::string constraints = writeConstraints();
  // print constraints
  if (!constraints.empty()) {
    ostr << ",constraints=(" << constraints << ")";
  }

  // collect the non-default ties
  auto tiesString = writeTies();
  if (!tiesString.empty()) {
    ties.emplace_back(tiesString);
  }
  // print the ties
  if (!ties.empty()) {
    ostr << ",ties=(" << Kernel::Strings::join(ties.begin(), ties.end(), ",")
         << ")";
  }
  // "local" attributes of a parent composite function
  ostr << parentLocalAttributesStr;
/** Add a list of constraints from a string
 * @param str :: A comma-separated list of constraint expressions.
 * @param isDefault :: Flag to mark as default the value of an object associated
 *with this reference.
void IFunction::addConstraints(const std::string &str, bool isDefault) {
  Expression list;
  list.parse(str);
  list.toList();
  for (auto it = list.begin(); it != list.end(); ++it) {
    auto expr = (*it);
    if (expr.terms()[0].str().compare("penalty") == 0) {
    if ((it + 1) != list.end()) {
      auto next_expr = *(it + 1);
      if (next_expr.terms()[0].str().compare("penalty") == 0) {
        auto c = std::unique_ptr<IConstraint>(
            ConstraintFactory::Instance().createInitialized(this, expr,
                                                            isDefault));
        double penalty_factor = std::stof(next_expr.terms()[1].str(), NULL);
        c->setPenaltyFactor(penalty_factor);
        this->addConstraint(std::move(c));
      } else {
        auto c = std::unique_ptr<IConstraint>(
            ConstraintFactory::Instance().createInitialized(this, expr,
                                                            isDefault));
        this->addConstraint(std::move(c));
      }
    } else {
      auto c = std::unique_ptr<IConstraint>(
          ConstraintFactory::Instance().createInitialized(this, expr,
                                                          isDefault));
      this->addConstraint(std::move(c));
  }
}

/**
 * Return a vector with all parameter names.
 */
std::vector<std::string> IFunction::getParameterNames() const {
  std::vector<std::string> out;
  for (size_t i = 0; i < nParams(); ++i) {
    out.emplace_back(parameterName(i));
/** Set a function handler
 * @param handler :: A new handler
 */
void IFunction::setHandler(std::unique_ptr<FunctionHandler> handler) {
  m_handler = std::move(handler);
  if (handler && handler->function().get() != this) {
    throw std::runtime_error("Function handler points to a different function");
  }
  m_handler->init();
}

/// Function to return all of the categories that contain this function
const std::vector<std::string> IFunction::categories() const {
  Mantid::Kernel::StringTokenizer tokenizer(
      category(), categorySeparator(),
      Mantid::Kernel::StringTokenizer::TOK_TRIM |
          Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
  return tokenizer.asVector();
/**
 * Operator <<
 * @param ostr :: The output stream
 * @param f :: The IFunction
 */
std::ostream &operator<<(std::ostream &ostr, const IFunction &f) {
namespace {
/**
 * Const attribute visitor returning the type of the attribute
 */
class AttType : public IFunction::ConstAttributeVisitor<std::string> {
protected:
  /// Apply if string
  std::string apply(const std::string & /*str*/) const override {
  /// Apply if int
  std::string apply(const int & /*i*/) const override { return "int"; }
  /// Apply if double
  std::string apply(const double & /*d*/) const override { return "double"; }
  /// Apply if bool
  std::string apply(const bool & /*i*/) const override { return "bool"; }
  /// Apply if vector
  std::string apply(const std::vector<double> & /*unused*/) const override {
    return "std::vector<double>";
  }
};
} // namespace
std::string IFunction::Attribute::type() const {
namespace {
/**
 * Const attribute visitor returning the value of the attribute as a string
 */
class AttValue : public IFunction::ConstAttributeVisitor<std::string> {
public:
  explicit AttValue(bool quoteString = false)
      : IFunction::ConstAttributeVisitor<std::string>(),
        m_quoteString(quoteString) {}

protected:
  /// Apply if string
  std::string apply(const std::string &str) const override {
    return (m_quoteString) ? std::string("\"" + str + "\"") : str;
  }
  /// Apply if int
  std::string apply(const int &i) const override { return std::to_string(i); }
  /// Apply if double
  std::string apply(const double &d) const override {
    return boost::lexical_cast<std::string>(d);
  }
  /// Apply if bool
  std::string apply(const bool &b) const override {
    return b ? "true" : "false";
  }
  /// Apply if vector
  std::string apply(const std::vector<double> &v) const override {
    std::string res = "(";
      for (size_t i = 0; i < v.size() - 1; ++i) {
        res += boost::lexical_cast<std::string>(v[i]) + ",";
      }
      res += boost::lexical_cast<std::string>(v.back());
    res += ")";
    return res;
  }
private:
  /// Flag to quote a string value returned
  bool m_quoteString;
};
} // namespace
/// Copy assignment. Do not copy m_quoteValue flag.
/// @param attr :: The attribute to copy from.
IFunction::Attribute &IFunction::Attribute::operator=(const Attribute &attr) {
std::string IFunction::Attribute::value() const {
  AttValue tmp(m_quoteValue);
  return apply(tmp);
}

/**
 * Return the attribute as a string if it is a string.
 */
std::string IFunction::Attribute::asString() const {
  if (m_quoteValue)
    return asQuotedString();

  try {
    return boost::get<std::string>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as string");
/**
 * Return the attribute as a quoted string if it is a string.
 */
std::string IFunction::Attribute::asQuotedString() const {
    attr = boost::get<std::string>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as string");
  if (attr.empty())
    return "\"\"";
  if (*(attr.begin()) != '\"')
    quoted = "\"" + attr;
  if (*(quoted.end() - 1) != '\"')
    quoted += "\"";
/**
 * Return the attribute as an unquoted string if it is a string.
 */
std::string IFunction::Attribute::asUnquotedString() const {
    attr = boost::get<std::string>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as string");
  if (attr.empty())
    return "";
  if (*(attr.begin()) == '\"')
    unquoted = std::string(attr.begin() + 1, attr.end() - 1);
  if (*(unquoted.end() - 1) == '\"')
    unquoted = std::string(unquoted.begin(), unquoted.end() - 1);

/**
 * Return the attribute as an int if it is a int.
 */
int IFunction::Attribute::asInt() const {
  try {
    return boost::get<int>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as int");
/**
 * Return the attribute as a double if it is a double.
 */
double IFunction::Attribute::asDouble() const {
  try {
    return boost::get<double>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as double");
/**
 * Return the attribute as a bool if it is a bool.
 */
bool IFunction::Attribute::asBool() const {
  try {
    return boost::get<bool>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as bool");
}

/**
 * Return the attribute as a bool if it is a vector.
 */
std::vector<double> IFunction::Attribute::asVector() const {
  try {
    return boost::get<std::vector<double>>(m_data);
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as vector");
/** Sets new value if attribute is a string. If the type is wrong
 * throws an exception
 * @param str :: The new value
 */
void IFunction::Attribute::setString(const std::string &str) {
  try {
    boost::get<std::string>(m_data) = str;
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as string");
/** Sets new value if attribute is a double. If the type is wrong
 * throws an exception
 * @param d :: The new value
 */
void IFunction::Attribute::setDouble(const double &d) {
  try {
    boost::get<double>(m_data) = d;
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as double");
/** Sets new value if attribute is an int. If the type is wrong
 * throws an exception
 * @param i :: The new value
 */
void IFunction::Attribute::setInt(const int &i) {
  try {
    boost::get<int>(m_data) = i;
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as int");
/** Sets new value if attribute is an bool. If the type is wrong
 * throws an exception
 * @param b :: The new value
void IFunction::Attribute::setBool(const bool &b) {
  try {
    boost::get<bool>(m_data) = b;
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as bool");
}

/**
 * Sets new value if attribute is a vector. If the type is wrong
 * throws an exception
 * @param v :: The new value
 */
void IFunction::Attribute::setVector(const std::vector<double> &v) {
  try {
    auto &value = boost::get<std::vector<double>>(m_data);
    value.assign(v.begin(), v.end());
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute "
                             "as vector");
/// Check if a string attribute is empty
bool IFunction::Attribute::isEmpty() const {
  try {
    return boost::get<std::string>(m_data).empty();
  } catch (...) {
    throw std::runtime_error("Trying to access a " + type() +
                             " attribute as string");
  }
}

namespace {
/**
 * Attribute visitor setting new value to an attribute
 */
class SetValue : public IFunction::AttributeVisitor<> {
public:
   * Constructor
   * @param value :: The value to set
  explicit SetValue(const std::string &value) : m_value(value) {}

protected:
  /// Apply if string
  void apply(std::string &str) const override { str = m_value; }
  /// Apply if int
  void apply(int &i) const override {
    std::istringstream istr(m_value + " ");
    istr >> i;
    if (!istr.good())
      throw std::invalid_argument("Failed to set int attribute "
                                  "from string " +
                                  m_value);
  }
  /// Apply if double
  void apply(double &d) const override {
    std::istringstream istr(m_value + " ");
    istr >> d;
    if (!istr.good())
      throw std::invalid_argument("Failed to set double attribute "
                                  "from string " +
                                  m_value);
  }
  /// Apply if bool
  void apply(bool &b) const override {
    b = (m_value == "true" || m_value == "TRUE" || m_value == "1");
  }
  /// Apply if vector
  void apply(std::vector<double> &v) const override {
    if (m_value.empty() || m_value == "EMPTY") {
      v.clear();
      return;
    if (m_value.size() > 2) {
      // check if the value is in barckets (...)
      if (m_value.front() == '(' && m_value.back() == ')') {
        m_value.erase(0, 1);
        m_value.erase(m_value.size() - 1);
      }
    Mantid::Kernel::StringTokenizer tokenizer(
        m_value, ",", Mantid::Kernel::StringTokenizer::TOK_TRIM);
    v.resize(tokenizer.count());
    for (size_t i = 0; i < v.size(); ++i) {
      v[i] = boost::lexical_cast<double>(tokenizer[i]);
  mutable std::string m_value; ///< the value as a string
} // namespace

/** Set value from a string. Throws exception if the string has wrong format
 * @param str :: String representation of the new value
 */
void IFunction::Attribute::fromString(const std::string &str) {
/// Value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
double IFunction::activeParameter(size_t i) const {
  if (!isActive(i)) {
    throw std::runtime_error("Attempt to use an inactive parameter " +
                             parameterName(i));
/// Set new value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
void IFunction::setActiveParameter(size_t i, double value) {
  if (!isActive(i)) {
    throw std::runtime_error("Attempt to use an inactive parameter " +
                             parameterName(i));
  setParameter(i, value);
/**
 * Returns the name of an active parameter.
 * @param i :: Index of a parameter. The parameter must be active.
 */
std::string IFunction::nameOfActive(size_t i) const {
  if (!isActive(i)) {
    throw std::runtime_error("Attempt to use an inactive parameter " +
                             parameterName(i));
/**
 * Returns the description of an active parameter.
 * @param i :: Index of a parameter. The parameter must be active.
 */
std::string IFunction::descriptionOfActive(size_t i) const {
  if (!isActive(i)) {
    throw std::runtime_error("Attempt to use an inactive parameter " +
                             parameterName(i));
/** Calculate numerical derivatives.
 * @param domain :: The domain of the function
 * @param jacobian :: A Jacobian matrix. It is expected to have dimensions of
 * domain.size() by nParams().
void IFunction::calNumericalDeriv(const FunctionDomain &domain,
                                  Jacobian &jacobian) {
  /*
   * There is a similar more specialized method for 1D functions in IFunction1D
   * but the method takes different parameters and uses slightly different
   * function calls in places making it difficult to share code. Please also
   * consider that method when updating this.
   */

  constexpr double epsilon = std::numeric_limits<double>::epsilon() * 100;