A function can be parametrised by variables as well as functions. Easiest way to achieve type agnostic expression is by inheriting from the same base class.
Function base class implementation options: purely virtual, only determines interface (methods). Use
- polymorphism (abstract base class),
- templated function pointer for more flexible functions?
Function class: the most generic function. Data members:
- function pointer,
- vector of base class pointers as arguments to function.
Variables (parameters/observables) are linear functions. Possible underlying datastructures:
- inherit directly from base class: a double, or vector of 1 double,
- inherit from function: linear function with a double (overkill?).
- Final: Use separate class with a double.
Types of variables: continuous, discrete, boolean, category
- value: implemented by
variable
. - boolean: implemented by
boolean
. - discrete: derive from
function_base
,variable
, orfunction
? To be consistent with the variable implementation, probably should derive from it and special case discretisation (enum in computing parlance). - category: this is more like a variable that partitions a dataset into subsets.
- variables with 0 range (min = max = val),
- variables bound to values (
boost::bind
).
Fixed signature: (number of args, arg array), (vector of args).
Bind user provided function pointer to standard interface internally. Not clear how to handle the input of arbitrary function signature w/o templates.
- Declaration w/ templates:
function(fptr_t<t1,t2> fptr, fnbase_ptr_vec);
- Declaration w/o templates (pseudo-code with Boost.MPL):
function(fptr_t fptr, boost::mpl::list<t1,t2> types, fnbase_ptr_vec);
This probably will never work, since
fptr_t
has to have a known signature at compile time. - Bind the user-function signature with the standard interface using
std::bind
orboost::bind
.
Do not take function parameters as pointers. Make copies inside the constructor.
Global mathematical operator overloads:
- [X] assignment:
operator=
, - [X] addition & subtraction (binary):
res = lhs +/- rhs
, - [X] sign (unary, -ve):
res = - obj
, - [X] multiplication & division:
res = lhs *// rhs
, - [ ] multiplication & division (with doubles):
res = num *// obj
, - [ ] exponentiation:
operator^
(okay since bitwise OR isn’t defined).
It is not clear what should be the implementation for comparison operators: equal to, less than, or geater than. Memory level comparisons are provided by pointer/reference comparisons, or dependency tree comparison.
Which of the following make more sense:
- scan range, or
- evaluate at point?
- Ask for function objects for integrands, and integrals.
- Each integral associated with a set of integration variables.
- GSL
- ROOT
- Boost.Numeric.Odeint
- All of the above as user configurable backends?
- Convert numerical integral into a function. Integrate once and save
as I(x) = ∫f(x’)dx’ (a,x), where a is the lower bound and x is any
value less than the upper bound, b. Then any arbitrary range ∈(a,b)
can be evaluated by two function calls.
- Look into primitive of a function (suggested by: Koen, and Pieter)
- Ask user for inflection points and kinks. Then can integrate in ranges in b/w the points. Maybe even have a way to auto-find them when not specified (quick scan in steps of 0.01 of range).
- State “DONE” from “TODO” [2013-10-17 Thu 22:34]
C++ testing switched to Boost.Test.
- C++: Boost.Test
- Python:
unittest
Test concepts:
- [X] Uniqueness of components
sum = (x+y) + (x+y) x → z ⇒ sum → sum + 2*(z-x)
- [ ] Possibility of copies in components
sum = (x+y) + (x'+y') (where the 2nd x+y is a copy) x → z ⇒ sum → sum + (z-x)
- [ ] Test with different functions
- Hash the component-tree.
- Should be possible to update only modified branches of the tree.
- Look at git tree objects for ideas.
- Caveat: hash function should be faster than evaluation.
- See Merkle tree,
std::hash
from<functional>
.
Use generic TFitter to build an interface to Minuit.
Boost.Log
Need tools that can take objects and print (to file or stdout) dependency information. The dependency tree traversal should be both ways: dependants as well as dependencies. Maybe limit to one hop, or ask for number of hops when instantiating the debugger.
- Implement getter and setters such that they are easily translateable to python properties with Boost.Python.
- Revisit inheritance hierarchy from the perspective of bindings.