I/O¶
SeQuant provides different forms of I/O for its objects. Generally, they can be found in the sequant::io namespace. Different formats live in
different sub-namespaces. E.g. sequant::io::latex::to_string() yields a LaTeX representation of the respective object.
Note
Frequently used I/O functions also have shorthands that can be brought in by including the sequant/core/io/shorthands.hpp header. These
shorthands live directly in the sequant namespace. The example from above could be achieved via sequant::to_latex() once that
header is included.
LaTeX¶
The relevant function is sequant::io::latex::to_string(). SeQuant provides support for LaTeX conversion on most object types. If the shorthands
header is included, this functionality is also exposed as sequant::to_latex().
The produced LaTeX code is not self-contained. It needs to be embedded in a suitable math environment. Furthermore, it assumes that the tensor has been loaded.
Warning
Some objects also have a to_latex() member function. However, we don’t provide any guarantees about which types do and they may also be
removed in future SeQuant versions. Hence, you should always prefer using sequant::io::latex::to_string().
Note
The produced LaTeX code is typically not human-friendly (that is, hard to read) but should compile successfully once embedded in a suitable LaTeX document.
Formatting and streams¶
Include SeQuant/core/io/format.hpp to print sequant::Expr, its subclasses, sequant::ExprPtr,
and sequant::ResultExpr with std::format or stream insertion (<<). Both default to serialization and
support narrow and wide characters; narrow output is UTF-8. An empty ExprPtr produces an empty string in both modes
and with stream insertion, matching the LaTeX and serialization converters. Deserializing that empty string
returns an empty ExprPtr.
The format specifier selects the representation: l or latex for LaTeX, and s or serialize for
serialization. An empty specifier selects serialization. These are the only supported specifiers;
apply string formatting to the rendered string if width, alignment, or precision is needed.
Stream insertion of sequant::Expr, sequant::ExprPtr and sequant::ResultExpr produces
serialization. For explicit LaTeX, insert the result of sequant::io::latex::to_string() into a wide stream, or
use std::format with l or latex for a narrow string. Wide formatting is available with wide format strings.
The The Expression Tree examples demonstrate stream insertion and default formatting.
Formatting uses the existing LaTeX and serialization converters and preserves their limitations. In particular,
a custom expression’s LaTeX output comes from its virtual to_latex() implementation; serialization requires
support in the serialization converter. Unsupported conversions propagate their exceptions.
sequant::mbpt::Operator has no serialization, so print operators and expressions containing them with l
or latex. Unknown format specifiers are rejected during compile-time format-string checking, or with sequant::Exception when
using runtime format strings with std::vformat. That exception does not derive from std::format_error, so a handler
for std::format_error alone does not catch it.
Serialization¶
SeQuant provides serialization support. This means that SeQuant objects can be transformed into some intermediary storable format (serialization), which can later be converted back (deserialization) to yield the original SeQuant object.
Functions associated with this live in the sequant::io::serialization namespace. At the moment, there is only a text format implemented via
to_string() and from_string(). More formats may be added at a later point. It is important to note that in order to work with C++’s
type system, from_string() is a template that takes in the type of object it is supposed to produce. The most important variants are
from_string and from_string where the former also allows to deserialize any Expr subclass.
Depending on the used template type, the expected format of the input will change accordingly.
As SeQuant’s capabilities develop over time, it can be necessary to adapt the syntax of the serialization format.
By default, the abovementioned functions will always adhere to the latest parse syntax specification. However, they can be
instructed to work with a different version by explicitly specifying a SerializationSyntax when calling them or using one of the versioned
function calls.
Warning
All syntax versions except SerializationSyntax::Latest are considered deprecated. Support for them will remain available for some time but
might get removed in future versions of SeQuant.
If the shorthands header is included, text-based serialization and deserialization is available as sequant::serialize() and
sequant::deserialize.
Customizations¶
The exact serialization format can be customized to some extend by providing SerializationOptions and DeserializationOptions
instances when calling the respective functions. Among other things, they allow for specification of a specific SerializationSyntax. For an
overview of all customization options, please refer to the documentation of those classes in the API reference.
Note
Typically, you should leave these at their defaults to yield the most reliable behavior.
SerializationSyntax¶
We will loosely follow EBNF syntax for specifying the rules of the grammar describing the parse syntax. However, we don’t define a full formal grammar here as minor details and precedence issues may be left out/simplified in order to increase readability.
V1¶
Note
Known limitations:
No support for second-quantized (normal-ordered) operators
No support for complex numbers
No support for representing operators (e.g. symmetrizers) explicitly
Component |
Rule |
Note |
|---|---|---|
Result |
(Tensor | Variable) (‘=’ | ‘<-’) Expression |
|
Expression |
Sum? |
|
Sum |
Product ( (‘+’ | ‘-’) Product)* |
|
Product |
Nullary ( ‘*’? Nullary )* |
Explict ‘*’ use is optional |
Nullary |
‘(’ Sum ‘)’ | Number | Tensor | Variable |
|
Number |
Integer, Floating point or fraction |
|
Tensor |
Name IndexGroup SymmetrySpec? |
|
IndexGroup |
‘{’ IndexList? ( ‘;’ IndexList? ( ‘;’ IndexList? )? )? ‘}’
‘^{’ IndexList? ‘}_{’ IndexList ‘}’
‘_{’ IndexList? ‘}^{’ IndexList ‘}’
|
Meaning is {<bra>;<ket>;<aux>}
Meaning is ^{<ket>}_{<bra>} (no aux)
Meaning is _{<bra>}^{<ket>} (no aux)
|
IndexList |
Index ( ‘,’ Index )? |
|
Index |
BaseKey ‘_’? Integer IndexDomain? |
|
IndexDomain |
‘<’ (ProtoLabel (‘,’ ProtoLabel)*)? (‘;’ Integer)? ‘>’ |
‘;Integer’ (signed, 32-bit) names a non-default index basis instance; absent when BaseKey is itself the label of a registered basis instance |
ProtoLabel |
BaseKey ‘_’? Integer ( ‘<’ ‘;’ Integer ‘>’ )? |
May carry only a domainless instance (no nested protos); same rule for a named basis |
BaseKey |
Letters, ⁺, ⁻, combining diacritics, arrows (e.g. ↑, ↓) and primes; the base key of a registered IndexSpace or the label of a registered basis instance (IndexBasis::base_key()) |
|
SymmetrySpec |
‘:’ ( [ASN] ( ‘-’ [SCN] ( ‘-’ [SN] )? )? ) |
:<Symmetry>-<BraKetSymmetry>-<ColumnSymmetry> |
Variable |
Name |
|
Name |
Single word (may include Unicode chars) |
The single-letter codes in SymmetrySpec abbreviate the corresponding enumerators, one letter per field: [ASN] is the tensor’s
permutational Symmetry (A = Antisymm, S = Symm, N = Nonsymm); [SCN] is its
BraKetSymmetry (S = Symm, C = Conjugate, N = Nonsymm); and the final [SN] is its
ColumnSymmetry (S = Symm, N = Nonsymm — this field has no Conjugate case). A tensor’s trailing
:A-C-S in the example below therefore reads “antisymmetric, conjugate bra-ket symmetric, symmetric column”.
sequant::io::serialization::from_string will start at rule Expression, whereas
sequant::io::serialization::from_string will start at Result.
Examples¶
The following parses a residual expression R1 as a sum of four terms, the last one antisymmetric-bra-ket-symmetric-column (:A-C-S) and
scaled by the constant 1/2:
R1{u1;i1} = f{u1;i1} - Ym1{u1;u2} f{u2;i1} - Ym1{u3;u2} * g{u1,u2;u3,i1} + 1/2 Ym2{u1,u4;u_2,u_3} g{u2,u3;u4,i1}:A-C-S