Mantid
Loading...
Searching...
No Matches
BoundaryConstraint.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
13#include "MantidAPI/IFunction.h"
14#include "MantidKernel/Logger.h"
15#include <boost/lexical_cast.hpp>
16#include <sstream>
17
19namespace {
21Kernel::Logger g_log("BoundaryConstraint");
22} // namespace
23
24DECLARE_CONSTRAINT(BoundaryConstraint)
25
26// using namespace Kernel;
27using namespace API;
30 : API::IConstraint(), m_penaltyFactor(getDefaultPenaltyFactor()), m_hasLowerBound(false), m_hasUpperBound(false),
31 m_lowerBound(DBL_MAX), m_upperBound(-DBL_MAX) {}
32
35BoundaryConstraint::BoundaryConstraint(const std::string &paramName)
36 : API::IConstraint(), m_penaltyFactor(getDefaultPenaltyFactor()), m_hasLowerBound(false), m_hasUpperBound(false) {
37 UNUSED_ARG(paramName);
38}
39
49BoundaryConstraint::BoundaryConstraint(API::IFunction *fun, const std::string &paramName, const double lowerBound,
50 const double upperBound, bool isDefault)
51 : m_penaltyFactor(getDefaultPenaltyFactor()), m_hasLowerBound(true), m_hasUpperBound(true),
52 m_lowerBound(lowerBound), m_upperBound(upperBound) {
53 reset(fun, fun->parameterIndex(paramName), isDefault);
54}
55
56BoundaryConstraint::BoundaryConstraint(API::IFunction *fun, const std::string &paramName, const double lowerBound,
57 bool isDefault)
58 : m_penaltyFactor(getDefaultPenaltyFactor()), m_hasLowerBound(true), m_hasUpperBound(false),
59 m_lowerBound(lowerBound), m_upperBound(-DBL_MAX) {
60 reset(fun, fun->parameterIndex(paramName), isDefault);
61}
62
72void BoundaryConstraint::initialize(API::IFunction *fun, const API::Expression &expr, bool isDefault) {
73 if (expr.size() < 2 || expr.name() != "==") {
74 g_log.error("Wrong initialization expression");
75 throw std::invalid_argument("Wrong initialization expression");
76 }
78 const Expression &terms(expr);
79
80 std::vector<double> values(3);
81 int ilow = -1;
82 int ihi = -1;
83 std::string parName;
84 for (size_t i = 0; i < terms.size(); i++) {
85 std::string name = terms[i].str();
86 try {
87 auto d = boost::lexical_cast<double>(name);
88 values[i] = d;
89 std::string op = terms[i].operator_name();
90 if (op.empty()) {
91 op = terms[i + 1].operator_name();
92 if (op[0] == '<') {
93 ilow = static_cast<int>(i);
94 } else if (op[0] == '>') {
95 ihi = static_cast<int>(i);
96 } else {
97 g_log.error("Unknown operator in initialization expression");
98 throw std::invalid_argument("Unknown operator in initialization expression");
99 }
100 } // if empty
101 else {
102 if (op[0] == '<') {
103 ihi = static_cast<int>(i);
104 } else if (op[0] == '>') {
105 ilow = static_cast<int>(i);
106 } else {
107 g_log.error("Unknown operator in initialization expression");
108 throw std::invalid_argument("Unknown operator in initialization expression");
109 }
110 } // if not empty
111 } catch (boost::bad_lexical_cast &) {
112 if (!parName.empty()) {
113 g_log.error("Non-numeric value for a bound");
114 throw std::invalid_argument("Non-numeric value for a bound");
115 }
116 parName = name;
117 }
118 } // for i
119
120 try {
121 size_t i = fun->parameterIndex(parName);
122 reset(fun, i, isDefault);
123 } catch (...) {
124 g_log.error() << "Parameter " << parName << " not found in function " << fun->name() << '\n';
125 throw;
126 }
127
128 if (ilow >= 0) {
129 setLower(values[ilow]);
130 }
131 if (ihi >= 0) {
132 setUpper(values[ihi]);
133 }
134}
135
141 if (c <= 0.0) {
142 g_log.warning() << "Penalty factor <= 0 selected for boundary constraint."
143 << " Only positive penalty factor allowed. Penalty factor set to 1";
144 m_penaltyFactor = 1;
145 } else {
146 m_penaltyFactor = c;
147 }
148}
149
152 g_log.warning() << "No bounds have been set on BoundaryConstraint for parameter " << parameterName()
153 << ". Therefore"
154 << " this constraint serves no purpose!";
155 return;
156 }
157
158 double paramValue = getParameter();
159
160 if (m_hasLowerBound && paramValue < m_lowerBound)
162 if (m_hasUpperBound && paramValue > m_upperBound)
164}
165
168 g_log.warning() << "No bounds have been set on BoundaryConstraint for parameter " << parameterName()
169 << ". Therefore"
170 << " this constraint serves no purpose!";
171 return 0.0;
172 }
173
174 double paramValue = getParameter();
175
176 double penalty = 0.0;
177
178 if (m_hasLowerBound)
179 if (paramValue < m_lowerBound) {
180 double dp = m_lowerBound - paramValue;
181 penalty = m_penaltyFactor * dp * dp;
182 }
183 if (m_hasUpperBound)
184 if (paramValue > m_upperBound) {
185 double dp = paramValue - m_upperBound;
186 penalty = m_penaltyFactor * dp * dp;
187 }
188
189 return penalty;
190}
191
193 double penalty = 0.0;
194
195 if (/*m_activeParameterIndex < 0 ||*/ !(m_hasLowerBound || m_hasUpperBound)) {
196 // no point in logging any warning here since checkDeriv() will always be
197 // called after
198 // check() is called
199 return penalty;
200 }
201
202 double paramValue = getParameter();
203
204 if (m_hasLowerBound)
205 if (paramValue < m_lowerBound) {
206 double dp = m_lowerBound - paramValue;
207 penalty = 2 * m_penaltyFactor * dp;
208 }
209 if (m_hasUpperBound)
210 if (paramValue > m_upperBound) {
211 double dp = paramValue - m_upperBound;
212 penalty = 2 * m_penaltyFactor * dp;
213 }
214
215 return penalty;
216}
217
219 double penalty = 0.0;
220
221 if (/*m_activeParameterIndex < 0 ||*/ !(m_hasLowerBound || m_hasUpperBound)) {
222 // no point in logging any warning here since checkDeriv() will always be
223 // called after
224 // check() is called
225 return penalty;
226 }
227
228 double paramValue = getParameter();
229
230 if (m_hasLowerBound)
231 if (paramValue < m_lowerBound)
232 penalty = 2 * m_penaltyFactor;
233 if (m_hasUpperBound)
234 if (paramValue > m_upperBound)
235 penalty = 2 * m_penaltyFactor;
236
237 return penalty;
238}
239
240std::string BoundaryConstraint::asString() const {
241 std::ostringstream ostr;
242 if (m_hasLowerBound) {
243 ostr << m_lowerBound << '<';
244 }
245 ostr << parameterName();
246 if (m_hasUpperBound) {
247 ostr << '<' << m_upperBound;
248 }
250 ostr << ",penalty=" << m_penaltyFactor;
251 }
252 return ostr.str();
253}
254
255} // namespace Mantid::CurveFitting::Constraints
#define DECLARE_CONSTRAINT(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
This class represents an expression made up of names, binary operators and brackets.
Definition: Expression.h:36
std::string name() const
Returns the name of the expression which is a function or variable name.
Definition: Expression.h:71
std::string operator_name() const
Returns the the expression's binary operator on its left.
Definition: Expression.h:74
std::string str() const
Returns this expression as a string.
Definition: Expression.cpp:469
size_t size() const
Returns the number of argumens.
Definition: Expression.h:79
An interface to a constraint.
Definition: IConstraint.h:26
static double getDefaultPenaltyFactor()
Return the value for default fitting penalties.
Definition: IConstraint.h:64
This is an interface to a fitting function - a semi-abstarct class.
Definition: IFunction.h:163
virtual std::string name() const =0
Returns the function's name.
virtual size_t parameterIndex(const std::string &name) const =0
Returns the index of parameter name.
bool isDefault() const
Returns the default value flag.
double getParameter() const
Get the value of the parameter.
void reset(IFunction *fun, std::size_t index, bool isDefault=false)
Reset the reference.
void setParameter(const double &value, bool isExplicitlySet=true)
Set the parameter.
std::string parameterName() const
Return parameter name in the owning function.
bool m_hasLowerBound
name of parameter you want to constraint
void setLower(const double &value)
Set lower bound value.
bool m_hasUpperBound
has a upper bound set true/false
double m_penaltyFactor
Penalty factor for the given boundary constraint.
void initialize(API::IFunction *fun, const API::Expression &expr, bool isDefault) override
Initialize the constraint from an expression.
std::string asString() const override
Return the string that can be used in this->initialize() to recreate this constraint.
double checkDeriv2() override
Returns the derivative of the penalty for each active parameter.
void setPenaltyFactor(const double &c) override
implement IConstraint virtual functions
void setParamToSatisfyConstraint() override
Set the parameters of IFitFunction to satisfy constraint.
void clearBounds()
Clear both bounds (lower and upper) at the same time.
void setUpper(const double &value)
Set upper bound value.
double checkDeriv() override
Returns the derivative of the penalty for each active parameter.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
Kernel::Logger g_log("ExperimentInfo")
static logger object