Example #1
0
/// Create a submatrix. A submatrix is a view into the parent matrix.
/// Lifetime of a submatrix cannot exceed the lifetime of the parent.
/// @param M :: The parent matrix.
/// @param row :: The first row in the submatrix.
/// @param col :: The first column in the submatrix.
/// @param nRows :: The number of rows in the submatrix.
/// @param nCols :: The number of columns in the submatrix.
GSLMatrix::GSLMatrix(const GSLMatrix &M, size_t row, size_t col, size_t nRows,
                     size_t nCols) {
  if (row + nRows > M.size1() || col + nCols > M.size2()) {
    throw std::runtime_error("Submatrix exceeds matrix size.");
  }
  auto view = gsl_matrix_const_submatrix(M.gsl(), row, col, nRows, nCols);
  m_matrix = gsl_matrix_alloc(nRows, nCols);
  gsl_matrix_memcpy(m_matrix, &view.matrix);
}
Example #2
0
/// Calculate the eigensystem of a symmetric matrix
/// @param eigenValues :: Output variable that receives the eigenvalues of this
/// matrix.
/// @param eigenVectors :: Output variable that receives the eigenvectors of
/// this matrix.
void GSLMatrix::eigenSystem(GSLVector &eigenValues, GSLMatrix &eigenVectors) {
  size_t n = size1();
  if (n != size2()) {
    throw std::runtime_error("Matrix eigenSystem: the matrix must be square.");
  }
  eigenValues.resize(n);
  eigenVectors.resize(n, n);
  auto workspace = gsl_eigen_symmv_alloc(n);
  gsl_eigen_symmv(gsl(), eigenValues.gsl(), eigenVectors.gsl(), workspace);
  gsl_eigen_symmv_free(workspace);
}
Example #3
0
/**
  * Calculates covariance matrix for fitting function's active parameters.
  */
void CostFuncFitting::calActiveCovarianceMatrix(GSLMatrix &covar,
                                                double epsrel) {
  // construct the jacobian
  GSLJacobian J(m_function, m_values->size());
  size_t na = this->nParams(); // number of active parameters
  assert(J.getJ()->size2 == na);
  covar.resize(na, na);

  // calculate the derivatives
  m_function->functionDeriv(*m_domain, J);

  // let the GSL to compute the covariance matrix
  gsl_multifit_covar(J.getJ(), epsrel, covar.gsl());
}
/**
  * Calculates covariance matrix for fitting function's active parameters. 
  * @param covar :: Output cavariance matrix.
  * @param epsrel :: Tolerance.
  */
void CostFuncLeastSquares::calActiveCovarianceMatrix(GSLMatrix& covar, double epsrel)
{
  UNUSED_ARG(epsrel);
  if (m_hessian.isEmpty())
  {
    valDerivHessian();
  }
  covar = m_hessian;
  covar.invert();
}
Example #5
0
/**
 * Calculate the transformation matrix T by numeric differentiation
 * @param tm :: The output transformation matrix.
 */
void CostFuncFitting::calTransformationMatrixNumerically(GSLMatrix &tm) {
  const double epsilon = std::numeric_limits<double>::epsilon() * 100;
  size_t np = m_function->nParams();
  size_t na = nParams();
  tm.resize(na, na);
  size_t ia = 0;
  for (size_t i = 0; i < np; ++i) {
    if (m_function->isFixed(i))
      continue;
    double p0 = m_function->getParameter(i);
    for (size_t j = 0; j < na; ++j) {
      double ap = getParameter(j);
      double step = ap == 0.0 ? epsilon : ap * epsilon;
      setParameter(j, ap + step);
      tm.set(ia, j, (m_function->getParameter(i) - p0) / step);
      setParameter(j, ap);
    }
    ++ia;
  }
}
Example #6
0
/**
  * Calculates covariance matrix for fitting function's active parameters.
  * @param covar :: Output cavariance matrix.
  * @param epsrel :: Tolerance.
  */
