Class Expr

Nested Relationships

Nested Types

Inheritance Relationships

Base Type

  • public std::enable_shared_from_this< Expr >

Derived Types

Class Documentation

class Expr : public std::enable_shared_from_this<Expr>

Base expression class.

Expr represents the interface needed to form expression trees. Classes that represent expressions should publicly derive from this class. Each Expr on a tree has links to its children Expr objects. The lifetime of Expr objects is expected to be managed by std::shared_ptr . Expr is an Iterable over subexpressions (each of which is an Expr itself). More precisely, Expr meets the SizedIterable concept (see https://raw.githubusercontent.com/ericniebler/range-v3/master/doc/std/D4128.md). Specifically, iterators to subexpressions dereference to ExprPtr. Since Expr is a range, it provides begin/end/etc. that can participate in overloads with other functions in the derived class. Consider a Container class derived from a BaseContainer class:

template <typename T> class Container : public BaseContainer, public Expr
{
  // WARNING: BaseContainer::begin clashes with Expr::begin
  // WARNING: BaseContainer::end clashes with Expr::end
  // etc.
};
There are two possible scenarios:
  • if Container is a container of Expr objects, BaseContainer will iterate over ExprPtr objects already and both ranges will be equivalent; it is sufficient to add using BaseContainer::begin, etc. to Container’s public API.

  • if Container is a container of non-Expr objects, iteration over BaseContainer is likely to be more commonly used in practice, hence again adding using BaseContainer::begin, etc. will suffice. To be able to iterate over subexpression range (in this case it is empty) Expr provides Expr::expr member to cast to Expr:

    Container c(...);
    for(const auto& e: c) {  // iterates over elements of BaseContainer
    }
    for(const auto& e: c.expr()) {  // iterates over subexpressions
    }
    

Subclassed by sequant::NormalOperatorSequence< S >, sequant::Operator< S >, sequant::Operator< void, S >, sequant::Constant, sequant::NormalOperatorSequence< S >, sequant::Operator< S >, sequant::Power, sequant::Product, sequant::Sum, sequant::Tensor, sequant::Variable, sequant::mbpt::Operator< void, S >

Public Types

using hash_type = std::size_t
using type_id_type = int

Public Functions

Expr() = default
virtual ~Expr() = default
inline bool is_atom() const
Returns:

true if this is a leaf

inline virtual bool is_zero() const
Returns:

true if this is zero

virtual std::wstring to_latex() const
Returns:

the string representation of this in the LaTeX format

virtual ExprPtr clone() const = 0
Returns:

a clone of this object, i.e. an object that is equal to this

inline ExprPtr exprptr_from_this()

like Expr::shared_from_this, but returns ExprPtr

Returns:

a shared_ptr to this object wrapped into ExprPtr, if this object is already managed by a shared_ptr, else returns a shared_ptr to a clone of this object wrapped into ExprPtr

inline ExprPtr exprptr_from_this() const

like Expr::shared_from_this, but returns ExprPtr

Returns:

a shared_ptr to this object wrapped into ExprPtr, if this object is already managed by a shared_ptr, else returns a shared_ptr to a clone of this object wrapped into ExprPtr

inline virtual ExprPtr canonicalize(CanonicalizeOptions = CanonicalizeOptions::default_options())

Canonicalizes this and returns the byproduct of canonicalization (e.g. phase)

Returns:

the byproduct of canonicalization, or nullptr if no byproduct generated

inline virtual ExprPtr rapid_canonicalize(CanonicalizeOptions = CanonicalizeOptions::default_options().copy_and_set(CanonicalizationMethod::Rapid))

Performs approximate, but fast, canonicalization of this and returns the byproduct of canonicalization (e.g. phase) The default is to use canonicalize(), unless overridden in the derived class.

Returns:

the byproduct of canonicalization, or nullptr if no byproduct generated

template<typename Visitor>
inline bool visit(Visitor &&visitor, const bool atoms_only = false)

recursively visit this expression, i.e. call visitor on each subexpression in depth-first fashion.

See also

expr_range

Warning

this will only work for tree expressions; no checking is performed that each subexpression has only been visited once TODO make work for graphs

Template Parameters:

Visitor – a callable of type void(ExprPtr&) or void(const ExprPtr&)

Parameters:
  • visitor – the visitor object

  • atoms_only – if true, will visit only the leaves; the default is to visit all nodes

Returns:

true if this object was visited

template<typename Visitor>
inline bool visit(Visitor &&visitor, const bool atoms_only = false) const

const version of visit

inline Expr &expr()
inline const Expr &expr() const
inline virtual bool is_scalar() const

Reports if this is a pure scalar (number-like) expression.

Note

This is distinct from is_cnumber()

Warning

this returns false for all leaves by default, hence must be overridden for scalar leaf types.

Returns:

true if this is a scalar

inline virtual bool is_cnumber() const

Reports if this is a c-number (https://en.wikipedia.org/wiki/C-number), i.e. it commutes multiplicatively with c-numbers and q-numbers.

Note

for leaves this has O(1) cost, for non-leaves this involves checking subexpressions

Warning

this returns true for all leaves, hence must be overridden for leaf q-numbers

Returns:

true if this is a c-number

inline bool commutes_with(const Expr &that) const

Checks if this commutes (wrt multiplication) with that.

Note

the default implementation checks if either is c-number; if both are q-numbers this checks commutativity of each subexpression with (each subexpression of) that

Note

expressions are assumed to always commute with respect to additions since it does not appear that +nonabelian near-rings (https://en.wikipedia.org/wiki/Near-ring) are commonly needed.

Note

commutativity of leaves is checked by commutes_with_atom()

Returns:

true if this commutes with that

virtual void adjoint() = 0

changes this to its adjoint

inline hash_type hash_value(std::function<hash_type(const std::shared_ptr<const Expr>&)> hasher = {}) const

Computes and returns the hash value. If default hasher is used then the value will be memoized, otherwise hasher will be used to compute the hash every time.

Note

always returns 0 unless this derived class overrides Expr::memoizing_hash

Parameters:

hasher – the hasher object, if omitted, the default is used (

Returns:

the hash value for this Expr

virtual type_id_type type_id() const = 0

Computes and returns the derived type identifier

Returns:

the hash value for this Expr

template<typename T, typename = std::enable_if<is_an_expr_v<T>>>
inline bool operator<(const T &that) const

Note

the derived class must implement Expr::static_less_than

Template Parameters:

TExpr or a class derived from Expr

Returns:

true if *this is less than that

template<typename T>
inline bool is() const
Template Parameters:

T – an Expr type

Returns:

true if this object is of type T

template<typename T>
inline const T &as() const
Template Parameters:

T – an Expr type

Returns:

this object cast to type T

template<typename T>
inline T &as()
Template Parameters:

T – an Expr type

Returns:

this object cast to type T

inline std::string type_name() const

Note

uses RTTI

Returns:

the (demangled) name of this type

ExprIterator begin()
ExprIterator end()
ConstExprIterator begin() const
ConstExprIterator end() const
ConstExprIterator cbegin() const
ConstExprIterator cend() const
virtual ExprIterator begin_subexpr()
virtual ExprIterator end_subexpr()
virtual ConstExprIterator begin_subexpr() const
virtual ConstExprIterator end_subexpr() const
std::size_t size() const
bool empty() const
ExprPtr &operator[](std::size_t idx)

unchecked element access

Note

the bounds check is only performed if SEQUANT_ASSERT_ENABLED is #defined; use at() for a bounds check that is always performed

const ExprPtr &operator[](std::size_t idx) const

unchecked element access

Note

the bounds check is only performed if SEQUANT_ASSERT_ENABLED is #defined; use at() for a bounds check that is always performed

ExprPtr &at(std::size_t idx)

checked element access

Throws:

Exception – if idx is not less than size()

const ExprPtr &at(std::size_t idx) const

checked element access

Throws:

Exception – if idx is not less than size()

ExprPtr &front()
Throws:

Exception – if this Expr is empty (e.g. is an atom)

const ExprPtr &front() const
Throws:

Exception – if this Expr is empty (e.g. is an atom)

ExprPtr &back()
Throws:

Exception – if this Expr is empty (e.g. is an atom)

const ExprPtr &back() const
Throws:

Exception – if this Expr is empty (e.g. is an atom)

Public Static Functions

template<typename T>
static inline type_id_type get_type_id()
Returns:

(unique) type id of class T

template<typename T>
static inline void set_type_id(type_id_type id)

sets (unique) type id of class T

Note

since get_type_id does not check for duplicates, it’s user’s responsiblity to make sure that there are no collisions between type ids

Parameters:

id – the value of type id of class T

Protected Functions

Expr(Expr&&) = default
Expr(const Expr&) = default
Expr &operator=(Expr&&) = default
Expr &operator=(const Expr&) = default
inline virtual hash_type memoizing_hash() const
inline virtual void reset_hash_value() const
virtual bool static_equal(const Expr &that) const = 0

Note

that is guaranteed to be of same type as *this, hence can be statically cast

Parameters:

that – an Expr object

Returns:

true if that is equivalent to *this

inline virtual bool static_less_than(const Expr &that) const

Note

that is guaranteed to be of same type as *this, hence can be statically cast

Note

base comparison compares Expr::hash_value() , specialize to each type as needed

Parameters:

that – an Expr object

Returns:

true if *this is less than that

inline virtual bool commutes_with_atom(const Expr &that) const

Note

*this and that are guaranteed to be leaves, and neither is a c-number , hence honest checking is needed

Note

this returns true unless overridden in derived class

Parameters:

that – an Expr object

Returns:

true if *this multiplicatively commutes with that

Protected Attributes

mutable std::optional<hash_type> hash_value_

Friends

inline friend bool operator==(const Expr &a, const Expr &b)
Returns:

true if a is equal to b

template<typename T, typename Enabler = void>
struct is_shared_ptr_of_expr : public std::false_type
template<>
struct is_shared_ptr_of_expr<ExprPtr, void> : public std::true_type
template<typename T, typename Enabler = void>
struct is_shared_ptr_of_expr_or_derived : public std::false_type
template<>
struct is_shared_ptr_of_expr_or_derived<ExprPtr, void> : public std::true_type