Annotations (APIARY_* macros)

Note

Generated from the C++ headers by apiary --emit-cpp-docs-json.

APIARY_BUFFER_FROM(...)

Designate a free function (or static member) that takes the bound type and returns py::buffer_info describing its memory layout.

The codegen wraps the call in a .def_buffer([](T &self) { return helper(self); }) lambda. The helper is your responsibility — it has to know the concrete instantiation’s element type, rank, and stride representation, and produce a valid buffer_info.

namespace einsums::pybuf {
        template <typename T, size_t N, typename A>
        pybind11::buffer_info make(GeneralTensor<T, N, A> &t);
    }

    APIARY_BUFFER_PROTOCOL
    APIARY_BUFFER_FROM(einsums::pybuf::make)
    struct GeneralTensor { ... };

Note

pybind11 only, since the helper is written against pybind11’s API; under nanobind it is refused with the unsupported-on-target diagnostic. Prefer APIARY_BUFFER_PROTOCOL_STD, which works under both.

Parameters:
  • ... – the helper function name

APIARY_BUFFER_PROTOCOL

Enable the pybind11 buffer protocol for this class (required for NumPy zero-copy interop on tensor types).

Note

Implied by APIARY_BUFFER_FROM and APIARY_BUFFER_PROTOCOL_STD, which are what actually export a buffer; on its own it only flips the pybind11 class option, and under nanobind it does nothing.

APIARY_BUFFER_PROTOCOL_STD(...)

Standard-layout buffer protocol. The codegen emits a per-backend buffer exporter (a .def_buffer lambda under pybind11, a bf_getbuffer type slot under nanobind) that describes the object’s memory from the named member functions on the bound class. Either way memoryview(), numpy.asarray() and numpy.array() see the memory zero copy, and it implies APIARY_BUFFER_PROTOCOL.

All four method names are required. element_type names the class template parameter that gives the element type; the codegen substitutes it per instantiation when emitting the format string and sizeof().

template <typename T, typename Alloc>
  APIARY_EXPOSE
  APIARY_BUFFER_PROTOCOL_STD(
      data = data, rank = rank, dim = dim, stride = stride,
      element_type = T)
  struct GeneralRuntimeTensor { ... };

The named methods must satisfy:

  • T*       data(); // pointer to first element

  • size_t   rank() const;

  • size_t   dim(int) const; // dim along an axis

  • size_t   stride(int) const; // stride in element units

Note

Stride conversion to byte units happens inside the codegen lambda.

Parameters:
  • ... – key = value assignments naming data, rank, dim, stride, and element_type

APIARY_DETAIL_ANNOTATE(payload)

Expand a payload to a Clang annotate attribute; a no-op on non-Clang compilers.

Parameters:
  • payload – string literal payload appended after the apiary: prefix

APIARY_DOC(text)

Override the docstring extracted from the doxygen comment block above this declaration.

Parameters:
  • text – string literal docstring to use instead

APIARY_DYNAMIC_ATTR

Allow Python instances to carry arbitrary attributes (py::dynamic_attr()).

APIARY_EXCEPTION

Mark a class as a Python exception type rather than a regular bound class.

The codegen emits py::register_exception<T>(m, "name") (pybind11) or nb::exception<T>(m, "name") (nanobind) instead of a class_<T>. Both need only a what() returning the message.

class APIARY_EXPOSE
          APIARY_EXCEPTION
          TensorError : public std::exception { ... };

Subsequent raise einsums.TensorError(...) from Python (or throw einsums::TensorError("...") from C++) crosses the boundary cleanly.

APIARY_EXPOSE

Mark a declaration for binding. Without this, the codegen tool ignores it.

APIARY_GETTER(py_name)

Bind a method as the getter of a Python property.

Parameters:
  • py_name – string literal naming the Python property

APIARY_HIDE

Suppress binding for a declaration that would otherwise be exposed.

Note

For example, an inherited member from a base flagged APIARY_EXPOSE.

APIARY_HOLDER(...)

Override the pybind11 holder type. Default is std::unique_ptr.

Note

Under nanobind, std::shared_ptr and std::unique_ptr need no holder (its smart-pointer casters work for any bound class), and any other holder is refused with the unsupported-on-target diagnostic.

