Commit 60aa3a99 authored by Roman Tolchenov's avatar Roman Tolchenov
Browse files

Added parameter ties. re #965

parent e501dfef
......@@ -264,6 +264,10 @@
RelativePath=".\src\MemoryManager.cpp"
>
</File>
<File
RelativePath=".\src\ParameterTie.cpp"
>
</File>
<File
RelativePath=".\src\ParInstrument.cpp"
>
......@@ -486,6 +490,10 @@
RelativePath=".\inc\MantidAPI\MemoryManager.h"
>
</File>
<File
RelativePath=".\inc\MantidAPI\ParameterTie.h"
>
</File>
<File
RelativePath=".\inc\MantidAPI\ParInstrument.h"
>
......
......@@ -66,6 +66,8 @@ public:
double getParameter(const std::string& name)const;
/// Total number of parameters
int nParams()const;
/// Returns the index of parameter name
int parameterIndex(const std::string& name)const;
/// Returns the name of parameter i
std::string parameterName(int i)const;
......@@ -82,15 +84,28 @@ public:
/// Returns the name of active parameter i
std::string nameOfActive(int i)const;
/// Check if a parameter is active
bool isActive(int i)const;
/// Removes a parameter from the list of active
void removeActive(int i);
/// Get active index for a declared parameter i
int activeIndex(int i)const;
/// Add a function
void addFunction(IFunction* f);
/// Returns the pointer to i-th function
IFunction* getFunction(int i);
IFunction* getFunction(int i)const;
/// Number of functions
int nFunctions(){return m_functions.size();}
int nFunctions()const{return m_functions.size();}
private:
double m_tst;
/// Get the function index
int functionIndex(int i)const;
/// Get the function index
int functionIndexActive(int i)const;
/// Extract function index and parameter name from a variable name
static void parseName(const std::string& varName,int& index, std::string& name);
/// Pointers to the included funtions
std::vector<IFunction*> m_functions;
......@@ -98,12 +113,16 @@ private:
std::vector<int> m_activeOffsets;
/// Individual function parameter offsets
std::vector<int> m_paramOffsets;
/// Keeps the function number for each parameter
/// Keeps the function number for each declared parameter
std::vector<int> m_iFunction;
/// Keeps the function number for each active parameter
std::vector<int> m_iFunctionActive;
/// Number of active parameters
int m_nActive;
/// Total number of parameters
int m_nParams;
//friend class ParameterTie;
};
} // namespace API
......
......@@ -26,6 +26,7 @@ namespace API
//----------------------------------------------------------------------
class MatrixWorkspace;
class Jacobian;
class ParameterTie;
/** An interface to a function.
......@@ -62,7 +63,7 @@ public:
/// Assignment operator
IFunction& operator=(const IFunction&);
/// Virtual destructor
virtual ~IFunction() {}
virtual ~IFunction();
/// Function initialization. Declare function parameters in this method.
virtual void init() = 0;
......@@ -84,11 +85,13 @@ public:
virtual double getParameter(const std::string& name)const;
/// Total number of parameters
virtual int nParams()const{return m_parameters.size();};
/// Returns the index of parameter name
virtual int parameterIndex(const std::string& name)const;
/// Returns the name of parameter i
virtual std::string parameterName(int i)const;
/// Number of active (in terms of fitting) parameters
virtual int nActive()const{return m_indexMap.size() ? m_indexMap.size() : nParams();}
virtual int nActive()const{return m_indexMap.size();}
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
virtual double activeParameter(int i)const;
/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
......@@ -100,6 +103,18 @@ public:
/// Returns the name of active parameter i
virtual std::string nameOfActive(int i)const;
/// Check if a declared parameter i is active
virtual bool isActive(int i)const;
/// Removes a declared parameter i from the list of active
virtual void removeActive(int i);
/// Get active index for a declared parameter i
virtual int activeIndex(int i)const;
/// Tie a parameter to other parameters (or a constant)
virtual void tie(const std::string& parName,const std::string& expr);
/// Apply the ties
virtual void applyTies();
protected:
/// Declare a new parameter
virtual void declareParameter(const std::string& name,double initValue = 0);
......@@ -111,6 +126,8 @@ private:
std::vector<std::string> m_parameterNames;
/// Keeps parameter values
std::vector<double> m_parameters;
/// Holds parameter ties
std::map<int,ParameterTie*> m_ties;
};
/** Represents the Jacobian in functionDeriv.
......
#ifndef MANTID_API_PARAMETERTIE_H_
#define MANTID_API_PARAMETERTIE_H_
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/DllExport.h"
namespace mu
{
class Parser;
}
namespace Mantid
{
namespace API
{
class DLLExport IFunction;
/** Ties fitting parameters.
@author Roman Tolchenov, Tessella Support Services plc
@date 28/10/2009
Copyright &copy; 2009 STFC Rutherford Appleton Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class DLLExport ParameterTie
{
public:
/// Constructor
ParameterTie(IFunction* funct,const std::string& parName);
/// Destructor
~ParameterTie();
/// Set the tie expression
void set(const std::string& expr);
/// Evaluate the expression
double eval();
/// The index of the tied parameter
int index()const{return m_iPar;}
private:
/// MuParser callback function
static double* ParameterTie::AddVariable(const char *varName, void *palg);
mu::Parser* m_parser; ///< math parser
IFunction* m_function; ///< Pointer to the function which parameter is to be tied
int m_iPar; ///< index of the tied parameter
};
} // namespace API
} // namespace Mantid
#endif /*MANTID_API_PARAMETERTIE_H_*/
......@@ -4,6 +4,7 @@
#include "MantidAPI/CompositeFunction.h"
#include "MantidKernel/Exception.h"
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
......@@ -69,13 +70,14 @@ void CompositeFunction::function(double* out, const double* xValues, const int&
*/
class PartialJacobian: public Jacobian
{
Jacobian* m_J;///< pointer to the overall Jacobian
Jacobian* m_J; ///< pointer to the overall Jacobian
int m_iP0; ///< offset in the overall Jacobian for a particular function
public:
/** Constructor
* @param J A pointer to the overall Jacobian
*/
PartialJacobian(Jacobian* J,int iP0):m_J(J),m_iP0(iP0){}
PartialJacobian(Jacobian* J,int iP0):m_J(J),m_iP0(iP0)
{}
/**
* Overridden Jacobian::set(...).
* @param iY The index of the data point
......@@ -83,7 +85,7 @@ public:
*/
void set(int iY, int iP, double value)
{
m_J->set(iY,m_iP0 + iP,value);
m_J->set(iY,m_iP0 + iP,value);
}
};
......@@ -93,7 +95,7 @@ void CompositeFunction::functionDeriv(Jacobian* out, const double* xValues, cons
if (nData <= 0) return;
for(int i=0;i<nFunctions();i++)
{
PartialJacobian J(out,m_activeOffsets[i]);
PartialJacobian J(out,m_paramOffsets[i]);
m_functions[i]->functionDeriv(&J,xValues,nData);
}
}
......@@ -104,7 +106,7 @@ void CompositeFunction::calJacobianForCovariance(Jacobian* out, const double* xV
if (nData <= 0) return;
for(int i=0;i<nFunctions();i++)
{
PartialJacobian J(out,m_activeOffsets[i]);
PartialJacobian J(out,m_paramOffsets[i]);
m_functions[i]->calJacobianForCovariance(&J,xValues,nData);
}
}
......@@ -113,33 +115,43 @@ void CompositeFunction::calJacobianForCovariance(Jacobian* out, const double* xV
/// Address of i-th parameter
double& CompositeFunction::parameter(int i)
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
return m_functions[ iFun ]->parameter(i - m_activeOffsets[iFun]);
int iFun = functionIndex(i);
return m_functions[ iFun ]->parameter(i - m_paramOffsets[iFun]);
}
/// Address of i-th parameter
double CompositeFunction::parameter(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
return m_functions[ iFun ]->parameter(i - m_activeOffsets[iFun]);
int iFun = functionIndex(i);
return m_functions[ iFun ]->parameter(i - m_paramOffsets[iFun]);
}
/// Get parameter by name.
double& CompositeFunction::getParameter(const std::string& name)
{
throw Kernel::Exception::NotImplementedError("CompositeFunction::getParameter is not implemented");
return m_tst;
std::string pname;
int index;
parseName(name,index,pname);
if (index < 0)
throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
else
{
return getFunction(index)->getParameter(pname);
}
}
/// Get parameter by name.
double CompositeFunction::getParameter(const std::string& name)const
{
throw Kernel::Exception::NotImplementedError("CompositeFunction::getParameter is not implemented");
return m_tst;
std::string pname;
int index;
parseName(name,index,pname);
if (index < 0)
throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
else
{
return getFunction(index)->getParameter(pname);
}
}
/// Total number of parameters
......@@ -148,13 +160,26 @@ int CompositeFunction::nParams()const
return m_nParams;
}
/**
* This method is undefined for CompositeFunction
* @param name The name of a parameter
*/
int CompositeFunction::parameterIndex(const std::string& name)const
{
std::string pname;
int index;
parseName(name,index,pname);
if (index < 0)
throw std::invalid_argument("CompositeFunction::getParameter: parameter name must contain function index");
return m_paramOffsets[index] + getFunction(index)->parameterIndex(pname);
}
/// Returns the name of parameter i
std::string CompositeFunction::parameterName(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
return m_functions[ iFun ]->parameterName(i - m_activeOffsets[iFun]);
int iFun = functionIndex(i);
return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}
/// Number of active (in terms of fitting) parameters
......@@ -166,18 +191,14 @@ int CompositeFunction::nActive()const
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
double CompositeFunction::activeParameter(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
int iFun = functionIndexActive(i);
return m_functions[ iFun ]->activeParameter(i - m_activeOffsets[iFun]);
}
/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
void CompositeFunction::setActiveParameter(int i, double value)
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
int iFun = functionIndexActive(i);
return m_functions[ iFun ]->setActiveParameter(i - m_activeOffsets[iFun],value);
}
......@@ -188,32 +209,66 @@ void CompositeFunction::updateActive(const double* in)
{
m_functions[ iFun ]->updateActive(in + m_activeOffsets[ iFun ]);
}
applyTies();
}
/// Returns "global" index of active parameter i
int CompositeFunction::indexOfActive(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
int iFun = functionIndexActive(i);
return m_paramOffsets[ iFun ] + m_functions[ iFun ]->indexOfActive(i - m_activeOffsets[iFun]);
}
/// Returns the name of active parameter i
std::string CompositeFunction::nameOfActive(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
int iFun = m_iFunction[i];
int iFun = functionIndexActive(i);
return m_functions[ iFun ]->nameOfActive(i - m_activeOffsets[iFun]);
}
/**
* Returns true if parameter i is active
* @param i The index of a declared parameter
*/
bool CompositeFunction::isActive(int i)const
{
int iFun = functionIndex(i);
return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}
/**
* @param i A declared parameter index to be removed from active
*/
void CompositeFunction::removeActive(int i)
{
int iFun = functionIndex(i);
int ia = m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
m_iFunctionActive.erase(m_iFunctionActive.begin()+ia);
m_functions[ iFun ]->removeActive(i - m_paramOffsets[iFun]);
--m_nActive;
for(int j=iFun+1;j<nFunctions();j++)
m_activeOffsets[j] -= 1;
}
/**
* @param i The index of a declared parameter
* @return The index of declared parameter i in the list of active parameters or -1
* if the parameter is tied.
*/
int CompositeFunction::activeIndex(int i)const
{
int iFun = functionIndex(i);
return m_activeOffsets[iFun] + m_functions[iFun]->activeIndex(i - m_paramOffsets[iFun]);
}
/** Add a function
* @param f A pointer to the added function
*/
void CompositeFunction::addFunction(IFunction* f)
{
m_iFunction.insert(m_iFunction.end(),f->nParams(),m_functions.size());
m_iFunctionActive.insert(m_iFunctionActive.end(),f->nActive(),m_functions.size());
m_functions.push_back(f);
//?f->init();
if (m_paramOffsets.size() == 0)
......@@ -232,7 +287,10 @@ void CompositeFunction::addFunction(IFunction* f)
}
}
IFunction* CompositeFunction::getFunction(int i)
/**
* @param i The index of the function
*/
IFunction* CompositeFunction::getFunction(int i)const
{
if ( i >= nFunctions() )
throw std::out_of_range("Function index out of range.");
......@@ -240,5 +298,56 @@ IFunction* CompositeFunction::getFunction(int i)
return m_functions[i];
}
/**
* Get the index of the function to which parameter i belongs
* @param i The parameter index
*/
int CompositeFunction::functionIndex(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
return m_iFunction[i];
}
/**
* Get the index of the function to which parameter i belongs
* @param i The active parameter index
*/
int CompositeFunction::functionIndexActive(int i)const
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
return m_iFunctionActive[i];
}
/**
* @param varName The variable name which may contain function index ( [f<index.>]name )
* @param index Receives function index or -1
* @param name Receives the parameter name
*/
void CompositeFunction::parseName(const std::string& varName,int& index, std::string& name)
{
size_t i = varName.find('.');
if (i == std::string::npos)
{
name = varName;
index = -1;
return;
}
else
{
if (varName[0] != 'f')
throw std::invalid_argument("External function parameter name must start with 'f'");
std::string sindex = varName.substr(1,i-1);
index = boost::lexical_cast<int>(sindex);
if (i == varName.size() - 1)
throw std::invalid_argument("Name cannot be empty");
name = varName.substr(i+1);
}
}
} // namespace API
} // namespace Mantid
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/IFunction.h"
#include "MantidKernel/Exception.h"
#include "MantidAPI/IFunction.h"
#include "MantidAPI/ParameterTie.h"
#include <sstream>
#include <iostream>
......@@ -29,7 +30,15 @@ IFunction& IFunction::operator=(const IFunction& f)
return *this;
}
/** Update parameters
/// Destructor
IFunction::~IFunction()
{
for(std::map<int,ParameterTie*>::iterator it = m_ties.begin();it != m_ties.end(); it++)
delete it->second;
m_ties.clear();
}
/** Update active parameters. Ties are applied.
* @param in Pointer to an array with active parameters values.
*/
void IFunction::updateActive(const double* in)
......@@ -39,9 +48,12 @@ void IFunction::updateActive(const double* in)
{
setActiveParameter(i,in[i]);
}
// apply ties
applyTies();
}
/**
* Sets active parameter i to value. Ties are not applied.
*/
void IFunction::setActiveParameter(int i,double value)
{
int j = indexOfActive(i);
......@@ -112,6 +124,25 @@ double IFunction::getParameter(const std::string& name)const
return m_parameters[it - m_parameterNames.begin()];
}
/**
* Returns the index of the parameter named name.
* @param name The name of the parameter.
*/
int IFunction::parameterIndex(const std::string& name)const
{
std::string ucName(name);
//std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(),m_parameterNames.end(),ucName);
if (it == m_parameterNames.end())
{
std::ostringstream msg;
msg << "Function parameter ("<<ucName<<") does not exist.";
throw std::invalid_argument(msg.str());
}
return int(it - m_parameterNames.begin());
}
/** Returns the name of parameter i
* @param i The index of a parameter
*/
......@@ -139,6 +170,7 @@ void IFunction::declareParameter(const std::string& name,double initValue )
throw std::invalid_argument(msg.str());
}
m_indexMap.push_back(nParams());
m_parameterNames.push_back(ucName);
m_parameters.push_back(initValue);
}
......@@ -149,13 +181,6 @@ void IFunction::declareParameter(const std::string& name,double initValue )
*/
int IFunction::indexOfActive(int i)const
{
if (m_indexMap.empty())
{
if (i < nParams()) return i;
else
throw std::out_of_range("Function parameter index out of range.");
}
if (i >= nActive())
throw std::out_of_range("Function parameter index out of range.");
......@@ -171,6 +196,79 @@ std::string IFunction::nameOfActive(int i)const
return m_parameterNames[indexOfActive(i)];
}
/**
* Returns true if parameter i is active
* @param i The index of a declared parameter
*/
bool IFunction::isActive(int i)const
{
return std::find(m_indexMap.begin(),m_indexMap.end(),i) != m_indexMap.end();
}
/**
* @param i A declared parameter index to be removed from active
*/
void IFunction::removeActive(int i)
{
if (i >= nParams())
throw std::out_of_range("Function parameter index out of range.");
if (m_indexMap.size() == 0)
{