Mantid
Loading...
Searching...
No Matches
FunctionFactory.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 +
13#include "MantidAPI/IFunction.h"
17#include "MantidAPI/Workspace.h"
21#include <boost/lexical_cast.hpp>
22#include <sstream>
23
24namespace Mantid::API {
25
27 // we need to make sure the library manager has been loaded before we
28 // are constructed so that it is destroyed after us and thus does
29 // not close any loaded DLLs with loaded algorithms in them
31}
32
34 IFunction_sptr fun = create(type);
35 fun->initialize();
36 return fun;
37}
38
52 Expression expr;
53 try {
54 expr.parse(input);
55 } catch (Expression::ParsingError &e) {
56 inputError(input + "\n " + e.what());
57 } catch (...) {
58 inputError(input);
59 }
60
61 const Expression &e = expr.bracketsRemoved();
62 std::map<std::string, std::string> parentAttributes;
63 if (e.name() == ";") {
64 IFunction_sptr fun = createComposite(e, parentAttributes);
65 if (!fun)
66 inputError();
67 return fun;
68 }
69
70 return createSimple(e, parentAttributes);
71}
72
86std::shared_ptr<MultiDomainFunction>
87FunctionFactoryImpl::createInitializedMultiDomainFunction(const std::string &input, size_t domainNumber) const {
88 auto singleFunction = createInitialized(input);
89 auto multiDomainFunction = std::make_shared<MultiDomainFunction>();
90
91 if (!singleFunction) {
92 return multiDomainFunction;
93 }
94
95 for (size_t i = 0; i < domainNumber; ++i) {
96 multiDomainFunction->addFunction(singleFunction->clone());
97 multiDomainFunction->setDomainIndex(i, i);
98 }
99
100 return multiDomainFunction;
101}
102
111 std::map<std::string, std::string> &parentAttributes) const {
112 if (expr.name() == "=" && expr.size() > 1) {
113 return createFunction(expr.terms()[1].name());
114 }
115
116 if (expr.name() != "," || expr.size() == 0) {
117 inputError(expr.str());
118 }
119
120 const std::vector<Expression> &terms = expr.terms();
121 auto term = terms.cbegin();
122
123 if (term->name() != "=")
124 inputError(expr.str());
125 if (term->terms()[0].name() != "name" && term->terms()[0].name() != "composite") {
126 throw std::invalid_argument("Function name must be defined before its parameters");
127 }
128 std::string fnName = term->terms()[1].name();
129
130 IFunction_sptr fun = createFunction(fnName);
131 for (++term; term != terms.end(); ++term) { // loop over function's parameters/attributes
132 if (term->name() != "=")
133 inputError(expr.str());
134 std::string parName = term->terms()[0].name();
135 std::string parValue = term->terms()[1].str();
136 if (fun->hasAttribute(parName)) {
137 // set attribute
138 if (parValue.size() > 1 && parValue[0] == '"') {
139 // remove the double quotes
140 parValue = parValue.substr(1, parValue.size() - 2);
141 }
142 IFunction::Attribute att = fun->getAttribute(parName);
143 att.fromString(parValue);
144 fun->setAttribute(parName, att);
145 } else if (parName.size() >= 10 && parName.substr(0, 10) == "constraint") {
146 // or it can be a list of constraints
147 addConstraints(fun, (*term)[1].bracketsRemoved());
148 } else if (parName == "ties") {
149 addTies(fun, (*term)[1].bracketsRemoved());
150 } else if (!parName.empty() && parName[0] == '$') {
151 parName.erase(0, 1);
152 parentAttributes[parName] = parValue;
153 } else {
154 // set initial parameter value
155 try {
156 fun->setParameter(parName, boost::lexical_cast<double>(parValue));
157 } catch (boost::bad_lexical_cast &) {
158 throw std::runtime_error(std::string("Error in value of parameter ")
159 .append(parName)
160 .append(".\n")
161 .append(parValue)
162 .append(" cannot be interpreted as a floating point value."));
163 }
164 }
165 } // for term
166
167 fun->applyTies();
168 return fun;
169}
170
180 std::map<std::string, std::string> &parentAttributes) const {
181 if (expr.name() != ";")
182 inputError(expr.str());
183
184 if (expr.size() == 0) {
185 return CompositeFunction_sptr();
186 }
187
188 const std::vector<Expression> &terms = expr.terms();
189 auto it = terms.cbegin();
190 const Expression &term = it->bracketsRemoved();
191
193 if (term.name() == "=") {
194 if (term.terms()[0].name() == "composite") {
195 cfun = std::dynamic_pointer_cast<CompositeFunction>(createFunction(term.terms()[1].name()));
196 if (!cfun)
197 inputError(expr.str());
198 ++it;
199 } else if (term.terms()[0].name() == "name") {
200 cfun = std::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction"));
201 if (!cfun)
202 inputError(expr.str());
203 } else {
204 inputError(expr.str());
205 }
206 } else if (term.name() == ",") {
207 auto firstTerm = term.terms().cbegin();
208 if (firstTerm->name() == "=") {
209 if (firstTerm->terms()[0].name() == "composite") {
210 cfun = std::dynamic_pointer_cast<CompositeFunction>(createSimple(term, parentAttributes));
211 if (!cfun)
212 inputError(expr.str());
213 ++it;
214 } else if (firstTerm->terms()[0].name() == "name") {
215 cfun = std::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction"));
216 if (!cfun)
217 inputError(expr.str());
218 } else {
219 inputError(expr.str());
220 }
221 }
222 } else if (term.name() == ";") {
223 cfun = std::dynamic_pointer_cast<CompositeFunction>(createFunction("CompositeFunction"));
224 if (!cfun)
225 inputError(expr.str());
226 } else {
227 inputError(expr.str());
228 }
229
230 if (!cfun)
231 inputError(expr.str());
232
233 for (; it != terms.end(); ++it) {
234 const Expression &currentTerm = it->bracketsRemoved();
235 IFunction_sptr fun;
236 std::map<std::string, std::string> pAttributes;
237 if (currentTerm.name() == ";") {
238 fun = createComposite(currentTerm, pAttributes);
239 if (!fun)
240 continue;
241 } else {
242 std::string parName = currentTerm[0].name();
243 if (parName.size() >= 10 && parName.substr(0, 10) == "constraint") {
244 addConstraints(cfun, currentTerm[1].bracketsRemoved());
245 continue;
246 } else if (parName == "ties") {
247 addTies(cfun, currentTerm[1].bracketsRemoved());
248 continue;
249 } else {
250 fun = createSimple(currentTerm, pAttributes);
251 }
252 }
253 cfun->addFunction(fun);
254 size_t i = cfun->nFunctions() - 1;
255 for (auto &pAttribute : pAttributes) {
256 // Apply parent attributes of the child function to this function. If this
257 // function doesn't have those attributes, they get passed up the chain to
258 // this function's parent.
259 if (cfun->hasLocalAttribute(pAttribute.first)) {
260 cfun->setLocalAttributeValue(i, pAttribute.first, pAttribute.second);
261 } else {
262 parentAttributes[pAttribute.first] = pAttribute.second;
263 }
264 }
265 }
266
267 if (cfun) {
268 cfun->applyTies();
269 }
270 return cfun;
271}
272
274void FunctionFactoryImpl::inputError(const std::string &str) const {
275 std::string msg("Error in input string to FunctionFactory");
276 if (!str.empty()) {
277 msg += "\n" + str;
278 }
279 throw std::invalid_argument(msg);
280}
281
292 if (expr.name() == ",") {
293 for (auto it = expr.begin(); it != expr.end(); ++it) {
294 // If this is a penalty term, we used it on the previous iteration
295 // so we move on to the next term.
296 auto constraint = (*it);
297 std::string constraint_term = constraint.terms()[0].str();
298 if (constraint_term.compare("penalty") == 0) {
299 continue;
300 }
301
302 if ((it + 1) != expr.end()) {
303 auto next_constraint = *(it + 1);
304 std::string next_term = next_constraint.terms()[0].str();
305 if (next_term.compare("penalty") == 0) {
306 addConstraint(fun, constraint, next_constraint);
307 } else {
308 addConstraint(fun, constraint);
309 }
310 } else {
311 addConstraint(fun, constraint);
312 }
313 }
314 } else { // There was a single constraint given, cannot contain a penalty
315 addConstraint(fun, expr);
316 }
317}
318
324void FunctionFactoryImpl::addConstraint(const std::shared_ptr<IFunction> &fun, const Expression &expr) const {
325 auto c = std::unique_ptr<IConstraint>(ConstraintFactory::Instance().createInitialized(fun.get(), expr));
326 c->setPenaltyFactor(c->getDefaultPenaltyFactor());
327 fun->addConstraint(std::move(c));
328}
329
336void FunctionFactoryImpl::addConstraint(const std::shared_ptr<IFunction> &fun, const Expression &constraint_expr,
337 const Expression &penalty_expr) const {
338 auto c = std::unique_ptr<IConstraint>(ConstraintFactory::Instance().createInitialized(fun.get(), constraint_expr));
339 double penalty_factor = std::stof(penalty_expr.terms()[1].str(), NULL);
340 c->setPenaltyFactor(penalty_factor);
341 fun->addConstraint(std::move(c));
342}
343
349void FunctionFactoryImpl::addTies(const IFunction_sptr &fun, const Expression &expr) const {
350 if (expr.name() == "=") {
351 addTie(fun, expr);
352 } else if (expr.name() == ",") {
353 for (const auto &constraint : expr) {
354 addTie(fun, constraint);
355 }
356 }
357}
358
363void FunctionFactoryImpl::addTie(const IFunction_sptr &fun, const Expression &expr) const {
364 if (expr.size() > 1) { // if size > 2 it is interpreted as setting a tie (last
365 // expr.term) to multiple parameters, e.g
366 // f1.alpha = f2.alpha = f3.alpha = f0.beta^2/2
367 const std::string value = expr[expr.size() - 1].str();
368 for (size_t i = expr.size() - 1; i != 0;) {
369 --i;
370 fun->tie(expr[i].name(), value);
371 }
372 }
373}
374
375std::vector<std::string> FunctionFactoryImpl::getFunctionNamesGUI() const {
376 auto allNames = getFunctionNames<IFunction1D>();
377 auto ImmutableCompositeFunctions = getFunctionNames<ImmutableCompositeFunction>();
378 allNames.insert(allNames.end(), ImmutableCompositeFunctions.begin(), ImmutableCompositeFunctions.end());
379 allNames.emplace_back("ProductFunction");
380 allNames.emplace_back("CompositeFunction");
381 allNames.emplace_back("Convolution");
382 std::sort(allNames.begin(), allNames.end());
383 std::vector<std::string> names;
384 names.reserve(allNames.size());
385 auto excludes = Kernel::ConfigService::Instance().getString("curvefitting.guiExclude");
387 std::set<std::string> excludeList(tokenizer.begin(), tokenizer.end());
388 std::copy_if(allNames.cbegin(), allNames.cend(), std::back_inserter(names),
389 [&excludeList](const auto &name) { return excludeList.count(name) == 0; });
390 return names;
391}
392
393void FunctionFactoryImpl::subscribe(const std::string &className, std::unique_ptr<AbstractFactory> pAbstractFactory,
395 // Clear the cache, then do all the work in the base class method
396 m_cachedFunctionNames.clear();
397 Kernel::DynamicFactory<IFunction>::subscribe(className, std::move(pAbstractFactory), replace);
398}
399
400void FunctionFactoryImpl::unsubscribe(const std::string &className) {
401 // Clear the cache, then do all the work in the base class method
402 m_cachedFunctionNames.clear();
404}
405
406} // namespace Mantid::API
double value
The value of the point.
Definition: FitMW.cpp:51
Specialised exception for parsing errors.
Definition: Expression.h:39
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
const std::vector< Expression > & terms() const
Returns the top level terms of the expression (function arguments).
Definition: Expression.h:77
void parse(const std::string &str)
Parse a string and create an expression.
Definition: Expression.cpp:159
const Expression & bracketsRemoved() const
If the expression has 1 argument and empty function name it means it is wrapped in brackets This meth...
Definition: Expression.cpp:513
iterator end() const
An iterator pointing to the end of the expressions.
Definition: Expression.h:86
iterator begin() const
An iterator pointing to the start of the expressions.
Definition: Expression.h:84
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
std::shared_ptr< IFunction > createFunction(const std::string &type) const
Creates an instance of a function.
std::shared_ptr< MultiDomainFunction > createInitializedMultiDomainFunction(const std::string &input, size_t domainNumber) const
Creates an instnce of an inizialised multidomain function where each domain has the same function.
std::shared_ptr< CompositeFunction > createComposite(const Expression &expr, std::map< std::string, std::string > &parentAttributes) const
Create a composite function.
void addConstraints(const std::shared_ptr< IFunction > &fun, const Expression &expr) const
Add constraints to the created function.
std::vector< std::string > getFunctionNamesGUI() const
Get function names that can be used by generic fitting GUIs.
std::shared_ptr< IFunction > createSimple(const Expression &expr, std::map< std::string, std::string > &parentAttributes) const
Create a simple function.
void inputError(const std::string &str="") const
Throw an exception.
void unsubscribe(const std::string &className)
void subscribe(const std::string &className, std::unique_ptr< AbstractFactory > pAbstractFactory, Kernel::DynamicFactory< IFunction >::SubscribeAction replace=ErrorIfExists)
void addTies(const std::shared_ptr< IFunction > &fun, const Expression &expr) const
Add ties to the created function.
std::map< std::string, std::vector< std::string > > m_cachedFunctionNames
void addTie(const std::shared_ptr< IFunction > &fun, const Expression &expr) const
Add a tie to the created function.
void addConstraint(const std::shared_ptr< IFunction > &fun, const Expression &expr) const
Add a single constraint to the created function.
FunctionFactoryImpl()
Private Constructor for singleton class.
std::shared_ptr< IFunction > createInitialized(const std::string &input) const
Creates an instance of a function.
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
void fromString(const std::string &str)
Set value from a string.
Definition: IFunction.cpp:971
This is an interface to a fitting function - a semi-abstarct class.
Definition: IFunction.h:163
The dynamic factory is a base dynamic factory for serving up objects in response to requests from oth...
void subscribe(const std::string &className)
Registers the instantiator for the given class with the DynamicFactory.
void unsubscribe(const std::string &className)
Unregisters the given class and deletes the instantiator for the class.
virtual std::shared_ptr< IFunction > create(const std::string &className) const
Creates a new instance of the class with the given name.
SubscribeAction
Defines replacement behaviour.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Iterator begin()
Iterator referring to first element in the container.
@ TOK_TRIM
remove leading and trailing whitespace from tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
Mantid::Kernel::StringTokenizer tokenizer
Definition: Expression.cpp:17
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class