Parameters:
  • ... – the holder type, e.g. APIARY_HOLDER(std::shared_ptr)

APIARY_IMPLICIT_FROM(...)

Register a one-way implicit conversion from Source to the annotated class.

Emits py::implicitly_convertible<Source, Class>() after the class definition. Useful for ergonomic factory ctors:

APIARY_EXPOSE
    APIARY_IMPLICIT_FROM(int)
    class Tensor { Tensor(int n); ... };  // can call Python f(t=42)
Parameters:
  • ... – the source type to convert from

APIARY_INDEX_PROTOCOL_STD(...)

Standard index protocol — scalar reads/writes via __getitem__/__setitem__.

The codegen emits per-backend lambdas dispatching on Python type (int, tuple, slice, Ellipsis), normalizing negative indices, bounds-checking, and calling the user’s pure-C++ helpers.

element_type — the class template parameter naming the scalar type rank — member function returning the tensor’s runtime rank dim — member function (size_t i) → size_t (axis size) at_element — T (std::vector<int64_t> const &idx) const set_element — void(std::vector<int64_t> const &idx, T value)

Optional, for slicing to views:

at_view — ViewType(std::vector<SliceSpec> const &specs) const view_type — the bound type at_view returns slice_spec — the SliceSpec type at_view takes; default einsums::SliceSpec. Any struct with its members works: an enum Kind of Index, Range and Full, kind, and int64 index, start, stop and step.

template <typename T, typename Alloc>
  APIARY_EXPOSE
  APIARY_INDEX_PROTOCOL_STD(
      element_type = T, rank = rank, dim = dim,
      at_element = at_element, set_element = set_element)
  struct GeneralRuntimeTensor {
      T    at_element(std::vector<int64_t> const &) const;
      void set_element(std::vector<int64_t> const &, T);
  };

Python: t[5] → scalar (rank-1 tensor) t[0, 1] → scalar (full int-indexing) t[5] = 1.0 → write scalar t[0, 1] = 2.0 → write scalar

With at_view and view_type, also: t[1] → view collapsing axis 0 (rank > 1) t[1:3], t[::-1] → view sliced along axis 0 t[:, 0], t[…] → view from a mixed tuple / the whole tensor

Note

Negative indices (“t[-1]”) are normalized to positive against the dim before being passed to user helpers. Out-of-range raises IndexError.

Warning

Assignment through a slice (t[1:3] = ...) is not emitted; only full integer indices can be written. Without at_view, a slice or partial index raises TypeError.

Parameters:
  • ... – key = value assignments naming element_type, rank, dim, at_element, set_element, and optionally at_view, view_type and slice_spec

APIARY_INSTANTIATE(...)

Cross-product template instantiation.

Each Param(values...) group’s keyword must match one of the C++ template-parameter names; the codegen tool errors out on mismatch, duplicates, missing parameters, or arity mismatches. Python identifiers for the resulting bindings are auto-derived (Tensor_float_2 etc.); use APIARY_INSTANTIATE_TEMPLATE if you want to control the name explicitly.

template <typename T, size_t rank>
  APIARY_INSTANTIATE(Tensor,
      T(float, double, std::complex<float>, std::complex<double>),
      rank(1, 2, 3, 4))
  struct Tensor;

Note

Reordering is allowed; this is equivalent to the above:

APIARY_INSTANTIATE(Tensor,
      rank(1, 2, 3, 4),
      T(float, double, std::complex<float>, std::complex<double>))

Note

Non-type parameters may be of enum type. Name the enumerators in the group (scope-qualified Layout::RowMajor or bare RowMajor); the codegen rewrites each to its fully-qualified form so the binding compiles at module scope, names the instantiation after the enumerator leaf (Storage_float_RowMajor), and errors if a value is not a real enumerator of that parameter’s enum:

enum class Layout { RowMajor, ColumnMajor };
  template <typename T, Layout L>
  APIARY_INSTANTIATE(Storage,
      T(float, double),
      L(Layout::RowMajor, Layout::ColumnMajor))
  struct Storage;
Parameters:
  • ... – the class name followed by Param(values...) groups

APIARY_INSTANTIATE_AS(py_name, ...)

Single-instance instantiation with an explicit Python-side name.

Use this when:

  • You want a specific Python identifier that isn’t a function of the template arguments;

  • Or one template parameter depends on another (e.g. Alloc = std::allocator<T>), which a flat cross-product can’t express.

