Krylov subspace & Green’s functions
InQuanto offers built-in support for measuring the moments of an operator to calculate
quantities within a Krylov subspace, such as the Lanczos representation of a
Hamiltonian or the Green’s function. The key computable class for this is the
KrylovSubspaceComputable
, which is an example
of a composite computable from the inquanto.computables.composite
submodule.
Given an operator and a state, this computable evaluates to a
series of moments as the expectation values of the powers of the operator.
We can demonstrate this using a simple 2-site Hubbard model. First, we prepare the necessary state and operator:
from inquanto.computables.composite import KrylovSubspaceComputable
from inquanto.express import DriverHubbardDimer
from inquanto.operators import FermionOperator
from inquanto.ansatzes import FermionSpaceAnsatzChemicallyAwareUCCSD
driver = DriverHubbardDimer(t=0.3, u=2.15)
hamiltonian, space, state = driver.get_system()
qubit_hamiltonian = hamiltonian.qubit_encode()
ansatz = FermionSpaceAnsatzChemicallyAwareUCCSD(space, state)
parameters = ansatz.state_symbols.construct_random(2, 0.01, 0.1)
The computable can be instantiated as follows, where the Krylov space is expanded up to rank 4:
krylov_subspace_computable = KrylovSubspaceComputable(ansatz, qubit_hamiltonian, 4)
Once we have the computable, we can use a protocol to measure it. Since the
KrylovSubspaceComputable
calculates expectation values, we may use the PauliAveraging
protocol:
from inquanto.protocols import PauliAveraging
from pytket.partition import PauliPartitionStrat
from pytket.extensions.qiskit import AerBackend
protocol = PauliAveraging(
AerBackend(),
shots_per_circuit=10000,
pauli_partition_strategy=PauliPartitionStrat.CommutingSets,
)
protocol.build_from(parameters, krylov_subspace_computable)
protocol.run(seed=2)
<inquanto.protocols.averaging._pauli_averaging.PauliAveraging at 0x7f7dd4e430d0>
Building the protocol from the Krylov subspace computable generates all measurement circuits,
and running the protocol submits circuits to the backend and retrieves results. We may then inspect
the protocol via dataframe helper methods, and use the evaluator to generate a
KrylovSubspace
:
print("Measurements:")
print(protocol.dataframe_measurements())
print("Circuits measured:")
print(protocol.dataframe_circuit_shot())
krylov_subspace = krylov_subspace_computable.evaluate(evaluator=protocol.get_evaluator())
Measurements:
pauli_string mean stderr umean sample_size
0 Z0 X1 X3 -0.0970 0.009953 -0.097+/-0.010 10000
1 Z2 0.8812 0.004728 0.881+/-0.005 10000
2 X0 X1 Y2 Y3 -0.4608 0.008875 -0.461+/-0.009 10000
3 X0 Z1 X2 Z3 0.1628 0.009867 0.163+/-0.010 10000
4 Z0 X1 Z2 X3 -0.1606 0.009871 -0.161+/-0.010 10000
5 Z0 Z1 -0.9844 0.001760 -0.9844+/-0.0018 10000
6 Z0 Z3 0.9844 0.001760 0.9844+/-0.0018 10000
7 Z0 Z1 Z2 -0.8786 0.004776 -0.879+/-0.005 10000
8 Z0 Y1 Y3 -0.0970 0.009953 -0.097+/-0.010 10000
9 Y0 Z1 Y2 -0.1114 0.009938 -0.111+/-0.010 10000
10 X0 Y1 Y2 X3 0.4608 0.008875 0.461+/-0.009 10000
11 Y0 Z1 Y2 Z3 0.1628 0.009867 0.163+/-0.010 10000
12 X0 Z1 X2 -0.1114 0.009938 -0.111+/-0.010 10000
13 Y1 Y3 0.1606 0.009871 0.161+/-0.010 10000
14 Y0 Y2 Z3 0.1114 0.009938 0.111+/-0.010 10000
15 Z0 Z1 Z2 Z3 1.0000 0.000000 1.0+/-0 10000
16 X0 X2 -0.1628 0.009867 -0.163+/-0.010 10000
17 Z0 Z2 Z3 0.8786 0.004776 0.879+/-0.005 10000
18 Y0 Y2 -0.1628 0.009867 -0.163+/-0.010 10000
19 Z0 Z1 Z3 0.8812 0.004728 0.881+/-0.005 10000
20 Y0 X1 X2 Y3 0.4608 0.008875 0.461+/-0.009 10000
21 Z0 -0.8812 0.004728 -0.881+/-0.005 10000
22 Y1 Z2 Y3 0.0970 0.009953 0.097+/-0.010 10000
23 Z3 -0.8786 0.004776 -0.879+/-0.005 10000
24 Z1 Z2 Z3 -0.8812 0.004728 -0.881+/-0.005 10000
25 Z0 Z2 -1.0000 0.000000 -1.0+/-0 10000
26 Z1 Z2 0.9844 0.001760 0.9844+/-0.0018 10000
27 X0 Y1 X2 Y3 -0.4764 0.008793 -0.476+/-0.009 10000
28 Z1 Z3 -1.0000 0.000000 -1.0+/-0 10000
29 Z0 Y1 Z2 Y3 -0.1606 0.009871 -0.161+/-0.010 10000
30 Y0 X1 Y2 X3 -0.4764 0.008793 -0.476+/-0.009 10000
31 Y0 Y1 Y2 Y3 -0.4764 0.008793 -0.476+/-0.009 10000
32 X1 Z2 X3 0.0970 0.009953 0.097+/-0.010 10000
33 Y0 Y1 X2 X3 -0.4608 0.008875 -0.461+/-0.009 10000
34 X0 X1 X2 X3 -0.4764 0.008793 -0.476+/-0.009 10000
35 Z2 Z3 -0.9844 0.001760 -0.9844+/-0.0018 10000
36 X1 X3 0.1606 0.009871 0.161+/-0.010 10000
37 X0 X2 Z3 0.1114 0.009938 0.111+/-0.010 10000
38 Z1 0.8786 0.004776 0.879+/-0.005 10000
Circuits measured:
Qubits Depth Depth2q DepthCX Shots
0 4 42 23 23 10000
1 4 43 24 24 10000
2 4 41 23 23 10000
Sum - - - - 30000
krylov_subspace
is an instance of the KrylovSubspace
class that offers various methods to calculate eigenvalues, Lanczos coefficients,
Green’s functions, and more.
print("Eigenvalues of the Lanczos matrix:", krylov_subspace.eigenvalues())
exact = qubit_hamiltonian.eigenspectrum(hamming_weight=state.single_term.hamming_weight)
print("Exact diagonalization: ", exact)
Eigenvalues of the Lanczos matrix: [-0.156 -0. 2.15 2.306]
Exact diagonalization: [-0.156 -0. -0. 0. 2.15 2.306]