Expressions and variables
Expressions
The abstract type of any node type in the expression tree is given by a simple virtual struct:
template <typename T>
struct expr {
T val{}; ///< The value of this expression node.
/// Construct an expr object with given value.
explicit constexpr expr(const T& v) noexcept : val(v) {}
virtual constexpr ~expr() {}
/// Bind a value pointer for writing the derivative during propagation
virtual constexpr void bind_value(std::shared_ptr<void>) {}
/// Update the contribution of this expression in the derivative of the root node of the expression tree.
/// @param wprime The derivative of the root expression node w.r.t. the child expression of this expression node.
virtual constexpr void propagate(std::shared_ptr<void>) = 0;
/// Update the value of this expression
virtual constexpr void update() = 0;
}; /// struct expr
Variables
This is the variable struct:
template <typename T>
struct variable {
using value_t = T;
expr_ptr<value_t> expr; //< The pointer to the expression tree of variable operations
/// Construct a default variable object
constexpr variable() noexcept : variable(0.0) {}
/// Construct a copy of a variable object
constexpr variable(const variable& other) noexcept : variable(other.expr) {}
/// Construct a copy of a variable object
constexpr variable(variable&& other) noexcept : variable(std::move(other.expr)) {}
/// Construct a variable object with given arithmetic value
template <typename U>
constexpr variable(const U& val) noexcept :
expr(std::make_shared<independent_variable_expr<value_t>>(val)) {}
/// Construct a variable object with given expression
constexpr variable(const expr_ptr<value_t>& e) noexcept :
expr(std::make_shared<dependent_variable_expr<value_t>>(e)) {}
/// Destruct a variable object
constexpr ~variable() {}
/// Assign an arithmetic value to this variable.
template <typename U>
constexpr variable& operator=(const U& val) noexcept {
return *this = variable(val);
}
/// Assign an expression to this variable.
constexpr variable& operator=(const expr_ptr<value_t>& x) noexcept {
return *this = variable(x);
}
/// Default copy assignment
constexpr variable& operator=(const variable& x) noexcept {
this->expr = x.expr;
return *this;
}
/// Implicitly convert this variable object into an expression pointer.
constexpr operator const expr_ptr<value_t>&() const {
return this->expr;
}
/// Implicitly convert this variable object into an arithmetic value.
constexpr explicit operator value_t() const {
return this->expr->val;
}
/// Update the value of this variable with changes in its expression tree
constexpr void update() {
this->expr->update();
}
/// Update the value of this variable with a given arithmetic value
constexpr void update(T value) {
if (auto independent_expr = std::dynamic_pointer_cast<independent_variable_expr<value_t>>(this->expr)) {
independent_expr->val = value;
independent_expr->update();
} else
throw std::logic_error("Cannot update the value of a dependent expression stored in a variable");
}
}; // struct variable