The Python name comes first so the C++ type, whose template arguments may contain commas, can occupy the variadic tail.

APIARY_INSTANTIATE_AS("Tensor2d_double",
                                GeneralTensor<double, 2, std::allocator<double>>)
Parameters:
  • py_name – string literal naming the Python binding

  • ... – the fully-qualified C++ type to instantiate

APIARY_INSTANTIATE_BOOLS(py_name, ...)

Cross-product instantiation over the leading bool template parameters.

Requires APIARY_TEMPLATE_KWARGS to declare how many leading template params are bool flags. Expands to 2^N APIARY_INSTANTIATE_AS entries with every false/true combination prepended in lexicographic order ((false,false), (false,true), (true,false), (true,true) for N=2).

The variadic tail is the comma-separated non-bool template arguments for one dtype slice — same syntax as APIARY_INSTANTIATE_AS minus the leading bool prefix. Repeat the directive once per dtype.

APIARY_TEMPLATE_KWARGS("trans_a", "trans_b")
  APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor<float,  std::allocator<float>>,  float)
  APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor<double, std::allocator<double>>, double)
  ...

Note

Use APIARY_INSTANTIATE_AS directly if you need to omit a particular bool combination for a given dtype (rare escape hatch).

Parameters:
  • py_name – string literal naming the Python binding

  • ... – the comma-separated non-bool template arguments for one dtype slice

APIARY_INSTANTIATE_MEMBER(...)

Pin a member-template parameter to a concrete type for binding purposes.

pybind11 cannot bind a member template directly — you must specify which instantiation to expose. Apply this directive on a method or constructor that itself has template parameters (distinct from the enclosing class’s template parameters); the codegen substitutes the binding into the emitted signature and into static_cast<>’d method-pointer expressions.

Note

Multiple member-template parameters: stack the directive once per parameter. Position-independent — the codegen matches by name.

template <typename T, typename Alloc>
  struct GeneralRuntimeTensor {
    template <Container Dim>
    APIARY_EXPOSE
    APIARY_INSTANTIATE_MEMBER(Dim = std::vector<size_t>)
    GeneralRuntimeTensor(std::string name, Dim const &dims);
  };

For GeneralRuntimeTensor<float, std::allocator<float>> this binds a constructor with signature (std::string, std::vector<size_t> const &).

Parameters:
  • ... – Param = Type assignment pinning the member-template parameter

APIARY_INSTANTIATE_MEMBER_AS(py_name, ...)

Multi-instantiation form of APIARY_INSTANTIATE_MEMBER.

Each directive defines one Python binding for a templated method; multiple directives stack to fan a method out across dtypes / ranks (mirror of APIARY_INSTANTIATE_AS for free functions).

The first argument is the Python name. Subsequent arguments are Param = Type assignments pinning each member-template parameter to a concrete type for this instantiation.

template <typename T, typename Alloc = std::allocator<T>>
  APIARY_EXPOSE
  APIARY_INSTANTIATE_MEMBER_AS("declare_runtime_tensor",
                                       T = float,  Alloc = std::allocator<float>)
  APIARY_INSTANTIATE_MEMBER_AS("declare_runtime_tensor",
                                       T = double, Alloc = std::allocator<double>)
  GeneralRuntimeTensor<T, Alloc> &declare_runtime_tensor(...);

Note

Sharing a Python name across directives produces a pybind11 overload set; py_name disambiguation is the user’s responsibility.

Parameters:
  • py_name – string literal naming the Python binding

  • ... – Param = Type assignments pinning each member-template parameter

APIARY_INSTANTIATE_TEMPLATE(name_template, ...)

Cross-product instantiation with a Python-name template.

Same matching rules as APIARY_INSTANTIATE: each parameter list keyword must be a C++ template-parameter name. Placeholders in the name template use those same names.

template <typename Element, int Rank> class Block;

  APIARY_INSTANTIATE_TEMPLATE("Block_{Element}_{Rank}",
      Block,
      Element(float, double),
      Rank(1, 2))

Produces Block_float_1, Block_float_2, Block_double_1, Block_double_2. Placeholder values are sanitized to valid Python identifiers (std::complex<double> -> std_complex_double).

