Hamiltonian -> Sparse Matrix or expval wrt state

I see that there is a matrix method attached to the qml.Hamiltonian class, but it is not implemented. I am attempting to use a custom loss function for a VQE type computation, and I have a statevector that I’d like to use to compute exp vals wrt. But there’s no obvious way to do this.

Given a statevector sv and a Hamiltonian H, there’s no API for computing <H> wrt sv.

Also, can I use a custom loss function for autograd after using qml.sample?

The idea is this:


def hc(mat :np.ndarray) -> np.ndarray:
    return np.conj(mat.transpose())

symbols = ["H", "H"]
coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])
h2_ham, n_qubits = qchem.molecular_hamiltonian(symbols, coordinates)
n_electrons = 2

singles, doubles = qchem.excitations(n_electrons, n_qubits)
s_wires, d_wires = qchem.excitations_to_wires(singles, doubles)
ref_state = qchem.hf_state(n_electrons, n_qubits)
ansatz = partial(UCCSD, init_state = ref_state, s_wires = s_wires, d_wires = d_wires)

dev_noisy = qml.device('default.mixed', wires = n_qubits, shots = 2)
@qml.qnode(dev_noisy)
def VQE_circuit(params, group, n_qubits):
    ansatz(params, wires=range(n_qubits))
    rotations = qml.grouping.diagonalize_qwc_pauli_words(group)[0]
    return qml.sample(wires=range(n_qubits))

params = np.random.randn(len(s_wires) + len(d_wires))
@qml.qnode(dev_noisy)
def cost(params, H):
    results = [[VQE_circuit(params, group = group, n_qubits = n_qubits)] for group in groupings]
    all_statevecs = process_results(results)
    psi = train(model, all_statevecs, callback_list=callbacks)
    #THIS LINE DOESN'T WORK
    loss = hc(psi)@H.matrix()@psi
    return loss

where psi is the result from training a tensorflow model on the data from VQE_circuit.

Hi @cuhrazatee! As of the latest version of PL (version 0.18), you can now specify expval(H) directly within your QNode:

@qml.qnode(dev_noisy)
def VQE_circuit(params, n_qubits):
    ansatz(params, wires=range(n_qubits))
    return qml.expval(H)

As you are using finite-shots, the grouping and diagonalization will occur automatically under the hood.

Alternatively, if you would like to continue as-is but extract the Hamiltonian numeric representation, can you use the qml.utils.sparse_hamiltonian() function:

>>> coeffs = [0.2, -0.543]
>>> ops = [
...   qml.PauliX(0) @ qml.PauliZ(1),
...   qml.PauliZ(0) @ qml.Hadamard(1)
... ]
>>> H = qml.Hamiltonian(coeffs, ops)
>>> Hmat = qml.utils.sparse_hamiltonian(H).real
>>> Hmat
<4x4 sparse matrix of type '<class 'numpy.float64'>'
        with 12 stored elements in COOrdinate format>

You can then use sparse matrix multiplication, or convert it into a dense array:

>>> Hmat.toarray()
array([[-0.38395898, -0.38395898,  0.2       ,  0.        ],
       [-0.38395898,  0.38395898,  0.        , -0.2       ],
       [ 0.2       ,  0.        ,  0.38395898,  0.38395898],
       [ 0.        , -0.2       ,  0.38395898, -0.38395898]])