Spin-½ Operator Transformations
At a glance
- Special transformations can be done on operator expressions comprised exclusively of spin 1/2 operators.
- Spin-1/2 operator expression can be reordered while respecting the bosonic algebra.
- Particular simplifications can be done to operator expressions comprised of single site spin-1/2 operators, namely pauli strings.
This document will assume you are familiar with general operator transformations and spin-1/2 operators. Feel free to consult them before reading this concept if you have not done so already.
Overview of transformations
There are currently three exclusively spin-1/2 operator transformations that are available in aleph:
reorder_by_sitesorts operators by site index for canonical ordering while obeying commutation relationssimplify_paulissimplifies pauli operators according to the pauli algebra.commutatorreturns for two spin-1/2 operators
The first transformation can be useful to put operator expression into a canonical order according to their sites without commuting terms within the local hilbert space. The second one on the other hand will simplify pauli operators according to the pauli algebra
where . The last transformation calculates the commutator of two spin-1/2 operators, which can be further simplified or used in numerical calculations.
Using transformations
Reorder by site
The reorder_by_site function sorts operators in ascending order of site index while preserving quantum commutation rules. That is, given an operator expression
the transformation orders into
where are such that , i.e. they are now ordered. Importantly, in order to respect the bosonic algebra of spin-1/2 operators
no operators are commuted with each other during this process. We can see this with the input operator expression
var S = operator_sum(2.0 * (X(2) * Y(0)) + 3.0 * (Z(1) * X(0)), as_real);
var reordered = reorder_by_site(S);
// Result: 2.0 * Y(0) * X(2) + 3.0 * X(0) * Z(1)
The out of the reordering only occurs between operators with disjoint support (acting on different qubits) so quantum mechanical commutation relationships are preserved. If we instead had a term with X(0) * Y(0) , then it wouldn't be reordered since both operators act on the same site.
var S = operator_sum(2.0 * (X(2) * Y(0)) + 3.0 * (Z(1) * X(0)) + 1.0 * (X(0) * Y(0)), as_real);
var reordered = reorder_by_site(S);
// Result: 2.0 * Y(0) * X(2) + 3.0 * X(0) * Z(1) + 1.0 * X(0) * Y(0)
Further simplifications can be done by calling merge after the operator has been reordered. This reorder ensures that all terms with the same operators but in different orders can be identified with each other and hence simplified.
var S = X(1) * Y(0) + Y(0) * X(1); // Same operators, different order
var reordered = reorder_by_site(S);
// Result: Y(0) * X(1) + Y(0) * X(1)
merge(reordered);
// Result: 2.0 * Y(0) * X(1)
Simplifying pauli strings
Special expressions can be manipulated and simplified utilizing known properties of the operators, namely pauli operators i.e. . General expressions made up of these operators are called pauli strings and are of the form
In this case, simplify_paulis applies Pauli algebra rules to operators in operator expressions on the same site resulting in the simplification of the pauli operators via the following identities,
var chain = X(0) * Y(0);
var simplified = simplify_paulis(chain); // Returns i*Z(0)
simplify_paulis always returns complex coefficients, even for real inputs. Pauli multiplication introduces imaginary phases (like ), so the result is always a complex operator_sum.
A more general workflow where one would perform several operation on a pauli string would be to use general transformations of the expression and then simplify it further at the end with simplify_paulis. This way, flatten, merge, and prune can help reduce the number of final terms to fully simplify with simplify_pailis.
When working with Pauli operators, its best practice to apply the general transformations first that potentially can reduce the number of terms in the expression and then use simplify_paulis at the end.
var term1 = X(0)*Y(0) + Z(1); // Pauli products
var term2 = X(2) + Y(2);
var S = operator_sum(2.0*term1*term2 + 3.0*X(0)*Y(0)*X(2) + 1e-15*Z(3)); // Nested, duplicates, and noise
// Step 1: Flatten nested structures
flatten(S);
// Result: 2*X(0)*Y(0)*X(2) + 2*X(0)*Y(0)*Y(2) + 2*Z(1)*X(2) + 2*Z(1)*Y(2) + 3*X(0)*Y(0)*X(2) + 1e-15*Z(3)
// Step 2: Merge duplicate terms, can also reorder before if needed
merge(S);
// Result: 5*X(0)*Y(0)*X(2) + 2*X(0)*Y(0)*Y(2) + 2*Z(1)*X(2) + 2*Z(1)*Y(2) + 1e-15*Z(3)
// Step 3: Prune with custom tolerance
prune(S, 1e-10); // Removes 1e-15*Z(3)
// Result: 5*X(0)*Y(0)*X(2) + 2*X(0)*Y(0)*Y(2) + 2*Z(1)*X(2) + 2*Z(1)*Y(2)
// Step 4: Simplify Pauli products (XY -> iZ)
var final = simplify_paulis(S);
// Final: (0+5i) * Z(0) * X(2) + (0+2i) * Z(0) * Y(2) + (2+0i) * Z(1) * X(2) + (2+0i) * Z(1) * Y(2)
In such a case, the final simplification pass done with simplify_paulis ensures theres only a single pauli operator for a site in the support of the operator expression.
Compute commutators
Evaluating the commutator of two operators is a fundamental operation in quantum mechanics. In the case of spin-1/2 degrees of freedom, operators commute with themselves and with those that have disjoint support. The commutator function uses this knowledge when applicable and returns an explicit calculation of the commutator of two spin-1/2 operator expressions.
var comm = commutator(X(0), Y(0)); // Returns (1+0i)*X(0)*Y(0) + (-1+-0i)*Y(0)*X(0)
Like any given operator expresison, the output is not simplified. Using general and spin-1/2 transformations, expressions can be simplified and truncated to suit your numerical needs or symbolic calculation. In the particular case of pauli operators we can simplify the result even further,
var comm = commutator(X(1), Y(1));
// Returns (1) * X(1) * Y(1) + (-1) * Y(1) * X(1)
simplify_paulis(comm);
// Returns (0+2i) * Z(1)
As mentioned above, in the case of the operators being identical or have disjoint support, the commutator automatically returns an empty operator representing zero.
var iden = commutator(X(0), X(0));
// Returns ()
var disJ = commutator(X(0), X(1));
// Returns ()
This is useful for optimization - you can skip expensive commutator calculations for disjoint operators, or identify which operators commute with your system Hamiltonian or circuit!
Detailed documentation
To check out more detailed documentation see Transformations in the Library Reference.