void CostFuncLeastSquares::calActiveCovarianceMatrix(GSLMatrix &covar,
                                                     double epsrel) {
  UNUSED_ARG(epsrel);

  if (m_hessian.isEmpty()) {
    valDerivHessian();
  }

  if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
    std::ostringstream osHess;
    osHess << "== Hessian (H) ==\n";
    osHess << std::left << std::fixed;
    for (size_t i = 0; i < m_hessian.size1(); ++i) {
      for (size_t j = 0; j < m_hessian.size2(); ++j) {
        osHess << std::setw(10);
        osHess << m_hessian.get(i, j) << "  ";
      }
      osHess << "\n";
    }
    g_log.debug() << osHess.str();
  }

  covar = m_hessian;
  covar.invert();
  if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
    std::ostringstream osCovar;
    osCovar << "== Covariance matrix (H^-1) ==\n";
    osCovar << std::left << std::fixed;
    for (size_t i = 0; i < covar.size1(); ++i) {
      for (size_t j = 0; j < covar.size2(); ++j) {
        osCovar << std::setw(10);
        osCovar << covar.get(i, j) << "  ";
      }
      osCovar << "\n";
    }
    g_log.debug() << osCovar.str();
  }
}
Example #7
0
/**
 * Calculate the fitting errors and assign them to the fitting function.
 * @param covar :: A covariance matrix to use for error calculations.
 *   It can be calculated with calCovarianceMatrix().
 * @param chi2 :: The final chi-squared of the fit.
 */
void CostFuncFitting::calFittingErrors(const GSLMatrix &covar, double chi2) {
  size_t np = m_function->nParams();
  auto covarMatrix = boost::shared_ptr<Kernel::Matrix<double>>(
      new Kernel::Matrix<double>(np, np));
  size_t ia = 0;
  for (size_t i = 0; i < np; ++i) {
    if (m_function->isFixed(i)) {
      m_function->setError(i, 0);
    } else {
      size_t ja = 0;
      for (size_t j = 0; j < np; ++j) {
        if (!m_function->isFixed(j)) {
          (*covarMatrix)[i][j] = covar.get(ia, ja);
          ++ja;
        }
      }
      double err = sqrt(covar.get(ia, ia));
      m_function->setError(i, err);
      ++ia;
    }
  }
  m_function->setCovarianceMatrix(covarMatrix);
  m_function->setChiSquared(chi2);
}
Example #8
0
/**
 * Calculate the fitting errors and assign them to the fitting function.
 * @param covar :: A covariance matrix to use for error calculations.
 *   It can be calculated with calCovarianceMatrix().
 */
