Class Result

Inheritance Relationships

Derived Types

Class Documentation

class Result

A type-erased class for the result of an evaluation. An object of this class can represent a tensor (eg. TA::DistArray, btas::Tensor, etc.) or a scalar (eg. double, std::complex etc.).

Subclassed by sequant::ResultScalar< T >, sequant::eval::dryrun::ResultDryRun, sequant::eval::dryrun::ResultDryRunNested

Public Types

using id_t = size_t

Public Functions

virtual ~Result() noexcept = default
inline virtual std::string trange_annot() const
Returns:

a compact, human-readable rendering of the backing tensor’s tiled range (for eval traces – lets a reader spot a sliced-vs-unsliced mode mismatch that a release build’s elided TA_ASSERT would otherwise let deadlock). Default empty for backends with no tiled range (e.g. DryRun).

template<typename T>
inline bool is() const noexcept
Returns:

Returns true if the concrete type of the object is T.

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

T const& where T is the concrete type of the object.

virtual ResultPtr sum(Result const&, std::array<std::any, 3> const&) const = 0

Sum other Result object with this object.

Note

In std::array<std::any, 3> is expected to be [l,r,res] where the elements are the annotations for left, right and result respectively.

virtual ResultPtr prod(Result const&, std::array<std::any, 3> const&, DeNest DeNestFlag) const = 0

Perform product binary operation with this object and other.

Note

In std::array<std::any, 3> is expected to be [l,r,res] where the elements are the annotations for left, right and result respectively.

virtual ResultPtr permute(std::array<std::any, 2> const&) const = 0

Permute this object according to the annotations in the argument.

Note

In std::array<std::any, 2> is expected to be [pre,post] where the elements are the annotations for the eval result before permutation and after permutation respectively.

inline virtual ResultPtr adjoint(std::array<std::any, 2> const&) const

Take the adjoint (complex-conjugate transpose) of this result.

Used to evaluate the EvalOp::Adjoint IR node — the unary op that holds a bare-label operand and emits T† = conj(T) permuted into the adjoint slot order. ann is [operand_annot, result_annot] (bra/ket swapped relative to the operand); backends with a real numeric type implement this as a pure permutation (conj is a no-op) and complex backends apply conj as well. Not a pure virtual: only tensor-backed results need it; the default throws. Mirrors the slice_mode precedent.

inline virtual ResultPtr pow(rational const&) const

Raise every element of this result to the power exponent.

Used to evaluate the EvalOp::Power IR node. Returns a fresh result of the same layout as this one (the node’s canon indices are its operand’s); this result is not modified. An integer exponent is exact (repeated multiplication, and the reciprocal for a negative exponent); any other goes through std::pow on the element type with the exponent converted to double (for complex elements, std::pow(std::complex, double)). A zero element raised to a negative power yields inf per IEEE; it is neither checked nor asserted. Not a pure virtual: only tensor-backed results need it; the default throws.

inline virtual ResultPtr broadcast(std::array<std::any, 2> const&, container::svector<ResultPtr> const&) const

Expand this result over the modes it lacks.

Used to evaluate the EvalOp::Broadcast IR node. Returns a fresh result over the modes of ann[1] that is constant along every mode absent from ann[0] and equals this result along the others. ann is [operand_annot, result_annot]; the result’s modes are a superset of this result’s. new_mode_ranges holds one rank-1 result per mode of the result that this result lacks (none if it lacks none), in the result’s mode order, built by BackendArrayOps::make_zeros (and restricted to the current batch when a batch loop runs over that mode): the result’s range along that mode is that result’s range. A mode this result carries keeps this result’s range. Not a pure virtual: only tensor-backed results need it; the default throws. A ResultScalar forwards to broadcast_scalar() of new_mode_ranges' first element.

inline virtual ResultPtr broadcast_scalar(Result const&, std::array<std::any, 2> const&, container::svector<ResultPtr> const&) const

Expand the scalar scalar over every mode of ann[1].

The broadcast() of a scalar operand (a ResultScalar), dispatched to the backend’s tensor type through the first of new_mode_ranges, which hold one rank-1 result per mode of the result (see broadcast()). Returns a fresh result every element of which is scalar's value; this result is not modified. Not a pure virtual: only tensor-backed results need it; the default throws.

inline virtual ResultPtr slice_mode(std::size_t, std::size_t, std::size_t) const

Restrict this result to a contiguous element range of one mode.

Keeps elements [elem_lo, elem_hi) of mode mode and all elements of every other mode. Element semantics keep this backend-neutral (no notion of tiles); a tiled backend may require [elem_lo, elem_hi) to fall on tile boundaries (mode_batches() returns such ranges). Used to evaluate a tensor network in batches over a contracted index (see make_batched_custom_evaluator): slicing every leaf that carries the index, evaluating, and summing reproduces the full contraction. Not a pure virtual: only tensor-backed results need it; the default throws.

inline virtual void write_into_slice(Result const&, std::size_t, std::size_t, std::size_t)

