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 0x7ffa5e943650>

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      Y0 Z1 X2 -0.0148  0.009999    -0.015+/-0.010        10000
1      Z0 X1 X3 -0.0796  0.009969    -0.080+/-0.010        10000
2            Z2  0.8770  0.004805     0.877+/-0.005        10000
3      Z0 X1 Y3 -0.0142  0.009999    -0.014+/-0.010        10000
4   X0 X1 Y2 Y3 -0.4594  0.008883    -0.459+/-0.009        10000
5         Y1 X3 -0.0096  0.010000    -0.010+/-0.010        10000
6   X0 Z1 X2 Z3  0.1522  0.009884     0.152+/-0.010        10000
7   Z0 X1 Z2 X3 -0.1412  0.009900    -0.141+/-0.010        10000
8      Y1 Z2 X3 -0.0142  0.009999    -0.014+/-0.010        10000
9         Z0 Z1 -0.9806  0.001960  -0.9806+/-0.0020        10000
10        Z0 Z3  0.9806  0.001960   0.9806+/-0.0020        10000
11     Z0 Z1 Z2 -0.8868  0.004622    -0.887+/-0.005        10000
12     Z0 Y1 Y3 -0.0796  0.009969    -0.080+/-0.010        10000
13     Y0 Z1 Y2 -0.1040  0.009946    -0.104+/-0.010        10000
14  X0 Y1 Y2 X3  0.4594  0.008883     0.459+/-0.009        10000
15  Z0 X1 Z2 Y3 -0.0096  0.010000    -0.010+/-0.010        10000
16  Y0 Z1 Y2 Z3  0.1522  0.009884     0.152+/-0.010        10000
17     X0 Z1 X2 -0.1040  0.009946    -0.104+/-0.010        10000
18  Y0 Y1 X2 Y3 -0.0082  0.010000    -0.008+/-0.010        10000
19        Y1 Y3  0.1412  0.009900     0.141+/-0.010        10000
20     Y0 Y2 Z3  0.1040  0.009946     0.104+/-0.010        10000
21        X0 Y2  0.0038  0.010000     0.004+/-0.010        10000
22  Z0 Z1 Z2 Z3  1.0000  0.000000           1.0+/-0        10000
23        X0 X2 -0.1522  0.009884    -0.152+/-0.010        10000
24     Z0 Z2 Z3  0.8868  0.004622     0.887+/-0.005        10000
25        Y0 Y2 -0.1522  0.009884    -0.152+/-0.010        10000
26     Z0 Z1 Z3  0.8770  0.004805     0.877+/-0.005        10000
27  X0 Y1 X2 X3 -0.0028  0.010000    -0.003+/-0.010        10000
28  X0 Y1 Y2 Y3  0.0082  0.010000     0.008+/-0.010        10000
29  Y0 X1 X2 Y3  0.4594  0.008883     0.459+/-0.009        10000
30           Z0 -0.8770  0.004805    -0.877+/-0.005        10000
31     Y1 Z2 Y3  0.0796  0.009969     0.080+/-0.010        10000
32           Z3 -0.8868  0.004622    -0.887+/-0.005        10000
33  X0 X1 Y2 X3  0.0082  0.010000     0.008+/-0.010        10000
34     Z1 Z2 Z3 -0.8770  0.004805    -0.877+/-0.005        10000
35        Z0 Z2 -1.0000  0.000000          -1.0+/-0        10000
36        Z1 Z2  0.9806  0.001960   0.9806+/-0.0020        10000
37  Z0 Y1 Z2 X3  0.0096  0.010000     0.010+/-0.010        10000
38  Y0 X1 Y2 Y3  0.0028  0.010000     0.003+/-0.010        10000
39  Y0 X1 X2 X3 -0.0082  0.010000    -0.008+/-0.010        10000
40  X0 Y1 X2 Y3 -0.4784  0.008782    -0.478+/-0.009        10000
41        Z1 Z3 -1.0000  0.000000          -1.0+/-0        10000
42     Z0 Y1 X3  0.0142  0.009999     0.014+/-0.010        10000
43     X1 Z2 Y3  0.0142  0.009999     0.014+/-0.010        10000
44  Z0 Y1 Z2 Y3 -0.1412  0.009900    -0.141+/-0.010        10000
45  Y0 X1 Y2 X3 -0.4784  0.008782    -0.478+/-0.009        10000
46  Y0 Y1 Y2 X3 -0.0028  0.010000    -0.003+/-0.010        10000
47     X0 Z1 Y2  0.0148  0.009999     0.015+/-0.010        10000
48  X0 Z1 Y2 Z3 -0.0038  0.010000    -0.004+/-0.010        10000
49  Y0 Y1 Y2 Y3 -0.4784  0.008782    -0.478+/-0.009        10000
50     X1 Z2 X3  0.0796  0.009969     0.080+/-0.010        10000
51  Y0 Y1 X2 X3 -0.4594  0.008883    -0.459+/-0.009        10000
52        Y0 X2 -0.0038  0.010000    -0.004+/-0.010        10000
53  Y0 Z1 X2 Z3  0.0038  0.010000     0.004+/-0.010        10000
54  X0 X1 X2 X3 -0.4784  0.008782    -0.478+/-0.009        10000
55        Z2 Z3 -0.9806  0.001960  -0.9806+/-0.0020        10000
56        X1 X3  0.1412  0.009900     0.141+/-0.010        10000
57     Y0 X2 Z3  0.0148  0.009999     0.015+/-0.010        10000
58     X0 X2 Z3  0.1040  0.009946     0.104+/-0.010        10000
59  X0 X1 X2 Y3  0.0028  0.010000     0.003+/-0.010        10000
60     X0 Y2 Z3 -0.0148  0.009999    -0.015+/-0.010        10000
61        X1 Y3  0.0096  0.010000     0.010+/-0.010        10000
62           Z1  0.8868  0.004622     0.887+/-0.005        10000
Circuits measured:
    Qubits Depth Depth2q DepthCX  Shots
0        4    44      25      25  10000
1        4    42      23      23  10000
2        4    43      24      24  10000
3        4    42      23      23  10000
4        4    41      23      23  10000
5        4    42      23      23  10000
Sum      -     -       -       -  60000

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]