.. ---------------------------------------------------------------------------------------------- Copyright (c) The Einsums Developers. All rights reserved. Licensed under the MIT License. See LICENSE.txt in the project root for license information. ---------------------------------------------------------------------------------------------- .. _cppapi_Annotations (APIARY_* macros): ============================= Annotations (APIARY_* macros) ============================= .. note:: Generated from the C++ headers by ``apiary --emit-cpp-docs-json``. .. c:macro:: 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. .. code-block:: text namespace einsums::pybuf { template pybind11::buffer_info make(GeneralTensor &t); } APIARY_BUFFER_PROTOCOL APIARY_BUFFER_FROM(einsums::pybuf::make) struct GeneralTensor { ... }; :param ...: the helper function name .. c:macro:: APIARY_BUFFER_PROTOCOL Enable the pybind11 buffer protocol for this class (required for NumPy zero-copy interop on tensor types). .. note:: Pair with APIARY_BUFFER_FROM to actually emit the ``.def_buffer()`` call — buffer_protocol alone only flips the class option. .. c:macro:: APIARY_BUFFER_PROTOCOL_STD(...) Standard-layout buffer protocol. The codegen emits a per-backend .def_buffer (pybind11) / __dlpack__ (nanobind) lambda that builds the backend-native buffer description from the named member functions on the bound class. 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(). .. code-block:: text template 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. :param ...: ``key = value`` assignments naming data, rank, dim, stride, and element_type .. c:macro:: APIARY_DETAIL_ANNOTATE(payload) Expand a payload to a Clang annotate attribute; a no-op on non-Clang compilers. :param payload: string literal payload appended after the ``apiary:`` prefix .. c:macro:: APIARY_DOC(text) Override the docstring extracted from the doxygen comment block above this declaration. :param text: string literal docstring to use instead .. c:macro:: APIARY_DYNAMIC_ATTR Allow Python instances to carry arbitrary attributes (py::dynamic_attr()). .. c:macro:: APIARY_EXCEPTION Mark a class as a Python exception type rather than a regular bound class. The codegen emits ``py::register_exception(m, "name")`` instead of ``py::class_(...)``. The C++ class must derive from ``std::exception`` (or whatever pybind11's register_exception template requires) for the registration to compile. .. code-block:: text 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. .. note:: Nanobind has a different exception API; this directive is pybind11-specific and is silently dropped under the nanobind target. .. c:macro:: APIARY_EXPOSE Mark a declaration for binding. Without this, the codegen tool ignores it. .. c:macro:: APIARY_GETTER(py_name) Bind a method as the getter of a Python property. :param py_name: string literal naming the Python property .. c:macro:: APIARY_HIDE Suppress binding for a declaration that would otherwise be exposed. .. note:: For example, an inherited member from a base flagged APIARY_EXPOSE. .. c:macro:: APIARY_HOLDER(...) Override the pybind11 holder type. Default is std::unique_ptr. :param ...: the holder type, e.g. ``APIARY_HOLDER(std::shared_ptr)`` .. c:macro:: APIARY_IMPLICIT_FROM(...) Register a one-way implicit conversion from ``Source`` to the annotated class. Emits ``py::implicitly_convertible()`` after the class definition. Useful for ergonomic factory ctors: .. code-block:: text APIARY_EXPOSE APIARY_IMPLICIT_FROM(int) class Tensor { Tensor(int n); ... }; // can call Python f(t=42) :param ...: the source type to convert from .. c:macro:: APIARY_INDEX_PROTOCOL_STD(...) Standard index protocol — scalar reads/writes via __getitem__/__setitem__. The codegen emits per-backend lambdas dispatching on Python type (``py::int_``, ``py::tuple``), 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 const &idx) const set_element — void(std::vector const &idx, T value) .. code-block:: text template 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 const &) const; void set_element(std::vector 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 .. note:: Negative indices ("t[-1]") are normalized to positive against the dim before being passed to user helpers. Out-of-range raises py::index_error. .. warning:: Slice/partial-index reads (returning a view) and buffer bulk-assign are not yet emitted — they need APIARY_INDEX_PROTOCOL_STD's extended form (with view_type and at_view) to land alongside the RuntimeTensorView binding. Until then, slice access throws a clear "view return not yet bound" error. :param ...: ``key = value`` assignments naming element_type, rank, dim, at_element, set_element .. c:macro:: 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. .. code-block:: text template APIARY_INSTANTIATE(Tensor, T(float, double, std::complex, std::complex), rank(1, 2, 3, 4)) struct Tensor; .. note:: Reordering is allowed; this is equivalent to the above: .. code-block:: text APIARY_INSTANTIATE(Tensor, rank(1, 2, 3, 4), T(float, double, std::complex, std::complex)) .. 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: .. code-block:: text enum class Layout { RowMajor, ColumnMajor }; template APIARY_INSTANTIATE(Storage, T(float, double), L(Layout::RowMajor, Layout::ColumnMajor)) struct Storage; :param ...: the class name followed by ``Param(values...)`` groups .. c:macro:: 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``), 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. .. code-block:: text APIARY_INSTANTIATE_AS("Tensor2d_double", GeneralTensor>) :param py_name: string literal naming the Python binding :param ...: the fully-qualified C++ type to instantiate .. c:macro:: 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. .. code-block:: text APIARY_TEMPLATE_KWARGS("trans_a", "trans_b") APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor>, float) APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor>, double) ... .. note:: Use ``APIARY_INSTANTIATE_AS`` directly if you need to omit a particular bool combination for a given dtype (rare escape hatch). :param py_name: string literal naming the Python binding :param ...: the comma-separated non-bool template arguments for one dtype slice .. c:macro:: 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. .. code-block:: text template struct GeneralRuntimeTensor { template APIARY_EXPOSE APIARY_INSTANTIATE_MEMBER(Dim = std::vector) GeneralRuntimeTensor(std::string name, Dim const &dims); }; For ``GeneralRuntimeTensor>`` this binds a constructor with signature ``(std::string, std::vector const &)``. :param ...: ``Param = Type`` assignment pinning the member-template parameter .. c:macro:: 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. .. code-block:: text template > APIARY_EXPOSE APIARY_INSTANTIATE_MEMBER_AS("declare_runtime_tensor", T = float, Alloc = std::allocator) APIARY_INSTANTIATE_MEMBER_AS("declare_runtime_tensor", T = double, Alloc = std::allocator) GeneralRuntimeTensor &declare_runtime_tensor(...); .. note:: Sharing a Python name across directives produces a pybind11 overload set; py_name disambiguation is the user's responsibility. :param py_name: string literal naming the Python binding :param ...: ``Param = Type`` assignments pinning each member-template parameter .. c:macro:: 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. .. code-block:: text template 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`` -> ``std_complex_double``). :param name_template: string literal name template with ``{Param}`` placeholders :param ...: the class name followed by ``Param(values...)`` groups .. c:macro:: 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();`` .. code-block:: text template 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 (py::keep_alive<0, 1>) so iteration is safe across the parent's lifetime. :param ...: ``key = value`` assignments naming the begin and end member functions .. c:macro:: APIARY_KEEP_ALIVE(nurse, patient) Emit py::keep_alive() for this call. :param nurse: index of the object kept alive :param patient: index of the object whose lifetime is tied to the nurse .. c:macro:: APIARY_MODULE(submodule) Place the binding inside a Python submodule (e.g. "tensor", "linalg"). :param submodule: string literal naming the target submodule .. c:macro:: APIARY_NOCOPY Skip generation of the copy constructor binding. .. c:macro:: APIARY_NOMOVE Skip generation of the move constructor binding. .. c:macro:: 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. .. c:macro:: APIARY_OPERATOR(py_name) Bind this method as a Python operator (e.g. "__add__", "__matmul__") instead of an ordinary named function. :param py_name: string literal naming the Python operator .. c:macro:: APIARY_READONLY Bind a class field as read-only (``def_readonly``). .. note:: Without this, fields marked APIARY_EXPOSE bind read-write. .. c:macro:: APIARY_RELEASE_GIL Wrap the call in py::call_guard(). .. c:macro:: APIARY_RENAME(py_name) Override the Python identifier used for the binding. :param py_name: string literal naming the Python identifier .. c:macro:: APIARY_RVP(policy) Override return_value_policy. Argument is the unqualified policy name. :param policy: the unqualified policy name, e.g. ``APIARY_RVP(reference_internal)`` .. c:macro:: 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. :param py_name: string literal naming the Python property .. c:macro:: 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``. .. code-block:: text template APIARY_EXPOSE APIARY_TEMPLATE_KWARGS("trans_a", "trans_b") APIARY_INSTANTIATE_BOOLS("gemm", einsums::GeneralRuntimeTensor>, 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`` instantiation. :param ...: string literals naming the leading bool template parameters .. c:macro:: 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``. .. code-block:: text template struct Tensor; template APIARY_EXPOSE APIARY_VARIADIC_FROM(rank, size_t) Tensor(std::string name, Dims... dims); For ``Tensor``, this binds a ctor with signature ``(std::string, size_t, size_t)``. :param param_name: template parameter that gives the expanded arity :param element_type: type of each expanded slot