API Reference
The parametric library API consists of the following parts:
parametric/core.hpp: the core API everything required tp build up compute graphs.
parametric/dag.hpp: the DAG API provides functions and classes to build up directed acyclic graphs.
parametric/operators.hpp: the header file adds provides parametric operator overloads
All functions and types provided by the library reside in namespace parametric.
Core
parametric/core.hpp defines everything required to build up compute graphs.
The main building blocks are parmetric values (parametric::param), compute nodes (parametric::ComputeNode)
and interface parameters(parametric::InterfaceParam).
The role of each object is described at the design concept section.
-
template<typename T, typename S = DefaultSerializer>
class param This class encapsulates an arbitrary type to be used as a parameter.
A parameter is an object with a value and a valid state. Whenever its value has been changed, it propagates this invalidation to all dependent parameters, requiring their recomputation.
Public Functions
-
inline param(const std::string &id, const T &v)
Creates a valid parameter from a value and an identifier.
After construction, the parameter is valid (it contains a value)
-
inline explicit param(const std::string &id)
Creates a invalid parameter with an identifier.
After construction, the parameter is invalid (it does not contain a value)
-
inline const NodeRef compute_node() const
returns a shared_ptr to the compute node, if this param is a computation result. If it is an independent parameter, the returned pointer will be null.
- Returns:
const NodeRef
-
inline void set_value(const T &value)
Sets the value of the parameter.
The value will only be changed only, if the new value is different than the old one. The parameter will be valid after setting the value.
Note: The check for difference is done using the != operator. If a custom class does not provide this operator, it can be added on global scope e.g.
bool operator(const MyClass& c1, const MyClass& c2) { return ... }
- Parameters:
value – The value to be set.
-
inline param &operator=(const T &other)
Sets the value of the parameter, see param::set_value.
-
inline std::string id() const
Gets the identifier of the parameter.
-
inline void set_id(const std::string &id)
Sets the identifier of the parameter.
-
inline bool is_valid() const
Indicates, whether the parameter contains a value (valid) or not (invalid)
-
inline param(const std::string &id, const T &v)
Warning
doxygenfunction: Unable to resolve function “parametric::new_param” with arguments (const T&, const std::string&) in doxygen xml output for project “parametric” from directory: /home/runner/work/parametric/parametric/build/docs/doxygen/xml. Potential matches:
- template<class T, typename S = DefaultSerializer> param<T, S> new_param()
- template<class T, typename S = DefaultSerializer> param<T, S> new_param(const T &v)
- template<class T, typename S = DefaultSerializer> param<T, S> new_param(const std::string &id, const T &v)
-
template<class T, typename S = DefaultSerializer>
param<T, S> parametric::new_param(const T &v) Convenience function to create a parameter of type T with value v.
-
template<class T, typename S = DefaultSerializer>
param<T, S> parametric::new_param() Convenience function to create an empty parameter of and identifier id.
-
template<class T, typename S, typename ...Args>
parametric::param<T> parametric::new_parametric_struct(const T &the_struct, const parametric::param<Args, S>&... parametric_members) This function creates a parametric version from a structure or an object that consists of parameters.
It propagates mutation of the member parameters to the object itself.
The first argument is the structure/object to be wrapped, the following arguments are all parameters, which the object depends on
Here’s an example:
struct AStruct { parametric::param<int> a{10, "a"}; parametric::param<int> b{100, "a"}; }; auto structSum = [](const AStruct& s) -> int { return s.a.value() + s.b.value(); }; AStruct s; auto parametricS = parametric::new_parametric_struct(s, s.a, s.b); auto sum = parametric::eval(structSum, parametricS);
The best practice is to create a helper function for each structure that contains parameters by creating a template specialization of parametric::new_param as follows:
template<> parametric::param<AStruct> parametric::new_param(const AStruct& s) { return parametric::new_parametric_struct(s, s.a, s.b); }
-
template<typename Fn, typename S, typename ...Args>
decltype(auto) parametric::eval(Fn wrapped_function, const parametric::param<Args, S>&... parameterArgs) This function creates a parametric version from a “normal” function.
The first argument is the function to be wrapped It accepts a variable list of input arguments, each must be a parameter
Here’s an example:
double mult(double a, double b) { return a * b; } parametric::param<double> a = parametric::new_param(2.0); parametric::param<double> b = parametric::new_param(10.0); auto result = parametric::eval(mult, a, b);
-
template<typename Derived, typename Results = ignore, typename Arguments = ignore>
class ComputeNode : public parametric::ClonableDAGNode<Derived>, public std::enable_shared_from_this<ComputeNode<Derived, ignore, ignore>> This class is the base class to define arbitrary compute nodes.
A compute node has to
inherit from parametric::ComputeNode<YourClass, parametric::Results<ResultType1, ResultType2, …>, parametric::Arguments<ArgType1, ArgType2, …>>
be constructed with parametric::compute
A compute node may
override the ComputeNode::eval method to perform the computation
customize parametric::compute by
providing a custom void connect_inputs(args…) function to connect inputs to the compute node
providing a custom R initialize_results() function to initialize the output parameters
providing a custom void connect_results(R const&) function to connect the outputs to the compute node
providing a custom void post_connect() callback to perform some customization after the compute node has been connected to its inputs and outputs, e.g. setting default ids.
A compute node may have any number of inputs and outputs
After a compute node has been connected to its inputs and outputs, argument parameters can be queried with ComputeNode::arg<i>() in the overwritten methods.
Pointers to a result can be queried with ComputeNode::res<i>(). Since it may be possible that a result goes out of scope before the compute node, pointers queried with ComputeNode::res<i>() may be nullptr. This should be checked in the overriden methods before using the pointer.
Example:
// define computing node class DivComputer : public parametric::ComputeNode<DivComputer, parametric::Results<double>, parametric::Arguments<double, double>> { void eval() const override { if (auto result = res<0>(); result) { result->set_value(arg<0>().value() / arg<1>().value()); } } void post_connect const override { if (auto result = res<0>(); result) { result->set_id("reosonable_default_id"); } } };
The DivComputer compute node is then used as follows
auto p1 = parametric::new_param(2.0, "p1"); auto p2 = parametric::new_param(5.0, "p2"); auto res = parametric::compute<DivComputer>(p1, p2);
Public Functions
-
template<typename ...Args>
inline void connect_inputs(Args&&... args) default implementation for connecting the inputs to the outputs.
This function may be provided by the derived class to customize the behavior of parametric::compute
- Template Parameters:
Args – arguments forwarded from parametric::compute
- Parameters:
args – input arguments that shall be connected to the compute node
-
inline compute_return_value<Results> initialize_results()
default implementation for initializing the results of the compute node
This function may be provided by the derived class to customize the behavior of parametric::compute
-
inline void connect_results(compute_return_value<Results> const &res)
default implementation for connecting the results of the compute node to the compute node.
This function may be provided by the derived class to customize the behavior of parametric::compute
- Parameters:
res – The results as returned by initialize_results
-
inline void post_connect() const
override this method as a post connection callback.
This method will be called immediately after the compute node has been connected to its inputs and outputs. It can be used to set a default id for the outputs using arg<i>() and res<i>().
-
inline virtual void eval() const
override this method to perform the calculation.
-
template<typename value_type, typename S = DefaultSerializer>
inline decltype(auto) arg(int i) const returns the i-th input argument. This function must be called after the compute node has been connected to its inputs via parametric::compute. It ignores the Argument list and expects the argument type to be specified by the user.
Caution: UB if the value_type does not match the actual type of the i-th argument!
- Template Parameters:
value_type – the value_type of the i-th argument.
- Parameters:
i – the index of the input argument.
- Returns:
A reference to an input parameter
-
template<int i>
inline decltype(auto) arg() const returns the i-th input argument. This function must be called after the compute node has been connected to its inputs via parametric::compute.
- Template Parameters:
i – the index of the input argument.
- Returns:
A reference to an input parameter
-
template<typename value_type, typename S = DefaultSerializer>
inline decltype(auto) res(int i) const returns a pointer to the i-th output argument. The function must be called after the compute node has been connected to its outputs via parametric::compute.
If the output parameter has already been deleted, the returned pointer will be null. This should be checked before using the pointer. This overload ignores the Result list and requires the user to specify the type of the i-th result
Caution: UB if the value_type does not match the actual type of the i-th result!
Example:
if (auto result = res<double>(0); result) { result->set_value(arg<double>(0).value() + arg<double>(1).value()); }
- Template Parameters:
i – the index of the output argument.
- Returns:
A shared_ptr to the output parameter
-
template<int i>
inline decltype(auto) res() const returns a pointer to the i-th output argument. The function must be called after the compute node has been connected to its outputs via parametric::compute.
If the output parameter has already been deleted, the returned pointer will be null. This should be checked before using the pointer.
Example:
if (auto result = res<0>(); result) { result->set_value(arg<0>().value() + arg<1>().value()); }
- Template Parameters:
i – the index of the output argument.
- Returns:
A shared_ptr to the output parameter
-
inline decltype(auto) args_tuple() const
A convenience function that collects the input arguments in a tuple.
This can be used to forward the input arguments to std::apply for instance.
- Returns:
A tuple of the evaluated input arguments.
Warning
doxygenfunction: Unable to resolve function “parametric::compute” with arguments (std::shared_ptr<C> const&, param<Args> const&…) in doxygen xml output for project “parametric” from directory: /home/runner/work/parametric/parametric/build/docs/doxygen/xml. Potential matches:
- template<typename C, typename ...Args> decltype(auto) compute(std::shared_ptr<C> const &ptr, Args&&... args)
- template<typename C, typename S, typename ...Args> decltype(auto) compute(param<Args, S> const&... args)
Warning
doxygenfunction: Unable to resolve function “parametric::compute” with arguments (param<Args> const&…) in doxygen xml output for project “parametric” from directory: /home/runner/work/parametric/parametric/build/docs/doxygen/xml. Potential matches:
- template<typename C, typename ...Args> decltype(auto) compute(std::shared_ptr<C> const &ptr, Args&&... args)
- template<typename C, typename S, typename ...Args> decltype(auto) compute(param<Args, S> const&... args)
DAG
-
typedef std::shared_ptr<parametric::DAGNode> parametric::NodeRef
A shared pointer to a DAG node.
-
class DAGNode
This class provides a basis node of a directed acyclic graph (DAG)
It provides all required methods to connect multiple nodes to a larger graph.
Design Considerations: In the current design, child nodes own their parent nodes. This makes it possible to hold a pointer to a child node keeping the whole graph alive.
Subclassed by parametric::ClonableDAGNode< Derived >
Public Types
Public Functions
-
inline DAGNode(const std::string &id)
DAGNode Constructs the node with an identifier. The id does not have to be unique.
- Parameters:
id – The identifier of the node.
-
inline virtual std::string serialize() const
This virtual function can be overwritten for serializing and deserializing nodes to std::string.
- Returns:
std::string
-
inline std::string id() const
Returns the identifier of the node.
- Returns:
The id as a string
-
inline void set_id(const std::string &id)
Sets the identifier of the node.
- Parameters:
id – The identifier string.
-
inline bool precedes(const DAGNode &node) const
Checks, whether “node” precides the current node in the DAG.
- Parameters:
node – The node to be checked
- Returns:
True, if node precedes this node.
-
template<typename Visitor>
inline void accept(Visitor &v, size_t depth = 0, Direction dir = Direction::down) const This provides an interface for the visitor pattern to walk through the whole DAG down from this node.
- Parameters:
v – The Visitor that is applied on each node during traversal
depth – The current depth of traversal
dir – The direction of traversal (either up or down)
-
template<typename Visitor>
inline void accept(Visitor &v, size_t depth = 0, Direction dir = Direction::down) This provides an interface for the visitor pattern to walk through the whole DAG down from this node.
- Parameters:
v – The Visitor that is applied on each node during traversal
depth – The current depth of traversal
dir – The direction of traversal (either up or down)
-
inline void remove_parent(const DAGNode &parent)
Removes the node “parent” from the current node.
- Parameters:
parent – The node to be removed
-
inline size_t num_parents() const
returns the number of parents
-
inline size_t num_children() const
returns the number of children
-
inline void invalidate()
Invalidates this node and all other childs.
-
inline virtual void eval() const
This method is internally used to evaluate the state of the node.
-
inline virtual bool IsValid() const
Returns whether the node is in a valid state.
This function deep-copies a node together with all of its ancestors, while maintaining parent-child-relations.
The optional input cloned_nodes is used to keep track of the already cloned nodes. This way redundant clones can be avoided.
Friends
-
inline friend void add_parent(const NodeRef &child, const NodeRef &parent)
Adds the node “parent” as parent to the node “child”.
The list of children is unique, but the list of parents may contain duplicates. The rationale behind this is that a compute node could have the same parent for different arguments, e.g. b = a*a, but a parent must only invalidate their children once.
- Parameters:
child – The node to which “parent” is added as a parent.
parent – The parent node to be added.
child – The node to which “parent” is added as a parent.
parent – The parent node to be added.
-
inline DAGNode(const std::string &id)
Operators
This file contains the parametric variant of arithmetic functions and their operator overloads.
Functions
-
template<class T1, class T2>
auto operator+(const parametric::param<T1> &a, const parametric::param<T2> &b)
-
template<class T1, class T2>
auto operator*(const parametric::param<T1> &a, const parametric::param<T2> &b)
-
namespace parametric
Objects to adapt to legacy code that does not yet use parameters yet
Functions
-
template<class T1, class T2>
auto p_add(const parametric::param<T1> &a, const parametric::param<T2> &b)
-
template<class T1, class T2>
auto p_mult(const parametric::param<T1> &a, const parametric::param<T2> &b)
-
template<class T1, class T2>