Creating observables
Warning
This page considers Observables specified either via a list of Pauli Term
or a matrix - for gate-based or analog quantum computations.
For ising-type of Observables please refer to the Ising Observables section.
Observables
As mentioned in the job section, it is possible to construct a Job
requiring the sampling of some observable on the final state produced by a quantum circuit.
The Observable
class provides a basic interface to declare observables.
from qat.core import Observable, Term
my_observable = Observable(4, # A 4 qubits observable
pauli_terms=[
Term(1., "ZZ", [0, 1]),
Term(4., "XZ", [2, 0]),
Term(3., "ZXZX", [0, 1, 2, 3])
],
constant_coeff=23.)
print(my_observable)
23.0 * I^4 +
1.0 * (ZZ|[0, 1]) +
4.0 * (XZ|[2, 0]) +
3.0 * (ZXZX|[0, 1, 2, 3])
Observables operations
Observables can be added and multiplied by a scalar:
Observable basic arithmetic
from qat.core import Observable, Term
obs1 = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])], constant_coeff=1.)
obs2 = Observable(2, pauli_terms=[Term(1., "X", [0])], constant_coeff=2.)
print(obs1 + obs2)
3.0 * I^2 +
1.0 * (ZZ|[0, 1]) +
1.0 * (X|[0])
from qat.core import Observable, Term
obs1 = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])])
print(4 * obs1)
4.0 * (ZZ|[0, 1])
They can be composed via tensor product using the ^ __xor__ operator:
Observable composition
from qat.core import Observable, Term
obs1 = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])])
obs2 = Observable(2, pauli_terms=[Term(1., "X", [0])])
print(obs1 ^ obs2)
1.0 * (ZZX|[0, 1, 2])
The commutator of two observables can be computed using the | __or__ operator:
Observable commutation
from qat.core import Observable, Term
obs1 = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])])
obs2 = Observable(2, pauli_terms=[Term(1., "X", [0])])
print(obs1 | obs2)
2j * (YZ|[0, 1])
Single term observables
Simple observables containing only one Pauli terms can be created with the sigma_x, sigma_y and sigma_z class methods (or equivalently, x, y and z):
Shorthand single Pauli term notation
from qat.core import Observable
obs1 = Observable.sigma_x(0)
obs2 = Observable.sigma_y(1)
obs3 = Observable.sigma_z(0, nbqbits=2)
print("obs1:", obs1)
print("obs2:", obs2)
print("obs3:", obs3)
obs1: 1.0 * (X|[0])
obs2: 1.0 * (Y|[1])
obs3: 1.0 * (Z|[0])
from qat.core import Observable
obs1 = Observable.x(0)
obs2 = Observable.y(1)
obs3 = Observable.z(0, nbqbits=2)
print("obs1:", obs1)
print("obs2:", obs2)
print("obs3:", obs3)
obs1: 1.0 * (X|[0])
obs2: 1.0 * (Y|[1])
obs3: 1.0 * (Z|[0])
Of course those simple observable can be composed by using previously seen operators in order to get more complex ones.
from qat.core import Observable
obs1 = Observable.sigma_z(0)
obs2 = Observable.x(0)
print(((obs1 ^ obs2) + 3) * 2)
6.0 * I^2 +
2.0 * (ZX|[0, 1])
Using an observable
Once written, observables can be attached to a circuit to form an observable sampling job (see the job section for more examples):
from qat.core import Observable, Term
obs = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])])
job = circuit.to_job(observable=obs, nbshots=2048)