Parameters:
  • name_template – string literal name template with {Param} placeholders

  • ... – the class name followed by Param(values...) groups

APIARY_ITERATOR_STD(...)

Standard iterator protocol. The codegen emits a per-backend __iter__ binding that returns a Python iterator over the half-open range [begin(), end()). User-side methods stay STL-style; no pybind11 in their signatures.

All values name member functions that satisfy the standard LegacyForwardIterator (or stronger) requirements:

  • Iter begin();

  • Iter end();

template <typename T, typename Alloc>
  APIARY_EXPOSE
  APIARY_ITERATOR_STD(begin = begin, end = end)
  struct GeneralRuntimeTensor {
      Iter begin();   // pure C++
      Iter end();
  };

Note

The Python iterator borrows a reference to the underlying object (keep_alive<0, 1>) so iteration is safe across the parent’s lifetime.

Parameters:
  • ... – key = value assignments naming the begin and end member functions

APIARY_KEEP_ALIVE(nurse, patient)

Emit py::keep_alive<nurse, patient>() for this call.

Parameters:
  • nurse – index of the object kept alive

  • patient – index of the object whose lifetime is tied to the nurse

APIARY_MODULE(submodule)

Place the binding inside a Python submodule (e.g. “tensor”, “linalg”).

Parameters:
  • submodule – string literal naming the target submodule

APIARY_NOCOPY

Skip generation of the copy constructor binding.

APIARY_NOMOVE

Skip generation of the move constructor binding.

APIARY_NO_BASES

Force-skip emission of base-class arguments to py::class_<>.

Note

Usually unnecessary: by default the emitter only forwards bases that are themselves bound in this run, so unbound internal bases are silently dropped. Use this directive only when you want to explicitly hide a bound base from the Python class hierarchy.

APIARY_OPERATOR(py_name)

Bind this method as a Python operator (e.g. “__add__”, “__matmul__”) instead of an ordinary named function.

Parameters:
  • py_name – string literal naming the Python operator

APIARY_READONLY

Bind a class field as read-only (def_readonly).

Note

Without this, fields marked APIARY_EXPOSE bind read-write.

APIARY_RELEASE_GIL

Wrap the call in py::call_guard<py::gil_scoped_release>().

APIARY_RENAME(py_name)

Override the Python identifier used for the binding.

Parameters:
  • py_name – string literal naming the Python identifier

APIARY_RVP(policy)

Override return_value_policy. Argument is the unqualified policy name.

Parameters:
  • policy – the unqualified policy name, e.g. APIARY_RVP(reference_internal)

APIARY_SETTER(py_name)

Bind a method as the setter of a Python property.

Note

Pair with a matching APIARY_GETTER on the read accessor.

Parameters:
  • py_name – string literal naming the Python property

APIARY_TEMPLATE_KWARGS(...)

Declare Python kwarg names for the leading bool template parameters of a templated free function.

The count of names tells the codegen how many leading template params are bool flags; their values become Python keyword-only arguments with the supplied names. Required when using APIARY_INSTANTIATE_BOOLS.

template <bool TransA, bool TransB, MatrixConcept T, typename U>
  APIARY_EXPOSE
  APIARY_TEMPLATE_KWARGS("trans_a", "trans_b")
  APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor<float, std::allocator<float>>, float)
  void gemm(U const alpha, T const &A, T const &B, U const beta, T *C);

The Python signature becomes gemm(alpha, A, B, beta, C, *, trans_a=False, trans_b=False) and dispatches at runtime to the right gemm<TA, TB, T, U> instantiation.

Parameters:
  • ... – string literals naming the leading bool template parameters

APIARY_VARIADIC_FROM(param_name, element_type)

Variadic-pack expansion for templated method/ctor binding.

Indicates that the (assumed-last) parameter is a parameter pack, and that the expanded arity is given by the template parameter named param_name. Each expanded slot has type element_type.

template <typename T, size_t rank> struct Tensor;

  template <typename... Dims>
  APIARY_EXPOSE
  APIARY_VARIADIC_FROM(rank, size_t)
  Tensor(std::string name, Dims... dims);

For Tensor<double, 2>, this binds a ctor with signature (std::string, size_t, size_t).

Parameters:
  • param_name – template parameter that gives the expanded arity

  • element_type – type of each expanded slot