void CostFuncFitting::calFittingErrors(const GSLMatrix& covar)
{
  size_t np = m_function->nParams();
  size_t ia = 0;
  for(size_t i = 0; i < np; ++i)
  {
    if (m_function->isFixed(i))
    {
      m_function->setError(i,0);
    }
    else
    {
      double err = sqrt(covar.get(ia,ia));
      m_function->setError(i,err);
      ++ia;
    }
  }
}
Example #9
0
/** Executes the algorithm
*
*  @throw runtime_error Thrown if algorithm cannot execute
*/
void Fit::execConcrete() {

  std::string ties = getPropertyValue("Ties");
  if (!ties.empty()) {
    m_function->addTies(ties);
  }
  std::string contstraints = getPropertyValue("Constraints");
  if (!contstraints.empty()) {
    m_function->addConstraints(contstraints);
  }

  // prepare the function for a fit
  m_function->setUpForFit();

  API::FunctionDomain_sptr domain;
  API::FunctionValues_sptr values;
  m_domainCreator->createDomain(domain, values);

  // do something with the function which may depend on workspace
  m_domainCreator->initFunction(m_function);

  // get the minimizer
  std::string minimizerName = getPropertyValue("Minimizer");
  API::IFuncMinimizer_sptr minimizer =
      API::FuncMinimizerFactory::Instance().createMinimizer(minimizerName);

  // Try to retrieve optional properties
  int intMaxIterations = getProperty("MaxIterations");
  const size_t maxIterations = static_cast<size_t>(intMaxIterations);

  // get the cost function which must be a CostFuncFitting
  boost::shared_ptr<CostFuncFitting> costFunc =
      boost::dynamic_pointer_cast<CostFuncFitting>(
          API::CostFunctionFactory::Instance().create(
              getPropertyValue("CostFunction")));

  costFunc->setFittingFunction(m_function, domain, values);
  minimizer->initialize(costFunc, maxIterations);

  const int64_t nsteps = maxIterations * m_function->estimateNoProgressCalls();
  API::Progress prog(this, 0.0, 1.0, nsteps);
  m_function->setProgressReporter(&prog);

  // do the fitting until success or iteration limit is reached
  size_t iter = 0;
  bool success = false;
  std::string errorString;
  g_log.debug("Starting minimizer iteration\n");
  while (iter < maxIterations) {
    g_log.debug() << "Starting iteration " << iter << "\n";
    m_function->iterationStarting();
    if (!minimizer->iterate(iter)) {
      errorString = minimizer->getError();
      g_log.debug() << "Iteration stopped. Minimizer status string="
                    << errorString << "\n";

      success = errorString.empty() || errorString == "success";
      if (success) {
        errorString = "success";
      }
      break;
    }
    prog.report();
    m_function->iterationFinished();
    ++iter;
  }
  g_log.debug() << "Number of minimizer iterations=" << iter << "\n";

  minimizer->finalize();

  if (iter >= maxIterations) {
    if (!errorString.empty()) {
      errorString += '\n';
    }
    errorString += "Failed to converge after " +
                   boost::lexical_cast<std::string>(maxIterations) +
                   " iterations.";
  }

  // return the status flag
  setPropertyValue("OutputStatus", errorString);

  // degrees of freedom
  size_t dof = domain->size() - costFunc->nParams();
  if (dof == 0)
    dof = 1;
  double rawcostfuncval = minimizer->costFunctionVal();
  double finalCostFuncVal = rawcostfuncval / double(dof);

  setProperty("OutputChi2overDoF", finalCostFuncVal);

  // fit ended, creating output

  // get the workspace
  API::Workspace_const_sptr ws = getProperty("InputWorkspace");

  bool doCreateOutput = getProperty("CreateOutput");
  std::string baseName = getPropertyValue("Output");
  if (!baseName.empty()) {
    doCreateOutput = true;
  }
  bool doCalcErrors = getProperty("CalcErrors");
  if (doCreateOutput) {
    doCalcErrors = true;
  }
  if (costFunc->nParams() == 0) {
    doCalcErrors = false;
  }

  GSLMatrix covar;
  if (doCalcErrors) {
    // Calculate the covariance matrix and the errors.
    costFunc->calCovarianceMatrix(covar);
    costFunc->calFittingErrors(covar, rawcostfuncval);
  }

  if (doCreateOutput) {
    copyMinimizerOutput(*minimizer);

    if (baseName.empty()) {
      baseName = ws->name();
      if (baseName.empty()) {
        baseName = "Output";
      }
    }
    baseName += "_";

    declareProperty(
        new API::WorkspaceProperty<API::ITableWorkspace>(
            "OutputNormalisedCovarianceMatrix", "", Kernel::Direction::Output),
        "The name of the TableWorkspace in which to store the final covariance "
        "matrix");
    setPropertyValue("OutputNormalisedCovarianceMatrix",
                     baseName + "NormalisedCovarianceMatrix");

    Mantid::API::ITableWorkspace_sptr covariance =
        Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
    covariance->addColumn("str", "Name");
    // set plot type to Label = 6
    covariance->getColumn(covariance->columnCount() - 1)->setPlotType(6);
    // std::vector<std::string> paramThatAreFitted; // used for populating 1st
    // "name" column
    for (size_t i = 0; i < m_function->nParams(); i++) {
      if (m_function->isActive(i)) {
        covariance->addColumn("double", m_function->parameterName(i));
        // paramThatAreFitted.push_back(m_function->parameterName(i));
      }
    }

    size_t np = m_function->nParams();
    size_t ia = 0;
    for (size_t i = 0; i < np; i++) {
      if (m_function->isFixed(i))
        continue;
      Mantid::API::TableRow row = covariance->appendRow();
      row << m_function->parameterName(i);
      size_t ja = 0;
      for (size_t j = 0; j < np; j++) {
        if (m_function->isFixed(j))
          continue;
        if (j == i)
          row << 100.0;
        else {
          if (!covar.gsl()) {
            throw std::runtime_error(
                "There was an error while allocating the (GSL) covariance "
                "matrix "
                "which is needed to produce fitting error results.");
          }
          row << 100.0 * covar.get(ia, ja) /
                     sqrt(covar.get(ia, ia) * covar.get(ja, ja));
        }
        ++ja;
      }
      ++ia;
    }

    setProperty("OutputNormalisedCovarianceMatrix", covariance);

    // create output parameter table workspace to store final fit parameters
    // including error estimates if derivative of fitting function defined

    declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>(
                        "OutputParameters", "", Kernel::Direction::Output),
                    "The name of the TableWorkspace in which to store the "
                    "final fit parameters");

    setPropertyValue("OutputParameters", baseName + "Parameters");

    Mantid::API::ITableWorkspace_sptr result =
        Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
    result->addColumn("str", "Name");
    // set plot type to Label = 6
    result->getColumn(result->columnCount() - 1)->setPlotType(6);
    result->addColumn("double", "Value");
    result->addColumn("double", "Error");
    // yErr = 5
    result->getColumn(result->columnCount() - 1)->setPlotType(5);

    for (size_t i = 0; i < m_function->nParams(); i++) {
      Mantid::API::TableRow row = result->appendRow();
      row << m_function->parameterName(i) << m_function->getParameter(i)
          << m_function->getError(i);
    }
    // Add chi-squared value at the end of parameter table
    Mantid::API::TableRow row = result->appendRow();
#if 1
    std::string costfuncname = getPropertyValue("CostFunction");
    if (costfuncname == "Rwp")
      row << "Cost function value" << rawcostfuncval;
    else
      row << "Cost function value" << finalCostFuncVal;
    setProperty("OutputParameters", result);
#else
    row << "Cost function value" << finalCostFuncVal;
    Mantid::API::TableRow row2 = result->appendRow();
    std::string name(getPropertyValue("CostFunction"));
    name += " value";
    row2 << name << rawcostfuncval;
#endif

    setProperty("OutputParameters", result);

    bool outputParametersOnly = getProperty("OutputParametersOnly");

    if (!outputParametersOnly) {
      const bool unrollComposites = getProperty("OutputCompositeMembers");
      bool convolveMembers = existsProperty("ConvolveMembers");
      if (convolveMembers) {
        convolveMembers = getProperty("ConvolveMembers");
      }
      m_domainCreator->separateCompositeMembersInOutput(unrollComposites,
                                                        convolveMembers);
      m_domainCreator->createOutputWorkspace(baseName, m_function, domain,
                                             values);
    }
  }

  progress(1.0);
}
Example #10
0
/// Copy constructor
/// @param M :: The other matrix.
GSLMatrix::GSLMatrix(const GSLMatrix &M)
    : m_data(M.m_data),
      m_view(gsl_matrix_view_array(m_data.data(), M.size1(), M.size2())) {}