Scatter block into the [block_lo, block_hi) element slice of this result’s mode mode.

The inverse of slice_mode(): where slice_mode() gathers one contiguous element block out of a mode, write_into_slice() scatters a per-block result into a pre-sized destination’s [block_lo, block_hi) slice along outer mode, leaving every other mode untouched. Used to assemble a result that is evaluated one block at a time over a partitioned (Hadamard/spectator) mode: partitioning the mode into disjoint blocks, evaluating each, and write_into_slice()-ing each block into its slice reconstructs the whole result. Unlike add_inplace() (which accumulates, correct only for a contracted mode), the blocks are disjoint slices of one pre-sized result. Element semantics keep this backend-neutral (no notion of tiles); a tiled backend may require [block_lo, block_hi) to fall on tile boundaries and preserves each mode’s element lobound. Not a pure virtual: only tensor-backed results need it; the default throws. Mirrors the slice_mode() precedent.

virtual void add_inplace(Result const&) = 0

Add other Result object into this object.

inline virtual double norm2() const

Diagnostic: the Frobenius norm of the held value (0 for scalars and backends without a numeric norm). Default throws.

inline virtual std::string layout_desc() const

Diagnostic: a short description of the held value’s layout (e.g. the tiled range of an array). Default: empty.

inline virtual std::string tile_diff(Result const&) const

Diagnostic: tile-by-tile comparison with another value of the same kind: counts of tiles present (non-zero) only here / only there, and the norm of the difference restricted to those one-sided tiles. Default: empty.

virtual ResultPtr clone() const = 0

An independently owned deep copy of this result.

The copy shares no mutable state with this object: add_inplace() or write_into_slice() on either one leaves the other unchanged. Needed wherever an accumulation takes ownership of a buffer it does not own – the ordered executor’s Assemble step seeds its running sum from the first batch’s partial, which may still be read again (the producing cell has life left, or is persistent across evaluations) and so must not be mutated in place.

virtual ResultPtr symmetrize() const = 0

Particle symmetrize the eval result.

virtual ResultPtr antisymmetrize(size_t bra_rank) const = 0

Particle antisymmetrize the eval result.

bool has_value() const noexcept
virtual ResultPtr mult_by_phase(std::int8_t) const = 0
template<typename T>
inline T &get()

A result that is a pending view of another result’s storage (see is_buffer_alias()) materializes its value here first, once.

Template Parameters:

T, and – return a ref.

Returns:

Cast the type-erased data to the type

template<typename T>
inline T const &get() const

A result that is a pending view of another result’s storage (see is_buffer_alias()) materializes its value here first, once.

Template Parameters:

T, and – return a const ref.

Returns:

Cast the type-erased data to the type

inline virtual bool is_buffer_alias() const noexcept
Returns:

true while this result stands for a transformation of another result’s storage that has not been applied – a batch slice, a mode permutation, a conjugation, a scaling by a constant – and so shares that storage instead of holding its own: it costs no allocation, and a backend consumer that can take the transformation into its own expression does so instead of asking for the value. get<T>() applies it (once) on demand. Default: false (a value held).

virtual std::size_t size_in_bytes() const = 0
Returns:

the bytes of storage this result keeps alive that no other result accounts for: for a result that holds its own value, the value’s size. Storage shared between results (see is_buffer_alias()) is meant to be reported by exactly one of them; a backend that cannot tell which may approximate this, so a sum over results is exact only where results never share storage. Within SeQuant it feeds diagnostics (the eval trace, the peak monitor, the residency counts), not evaluation.

inline virtual std::size_t measured_size_in_bytes() const
Returns:

the size of the object in bytes, measured even where size_in_bytes() is switched off for cost: a backend whose measurement is collective (TiledArray’s) gates size_in_bytes() behind the eval trace, since the trace calls it on every op; the schedule document’s run record calls this once per production instead. Default: size_in_bytes().

inline virtual void fence() const noexcept

Diagnostic (analysis-only): force any deferred/asynchronous computation backing this result to complete. Default no-op (scalars are always ready); distributed-array backends override to fence their world. Used to make an otherwise lazily-executed op’s wall-clock timer capture execution rather than just dispatch, when SEQUANT_UT_FORCE_SYNC is set at the call site.

Protected Functions

template<typename T, typename = std::enable_if_t<!std::is_convertible_v<T, Result>>>
inline explicit Result(T &&arg) noexcept
Result() noexcept = default

a result without a value yet: a pending view (see is_buffer_alias()), which stores its value through set_value() when first asked for it

inline void set_value(std::any value) const noexcept

Stores value as this result’s value. Logically const: a pending view materializing itself does not change what the result stands for.

inline virtual void ensure_value() const

Called by get<T>() before the cast: a pending view materializes its value here (set_value()). Default no-op.

virtual id_t type_id() const noexcept = 0

Protected Static Functions

template<typename T>
static inline id_t id_for_type() noexcept