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 = std::uint64_t
using type_rank_type = std::uint8_t

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 opts = 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

bool is_canonical(const CanonicalizeOptions &opts = CanonicalizeOptions::default_options()) const

Note

always false if opts does not request Complete canonicalization, the only method whose result is the same for every spelling of an expression

Parameters:

opts – the canonicalization options

Returns:

true if this is the full canonical form that canonicalization with opts produced, and since then neither this nor any of its subexpressions has been mutated or replaced, nor have the contexts in effect changed (see current_contexts_version())

void mark_canonical(const CanonicalizeOptions &opts, std::uint64_t contexts_version = current_contexts_version()) const

records that this, with its subexpressions as they are now, is the full canonical form for opts, so that is_canonical(opts) holds until this or any of its subexpressions is mutated or replaced, or the contexts in effect change

Note

no-op if opts does not request Complete canonicalization

Warning

only to be called with the result of canonicalization with opts: canonicalization leaves an expression marked as canonical alone

Parameters:
  • opts – the canonicalization options

  • contexts_version – the value of current_contexts_version() when the canonicalization started; if it has changed since, the mark is not valid

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>
inline bool operator<(const T &that) const

Note

the derived class must implement Expr::static_less_than

Template Parameters:

T – Expr 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

Expr &operator[](const TreeIndex &idx)
Returns:

The subexpression identified by the given index

const Expr &operator[](const TreeIndex &idx) const
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

static inline constexpr type_id_type make_type_id(type_rank_type rank, std::string_view name)
Returns:

the type id of a type of rank rank named name : rank in the top 8 bits, the top 56 bits of fnv1a_64(name) below them

static inline constexpr type_rank_type type_rank_of(type_id_type id)

Returns:

the rank encoded in type id id

template<typename T>
static inline type_id_type get_type_id()

The id is make_type_id(rank, name), where rank is T::type_rank (a static constexpr Expr::type_rank_type) if T declares it, else Expr::default_type_rank , and name is sequant::type_name_of<T>(). Hence Expr::operator< orders unlike types by rank first. A type whose relative order must not depend on the compiler declares static constexpr std::string static_type_name(std::type_identity<Self> = {}); constexpr makes it usable in constant expressions, but is not required. A derived class inherits its base’s type_rank but not its name, so unless it declares its own name it gets the compiler-derived one. A type in an unnamed namespace declares a name if another translation unit may define one of the same name, since types are told apart by mangled name and such a pair would silently share an id.

Throws:

sequant::Exception – if a type of another mangled name already has this id

Returns:

the (unique) type id of class T

Public Static Attributes

static constexpr type_rank_type default_type_rank = 128

rank of an Expr type that does not declare type_rank

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

invalidates the memoized hash and the canonical mark

Note

to be called by every mutation of this object’s own data

inline void reset_canonical_mark() const

invalidates the canonical mark, see is_canonical()

Note

to be called by every mutation of this object’s own data that does not call reset_hash_value() (mutations of subexpressions, and their replacement, are detected without it)

inline void copy_canonical_mark(const Expr &other) const

copies the canonical mark of other

Pre:

the own data of *this is identical to that of other , and its subexpressions are copies (or clones) of those of other

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