Example #11
0
/// Execute algorithm.
void Schrodinger1D::exec()
{
  double startX = get("StartX");
  double endX = get("EndX");

  if (endX <= startX)
  {
    throw std::invalid_argument("StartX must be <= EndX");
  }

  IFunction_sptr VPot = getClass("VPot");
  chebfun vpot( 0, startX, endX );
  vpot.bestFit( *VPot );

  size_t nBasis = vpot.n() + 1;
  std::cerr << "n=" << nBasis << std::endl;
  //if (n < 3)
  {
    nBasis = 200;
    vpot.resize( nBasis );
  }

  const double beta = get("Beta");

  auto kinet = new ChebCompositeOperator;
  kinet->addRight( new ChebTimes(-beta) );
  kinet->addRight( new ChebDiff2 );
  auto hamiltonian = new ChebPlus;
  hamiltonian->add('+', kinet );
  hamiltonian->add('+', new ChebTimes(VPot) );

  GSLMatrix L;
  hamiltonian->createMatrix( vpot.getBase(), L );

  GSLVector d;
  GSLMatrix v;
  L.diag( d, v );

  std::vector<double> norms = vpot.baseNorm();
  assert(norms.size() == L.size1());
  assert(norms.size() == L.size2());

  for(size_t i = 0; i < norms.size(); ++i)
  {
      double factor = 1.0 / norms[i];
      for(size_t j = i; j < norms.size(); ++j)
      {
          v.multiplyBy(i,j,factor);
      }
  }

//  eigenvectors orthogonality check
//  GSLMatrix v1 = v;
//  GSLMatrix tst;
//  tst = Tr(v1) * v;
//  std::cerr << tst << std::endl;

  std::vector<size_t> indx(L.size1());
  getSortedIndex( d, indx );

  auto eigenvalues = API::TableWorkspace_ptr(dynamic_cast<API::TableWorkspace*>(
    API::WorkspaceFactory::instance().create("TableWorkspace"))
    );
  eigenvalues->setRowCount(nBasis);
  setProperty("Eigenvalues", eigenvalues);

  eigenvalues->addColumn("double","N");
  auto nColumn = static_cast<API::TableColumn<double>*>(eigenvalues->getColumn("N").get());
  nColumn->asNumeric()->setPlotRole(API::NumericColumn::X);
  auto& nc = nColumn->data();

  eigenvalues->addDoubleColumn("Energy");
  auto eColumn = static_cast<API::TableColumn<double>*>(eigenvalues->getColumn("Energy").get());
  eColumn->asNumeric()->setPlotRole(API::NumericColumn::Y);
  auto& ec = eigenvalues->getDoubleData("Energy");

  boost::scoped_ptr<ChebfunVector> eigenvectors(new ChebfunVector);

  chebfun fun0(nBasis,startX,endX);
  ChebFunction_sptr theSum(new ChebFunction(fun0));

  // collect indices of spurious eigenvalues to move them to the back
  std::vector<size_t> spurious;
  // index for good eigenvalues
  size_t n = 0;
  for(size_t j = 0; j < nBasis; ++j)
  {
    size_t i = indx[j];
    chebfun fun(fun0);
    fun.setP(v,i);

    // check eigenvalues for spurious ones
    chebfun dfun(fun);
    dfun.square();
    double norm = dfun.integr();

    // I am not sure that it's a solid condition
    if ( norm < 0.999999 )
    {
        // bad eigenvalue
        spurious.push_back(j);
    }
    else
    {
        nc[n] = double(n);
        ec[n] = d[i];
        eigenvectors->add(ChebFunction_sptr(new ChebFunction(fun)));

        // test sum of functions squares
        *theSum += dfun;

//        chebfun dfun(fun);
//        hamiltonian->apply(fun,dfun);
//        dfun *= fun;
//        std::cerr << "ener["<<n<<"]=" << ec[n] << ' ' << norm << ' ' << dfun.integr() << std::endl;
        ++n;
    }
  }

  GSLVector eigv;
  ChebfunVector *eigf = NULL;
  improve(hamiltonian, eigenvectors.get(), eigv, &eigf);

  eigenvalues->setRowCount( eigv.size() );
  for(size_t i = 0; i < eigv.size(); ++i)
  {
      nc[i] = double(i);
      ec[i] = eigv[i];
  }

  eigf->add(theSum);
  setProperty("Eigenvectors",ChebfunVector_sptr(eigf));

  //makeQuadrature(eigf);

}
Example #12
0
//----------------------------------------------------------------------------------------------
/// Examine the chi squared as a function of fitting parameters and estimate
/// errors for each parameter.
void CalculateChiSquared::estimateErrors() {
  // Number of fiting parameters
  auto nParams = m_function->nParams();
  // Create an output table for displaying slices of the chi squared and
  // the probabilitydensity function
  auto pdfTable = API::WorkspaceFactory::Instance().createTable();

  std::string baseName = getProperty("Output");
  if (baseName.empty()) {
    baseName = "CalculateChiSquared";
  }
  declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>(
                      "PDFs", "", Kernel::Direction::Output),
                  "The name of the TableWorkspace in which to store the "
                  "pdfs of fit parameters");
  setPropertyValue("PDFs", baseName + "_pdf");
  setProperty("PDFs", pdfTable);

  // Create an output table for displaying the parameter errors.
  auto errorsTable = API::WorkspaceFactory::Instance().createTable();
  auto nameColumn = errorsTable->addColumn("str", "Parameter");
  auto valueColumn = errorsTable->addColumn("double", "Value");
  auto minValueColumn = errorsTable->addColumn("double", "Value at Min");
  auto leftErrColumn = errorsTable->addColumn("double", "Left Error");
  auto rightErrColumn = errorsTable->addColumn("double", "Right Error");
  auto quadraticErrColumn = errorsTable->addColumn("double", "Quadratic Error");
  auto chiMinColumn = errorsTable->addColumn("double", "Chi2 Min");
  errorsTable->setRowCount(nParams);
  declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>(
                      "Errors", "", Kernel::Direction::Output),
                  "The name of the TableWorkspace in which to store the "
                  "values and errors of fit parameters");
  setPropertyValue("Errors", baseName + "_errors");
  setProperty("Errors", errorsTable);

  // Calculate initial values
  double chiSquared = 0.0;
  double chiSquaredWeighted = 0.0;
  double dof = 0;
  API::FunctionDomain_sptr domain;
  API::FunctionValues_sptr values;
  m_domainCreator->createDomain(domain, values);
  calcChiSquared(*m_function, nParams, *domain, *values, chiSquared,
                 chiSquaredWeighted, dof);
  // Value of chi squared for current parameters in m_function
  double chi0 = chiSquared;
  // Fit data variance
  double sigma2 = chiSquared / dof;
  bool useWeighted = getProperty("Weighted");

  if (useWeighted) {
    chi0 = chiSquaredWeighted;
    sigma2 = 0.0;
  }

  if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
    g_log.debug() << "chi0=" << chi0 << std::endl;
    g_log.debug() << "sigma2=" << sigma2 << std::endl;
    g_log.debug() << "dof=" << dof << std::endl;
  }

  // Parameter bounds that define a volume in the parameter
  // space within which the chi squared is being examined.
  GSLVector lBounds(nParams);
  GSLVector rBounds(nParams);

  // Number of points in lines for plotting
  size_t n = 100;
  pdfTable->setRowCount(n);
  const double fac = 1e-4;

  // Loop over each parameter
  for (size_t ip = 0; ip < nParams; ++ip) {

    // Add columns for the parameter to the pdf table.
    auto parName = m_function->parameterName(ip);
    nameColumn->read(ip, parName);
    // Parameter values
    auto col1 = pdfTable->addColumn("double", parName);
    col1->setPlotType(1);
    // Chi squared values
    auto col2 = pdfTable->addColumn("double", parName + "_chi2");
    col2->setPlotType(2);
    // PDF values
    auto col3 = pdfTable->addColumn("double", parName + "_pdf");
    col3->setPlotType(2);

    double par0 = m_function->getParameter(ip);
    double shift = fabs(par0 * fac);
    if (shift == 0.0) {
      shift = fac;
    }

    // Make a slice along this parameter
    GSLVector dir(nParams);
    dir.zero();
    dir[ip] = 1.0;
    ChiSlice slice(*m_function, dir, *domain, *values, chi0, sigma2);

    // Find the bounds withn which the PDF is significantly above zero.
    // The bounds are defined relative to par0:
    //   par0 + lBound is the lowest value of the parameter (lBound <= 0)
    //   par0 + rBound is the highest value of the parameter (rBound >= 0)
    double lBound = slice.findBound(-shift);
    double rBound = slice.findBound(shift);
    lBounds[ip] = lBound;
    rBounds[ip] = rBound;

    // Approximate the slice with a polynomial.
    // P is a vector of values of the polynomial at special points.
    // A is a vector of Chebyshev expansion coefficients.
    // The polynomial is defined on interval [lBound, rBound]
    // The value of the polynomial at 0 == chi squared at par0
    std::vector<double> P, A;
    bool ok = true;
    auto base = slice.makeApprox(lBound, rBound, P, A, ok);
    if (!ok) {
      g_log.warning() << "Approximation failed for parameter " << ip << std::endl;
    }
    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "Parameter " << ip << std::endl;
      g_log.debug() << "Slice approximated by polynomial of order "
                    << base->size() - 1;
      g_log.debug() << " between " << lBound << " and " << rBound << std::endl;
    }

    // Write n slice points into the output table.
    double dp = (rBound - lBound) / static_cast<double>(n);
    for (size_t i = 0; i < n; ++i) {
      double par = lBound + dp * static_cast<double>(i);
      double chi = base->eval(par, P);
      col1->fromDouble(i, par0 + par);
      col2->fromDouble(i, chi);
    }

    // Check if par0 is a minimum point of the chi squared
    std::vector<double> AD;
    // Calculate the derivative polynomial.
    // AD are the Chebyshev expansion of the derivative.
    base->derivative(A, AD);
    // Find the roots of the derivative polynomial
    std::vector<double> minima = base->roots(AD);
    if (minima.empty()) {
      minima.push_back(par0);
    }

    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "Minima: ";
    }

    // If only 1 extremum is found assume (without checking) that it's a
    // minimum.
    // If there are more than 1, find the one with the smallest chi^2.
    double chiMin = std::numeric_limits<double>::max();
    double parMin = par0;
    for (size_t i = 0; i < minima.size(); ++i) {
      double value = base->eval(minima[i], P);
      if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
        g_log.debug() << minima[i] << " (" << value << ") ";
      }
      if (value < chiMin) {
        chiMin = value;
        parMin = minima[i];
      }
    }
    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << std::endl;
      g_log.debug() << "Smallest minimum at " << parMin << " is " << chiMin
                    << std::endl;
    }

    // Points of intersections with line chi^2 = 1/2 give an estimate of
    // the standard deviation of this parameter if it's uncorrelated with the
    // others.
    A[0] -= 0.5; // Now A are the coefficients of the original polynomial
                 // shifted down by 1/2.
    std::vector<double> roots = base->roots(A);
    std::sort(roots.begin(), roots.end());

    if (roots.empty()) {
      // Something went wrong; use the whole interval.
      roots.resize(2);
      roots[0] = lBound;
      roots[1] = rBound;
    } else if (roots.size() == 1) {
      // Only one root found; use a bound for the other root.
      if (roots.front() < 0) {
        roots.push_back(rBound);
      } else {
        roots.insert(roots.begin(), lBound);
      }
    } else if (roots.size() > 2) {
      // More than 2 roots; use the smallest and the biggest
      auto smallest = roots.front();
      auto biggest = roots.back();
      roots.resize(2);
      roots[0] = smallest;
      roots[1] = biggest;
    }

    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "Roots: ";
      for (size_t i = 0; i < roots.size(); ++i) {
        g_log.debug() << roots[i] << ' ';
      }
      g_log.debug() << std::endl;
    }

    // Output parameter info to the table.
    valueColumn->fromDouble(ip, par0);
    minValueColumn->fromDouble(ip, par0 + parMin);
    leftErrColumn->fromDouble(ip, roots[0] - parMin);
    rightErrColumn->fromDouble(ip, roots[1] - parMin);
    chiMinColumn->fromDouble(ip, chiMin);

    // Output the PDF
    for (size_t i = 0; i < n; ++i) {
      double chi = col2->toDouble(i);
      col3->fromDouble(i, exp(-chi + chiMin));
    }

    // make sure function parameters don't change.
    m_function->setParameter(ip, par0);
  }

  // Improve estimates for standard deviations.
  // If parameters are correlated the found deviations
  // most likely underestimate the true values.
  unfixParameters();
  GSLJacobian J(m_function, values->size());
  m_function->functionDeriv(*domain, J);
  refixParameters();
  // Calculate the hessian at the current point.
  GSLMatrix H;
  if (useWeighted) {
    H.resize(nParams, nParams);
    for (size_t i = 0; i < nParams; ++i) {
      for (size_t j = i; j < nParams; ++j) {
        double h = 0.0;
        for (size_t k = 0; k < values->size(); ++k) {
          double w = values->getFitWeight(k);
          h += J.get(k, i) * J.get(k, j) * w * w;
        }
        H.set(i, j, h);
        if (i != j) {
          H.set(j, i, h);
        }
      }
    }
  } else {
    H = Tr(J.matrix()) * J.matrix();
  }
  // Square roots of the diagonals of the covariance matrix give
  // the standard deviations in the quadratic approximation of the chi^2.
  GSLMatrix V(H);
  if (!useWeighted) {
    V *= 1. / sigma2;
  }
  V.invert();
  // In a non-quadratic asymmetric case the following procedure can give a
  // better result:
  // Find the direction in which the chi^2 changes slowest and the positive and
  // negative deviations in that direction. The change in a parameter at those
  // points can be a better estimate for the standard deviation.
  GSLVector v(nParams);
  GSLMatrix Q(nParams, nParams);
  // One of the eigenvectors of the hessian is the direction of the slowest
  // change.
  H.eigenSystem(v, Q);

  // Loop over the eigenvectors
  for (size_t i = 0; i < nParams; ++i) {
    auto dir = Q.copyColumn(i);
    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "Direction " << i << std::endl;
      g_log.debug() << dir << std::endl;
    }
    // Make a slice in that direction
    ChiSlice slice(*m_function, dir, *domain, *values, chi0, sigma2);
    double rBound0 = dir.dot(rBounds);
    double lBound0 = dir.dot(lBounds);
    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "lBound " << lBound0 << std::endl;
      g_log.debug() << "rBound " << rBound0 << std::endl;
    }
    double lBound = slice.findBound(lBound0);
    double rBound = slice.findBound(rBound0);
    std::vector<double> P, A;
    // Use a polynomial approximation
    bool ok = true;
    auto base = slice.makeApprox(lBound, rBound, P, A, ok);
    if (!ok) {
      g_log.warning() << "Approximation failed in direction " << i << std::endl;
    }
    // Find the deviation points where the chi^2 = 1/2
    A[0] -= 0.5;
    std::vector<double> roots = base->roots(A);
    std::sort(roots.begin(), roots.end());
    // Sort out the roots
    auto nRoots = roots.size();
    if (nRoots == 0) {
      roots.resize(2, 0.0);
    } else if (nRoots == 1) {
      if (roots.front() > 0.0) {
        roots.insert(roots.begin(), 0.0);
      } else {
        roots.push_back(0.0);
      }
    } else if (nRoots > 2) {
      roots[1] = roots.back();
      roots.resize(2);
    }
    if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
      g_log.debug() << "Roots " << roots[0] << " (" << slice(roots[0]) << ") " << roots[1] << " (" << slice(roots[1]) << ") " << std::endl;
    }
    // Loop over the parameters and see if there deviations along
    // this direction is greater than any previous value.
    for (size_t ip = 0; ip < nParams; ++ip) {
      auto lError = roots.front() * dir[ip];
      auto rError = roots.back() * dir[ip];
      if (lError > rError) {
        std::swap(lError, rError);
      }
      if (lError < leftErrColumn->toDouble(ip)) {
        if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
          g_log.debug() << "  left for  " << ip << ' ' << lError << ' ' << leftErrColumn->toDouble(ip) << std::endl;
        }
        leftErrColumn->fromDouble(ip, lError);
      }
      if (rError > rightErrColumn->toDouble(ip)) {
        if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
          g_log.debug() << "  right for " << ip << ' ' << rError << ' ' << rightErrColumn->toDouble(ip) << std::endl;
        }
        rightErrColumn->fromDouble(ip, rError);
      }
    }
    // Output the quadratic estimate for comparrison.
    quadraticErrColumn->fromDouble(i, sqrt(V.get(i, i)));
  }
}
Example #13
0
/// Copy constructor
/// @param M :: The other matrix.
GSLMatrix::GSLMatrix(const GSLMatrix &M) {
  m_matrix = gsl_matrix_alloc(M.size1(), M.size2());
  gsl_matrix_memcpy(m_matrix, M.gsl());
}
Example #14
0
 /** Returns the number of rows in TNT-based matrix  */
 size_t GSLUtility::Rows(const GSLMatrix &m) const {
   return (m.dim2());
 }
Example #15
0
 /** Returns the number of columns in TNT-based matrix */
 size_t GSLUtility::Columns(const GSLMatrix &m) const {
   return (m.dim1());
 }