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.compile_circuits()
protocol.run(seed=2)
<inquanto.protocols.averaging._pauli_averaging.PauliAveraging at 0x7f44017b1310>

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  Standard error  Sample size
0      Z0 X1 X3 -0.0970        0.009953        10000
1            Z2  0.8812        0.004728        10000
2   X0 X1 Y2 Y3 -0.4608        0.008875        10000
3   Z0 X1 Z2 X3 -0.1606        0.009871        10000
4   X0 Z1 X2 Z3  0.1628        0.009867        10000
5         Z0 Z1 -0.9844        0.001760        10000
6         Z0 Z3  0.9844        0.001760        10000
7      Z0 Z1 Z2 -0.8786        0.004776        10000
8      Z0 Y1 Y3 -0.0970        0.009953        10000
9      Y0 Z1 Y2 -0.1114        0.009938        10000
10  X0 Y1 Y2 X3  0.4608        0.008875        10000
11  Y0 Z1 Y2 Z3  0.1628        0.009867        10000
12     X0 Z1 X2 -0.1114        0.009938        10000
13        Y1 Y3  0.1606        0.009871        10000
14     Y0 Y2 Z3  0.1114        0.009938        10000
15  Z0 Z1 Z2 Z3  1.0000        0.000000        10000
16        X0 X2 -0.1628        0.009867        10000
17     Z0 Z2 Z3  0.8786        0.004776        10000
18        Y0 Y2 -0.1628        0.009867        10000
19     Z0 Z1 Z3  0.8812        0.004728        10000
20  Y0 X1 X2 Y3  0.4608        0.008875        10000
21           Z0 -0.8812        0.004728        10000
22     Y1 Z2 Y3  0.0970        0.009953        10000
23           Z3 -0.8786        0.004776        10000
24     Z1 Z2 Z3 -0.8812        0.004728        10000
25        Z0 Z2 -1.0000        0.000000        10000
26        Z1 Z2  0.9844        0.001760        10000
27  X0 Y1 X2 Y3 -0.4764        0.008793        10000
28        Z1 Z3 -1.0000        0.000000        10000
29  Z0 Y1 Z2 Y3 -0.1606        0.009871        10000
30  Y0 X1 Y2 X3 -0.4764        0.008793        10000
31  Y0 Y1 Y2 Y3 -0.4764        0.008793        10000
32     X1 Z2 X3  0.0970        0.009953        10000
33  Y0 Y1 X2 X3 -0.4608        0.008875        10000
34  X0 X1 X2 X3 -0.4764        0.008793        10000
35        Z2 Z3 -0.9844        0.001760        10000
36        X1 X3  0.1606        0.009871        10000
37     X0 X2 Z3  0.1114        0.009938        10000
38           Z1  0.8786        0.004776        10000
Circuits measured:
    Qubits Depth Count Depth2q Count2q DepthCX CountCX  Shots
0        4    46    58      25      25      25      25  10000
1        4    54    75      32      35      32      35  10000
2        4    45    58      25      25      25      25  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]