26constexpr double absoluteCutOff = 0.0;
27constexpr double effectiveCutOff = 0.0001;
28constexpr double epsilon = 1e-10;
30double calculatePoissonLoss(
double observedCounts,
double predicted) {
31 double retVal = (predicted - observedCounts);
32 retVal += observedCounts * (log(observedCounts) - log(predicted));
40namespace PoissonLossLM {
44 observedCounts = std::max(absoluteCutOff, observedCounts);
45 double retVal = (predicted - observedCounts);
46 if (predicted <= absoluteCutOff) {
47 return std::numeric_limits<double>::max();
50 if (observedCounts != 0) {
51 if (
const auto x = retVal / observedCounts; std::abs(
x) < effectiveCutOff) {
53 return observedCounts * (
x *
x) * (0.5 - (
x / 3.0) + (
x *
x) / 4.0);
56 retVal += observedCounts * (log(observedCounts) - log(predicted));
61 if (predicted <= absoluteCutOff) {
62 return std::numeric_limits<double>::max();
64 const double delta = predicted - observedCounts;
67 if (observedCounts == absoluteCutOff) {
68 return predicted > epsilon ? signDelta / std::sqrt(2.0 * predicted) : signDelta / epsilon;
71 if (
const auto x =
delta / observedCounts; std::abs(
x) < effectiveCutOff) {
72 return (1.0 / std::sqrt(observedCounts)) * (1.0 - (2.0 / 3.0) *
x + (7.0 / 12.0) * (
x *
x));
75 return signDelta * (1 - observedCounts / predicted) * 1 /
100 size_t ny = values->size();
104 for (
size_t i = 0; i < ny; i++) {
105 const double predicted = values->getCalculated(i);
107 if (predicted <= absoluteCutOff) {
108 retVal = std::numeric_limits<double>::infinity();
112 const double observed = values->getFitData(i);
113 if (predicted <= effectiveCutOff) {
114 retVal += (effectiveCutOff - predicted) / predicted;
115 }
else if (observed == 0.0) {
119 retVal += calculatePoissonLoss(observed, predicted);
138 const size_t numParams =
nParams();
155 const size_t numParams = function.
nParams();
156 const size_t numDataPoints = domain.
size();
158 Jacobian jacobian(numDataPoints, numParams);
162 size_t activeParamIndex = 0;
163 double costVal = 0.0;
165 for (
size_t paramIndex = 0; paramIndex < numParams; ++paramIndex) {
169 double determinant = 0.0;
170 for (
size_t i = 0; i < numDataPoints; ++i) {
174 if (calc <= absoluteCutOff) {
175 if (activeParamIndex == 0) {
176 costVal += std::numeric_limits<double>::infinity();
178 determinant += std::numeric_limits<double>::infinity();
182 if (calc <= effectiveCutOff) {
183 if (activeParamIndex == 0) {
184 costVal += (effectiveCutOff - calc) / (calc - absoluteCutOff);
186 double tmp = calc - absoluteCutOff;
187 determinant += jacobian.
get(i, paramIndex) * (absoluteCutOff - effectiveCutOff) / (
tmp *
tmp);
189 }
else if (obs == 0.0) {
190 if (activeParamIndex == 0) {
193 determinant += jacobian.
get(i, paramIndex);
196 if (activeParamIndex == 0) {
197 costVal += calculatePoissonLoss(obs, calc);
199 determinant += jacobian.
get(i, paramIndex) * (1.0 - obs / calc);
203 double der =
m_der.
get(activeParamIndex);
204 m_der.
set(activeParamIndex, der + determinant);
215 size_t numParams = function.
nParams();
216 size_t numDataPoints = domain.
size();
218 Jacobian jacobian(numDataPoints, numParams);
221 size_t activeParamFirstIndex = 0;
222 for (
size_t paramIndex = 0; paramIndex < numParams; ++paramIndex) {
226 size_t activeParamSecondIndex = 0;
229 double scalingFactor = 1e-4;
230 if (parameter != 0.0) {
231 scalingFactor *= parameter;
234 function.
setParameter(paramIndex, parameter + scalingFactor);
235 Jacobian jacobian2(numDataPoints, numParams);
239 for (
size_t j = 0; j <= paramIndex; ++j)
244 for (
size_t k = 0; k < numDataPoints; ++k)
246 double d2 = (jacobian2.
get(k, j) - jacobian.
get(k, j)) / scalingFactor;
250 if (calc <= absoluteCutOff) {
251 d += std::numeric_limits<double>::infinity();
253 if (calc <= effectiveCutOff) {
254 double constrainedCalc = calc - absoluteCutOff;
255 d += d2 * (absoluteCutOff - effectiveCutOff) / (constrainedCalc * constrainedCalc);
256 d += jacobian.
get(k, paramIndex) * jacobian.
get(k, j) * (effectiveCutOff - absoluteCutOff) * 2 /
257 (constrainedCalc * constrainedCalc * constrainedCalc);
258 }
else if (obs == 0.0) {
261 d += d2 * (1.0 - obs / calc);
262 d += jacobian.
get(k, paramIndex) * jacobian.
get(k, j) * obs / (calc * calc);
267 double h =
m_hessian.
get(activeParamFirstIndex, activeParamSecondIndex) +
d;
268 m_hessian.
set(activeParamFirstIndex, activeParamSecondIndex, h);
269 if (activeParamFirstIndex != activeParamSecondIndex) {
270 m_hessian.
set(activeParamSecondIndex, activeParamFirstIndex, h);
273 ++activeParamSecondIndex;
275 ++activeParamFirstIndex;
#define DECLARE_COSTFUNCTION(classname, username)
Macro for declaring a new type of cost functions to be used with the CostFunctionFactory.
#define PARALLEL_CRITICAL(name)
Base class that represents the domain of a function.
virtual size_t size() const =0
Return the number of points in the domain.
A class to store values calculated by a function.
double getFitData(size_t i) const
Get a fitting data value.
double getCalculated(size_t i) const
Get i-th calculated value.
This is an interface to a fitting function - a semi-abstarct class.
virtual void functionDeriv(const FunctionDomain &domain, Jacobian &jacobian)
Derivatives of function with respect to active parameters.
virtual size_t nParams() const =0
Total number of parameters.
bool isActive(size_t i) const
Check if an active parameter i is actually active.
virtual double getParameter(size_t i) const =0
Get i-th parameter.
virtual void setParameter(size_t, const double &value, bool explicitlySet=true)=0
Set i-th parameter.
virtual void function(const FunctionDomain &domain, FunctionValues &values) const =0
Evaluates the function for all arguments in the domain.
Represents the Jacobian in IFitFunction::functionDeriv.
virtual double get(size_t iY, size_t iP)=0
Get the value to a Jacobian matrix element.
A semi-abstract class for a cost function for fitting functions.
size_t nParams() const override
Number of parameters.
API::IFunction_sptr m_function
Shared pointer to the fitting function.
CostFuncPoisson : Implements a cost function for fitting applications using a Poisson measure.
void calculateHessian(API::IFunction &function, const API::FunctionDomain &domain, const API::FunctionValues &values) const
Calculates the Hessian matrix for the addValDerivHessian method.
void addValDerivHessian(API::IFunction_sptr function, API::FunctionDomain_sptr domain, API::FunctionValues_sptr values, bool evalDeriv=true, bool evalHessian=true) const override
Update the cost function, derivatives and hessian by adding values calculated on a domain.
void addVal(API::FunctionDomain_sptr domain, API::FunctionValues_sptr values) const override
Add a contribution to the cost function value from the fitting function evaluated on a particular dom...
void calculateDerivative(API::IFunction &function, const API::FunctionDomain &domain, API::FunctionValues &values) const
Calculates the derivative for the addValDerivHessian method.
void set(size_t i, size_t j, double value)
Set an element.
double get(size_t i, size_t j) const
Get an element.
void zero()
Set all elements to zero.
void resize(const size_t nx, const size_t ny)
Resize the matrix.
void set(const size_t i, const double value)
Set an element.
double get(const size_t i) const
Get an element.
void resize(const size_t n)
Resize the vector.
std::shared_ptr< FunctionValues > FunctionValues_sptr
typedef for a shared pointer
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< FunctionDomain > FunctionDomain_sptr
typedef for a shared pointer
template MANTID_CURVEFITTING_DLL int sgn< double >(double val)
double calculatePoissonResidualLM(double observedCounts, double predicted)
double MANTID_CURVEFITTING_DLL calculateJacobianScaleFactor(double observedCounts, double predicted)
double MANTID_CURVEFITTING_DLL calculatePoissonLossLM(double observedCounts, double predicted)