General Operator Transformations
At a glance
- Operator transformations manipulate quantum expressions symbolically.
- General transformations apply to any operator expression.
- All transformations have both in-place and out-of-place versions
- Transformations are designed to prepare operator expressions for efficient numerical calculations
Before working with transformations, you should be familiar with the operator sums and products that are generated from the factory functions operator_sum and operator_prod. We encourage you to review these types first to understand how operator expressions are structured and constructed.
Design Philosophy
Our transformation system follows a "nothing is automatic" principle - all operations are explicit, transparent, and user-controlled. This deliberate design decision ensures that:
- Users have full visibility into each transformation step
- Complex simplifications don't happen unexpectedly
- The transformations remain predictable and debuggable
- Users can selectively apply only the transformations they need
This approach prioritizes transparency, giving users complete control over how the expressions are processed.
Overview of transformations
When building quantum operator expressions through composition, the resulting expressions can become unwieldy with redundant terms, nested structures, and numerical artifacts. Operator transformations convert these expressions into cleaner and canonical forms that are ready for calculations. If no transformations are employed, no simplifications of the expressions are done.
Each operation serves a specific purpose:
- flatten expands nested products into a flat sum
- merge combines identical operator terms
- prune removes negligible contributions.
In-place vs. out-of-place transformations
Every transformation comes in two versions. Out-of-place versions (merged, pruned, flattened) preserve the original expression and return a transformed copy, while in-place versions (merge, prune, flatten) modify it directly.
var cleaned = merged(original); // original unchanged
merge(original); // original is modified
In Aleph, methods in the past tense return copies while those in the present tense denote in-place modification. Use in-place transformations when working with large expressions to save memory, and chain them for efficiency:
flatten(S);
merge(S);
prune(S);
Not all transformations have in-place versions. reorder_by_site and simplify_paulis always return new copies, so you must assign the result back to a variable:
var reorderS = reorder_by_site(S);
var simpleS = simplify_paulis(S);
Using transformations
Flatten nested structures
Flattening distributes multiplication over addition, expanding nested expressions into a flat sum of products. A generic flattened operator_sum is one that has the form
Such a sum has total terms, each with a possibly different number of non-nested operators in a product. Given some operator expression, the flatten function transforms it into the form shown above.
var S = operator_sum(2.0 * Z(0) * (X(1) + Y(2)), as_real)
flatten(S);
// Result: 2 * Z(0) * X(1) + 2 * Z(0) * Y(2)
In the above example a sum is made using operator_sum consisting of a single term . The flatten function then modifies the sum object in-place by expanding the sum into .
Use flatten before doing any other kind of transformations as hidden duplicate terms and similat simplfications only become visible after flattening.
Only use flatten on operator_sum types where you've built nested structures.
Flattening a single operator like X(0) or clear operator_prod type is pointless.
Merge like terms
One simplification we can perform on a flattened sum is to merge like terms. Merging identifies identical operators and combines their coefficients and removes terms near-zero coefficients (below machine precision).
Merging before computing expectation values, time evolution, or other operations can increase performance from removing redundant terms.
var S = (2.0 + 1.0i)*X(0) + 3.0*Y(1) + 1.5*X(0)
merge(S); // Result: (3.5 + 1.0i)*X(0) + 3.0*Y(0)
merge will not commute terms when checking if terms are equal. It is possible that further manipulations are required to merge terms that are equivalent algebraically. There is support for both fermionic and spin-1/2 reordering transformations, they should be called before merge to ensure more terms get combined.
Prune negligible contributions
As operator_sum expressions get complex, terms may accrue small coefficients or the operators themselves may have small norms. By pruning the sum, terms whose effective norms fall below a threshold are removed. Here, the effective norm is computed as:
where represents the spectral norm, i.e., the absolute value of the largest eigenvalue of the operator.
var S = X(0) + 0.5*Y(1) + 1e-14*Z(2) + 1e-15*X(3);
prune(S); // Removes 1e-14*Z(2) and 1e-15*X(3)
Default thresholds are for double precision and for single precision.
Use prune(expr, tolerance) for custom cutoffs:
var S = 0.1*X(0) + 0.05*Y(1) + 1e-6*Z(2);
prune(S, 1e-5); // Removes 1e-6*Z(2) with custom tolerance
Use prune after merging to catch near-zero coefficients created when terms nearly cancel.
Be careful with custom prune tolerances. Setting the tolerance too high can remove physically important terms. Understand your physical scale before using custom tolerances.
Detailed documentation
To check out more detailed documentation see Transformations in the Library Reference.