Problems on VQE with cuda

Hello! I’m still quite new here and I hope I can get some help.

I’m trying to conduct a VQE algorithm on a numpy Hermition matrix. When runing with CPU, I used hermitian = qml.Hermitian(matrixReal, wires=range(qubits)) H = qml.Hamiltonian((1, ), (hermitian, )) to convert the numpy matrixReal to a Hamiltonian operator and use it to obtain the energy ``. It works.

However, when I try to use cuda for acceleration, it failed and put out an error sayinig

Can only compute sparse representation for tensors whose operations act on consecutive wires;

Here is my code. The error occurs on line loss = ansatz(params, H)

import numpy as np
import pennylane as qml
import matplotlib.pyplot as plt
import time
import torch
from torch.optim.lr_scheduler import StepLR

def qmlVQE(matrix, maxIter=800, rate=0.1, reps=60):
    timeStart = time.time()
    
    matrixReal = complexToRealMatrix(matrix)
    qubits = round(np.log2(matrixReal.shape[0]))

    dev = qml.device('default.qubit.torch', wires=qubits)
    base = torch.tensor(np.random.random(size=qubits * 2 * reps), device='cuda')
    base.requires_grad = True
    

    @qml.qnode(dev, interface='torch')
    def ansatz(params, H):
        cnt = 0
        for index in range(reps):
            for i in range(qubits):
                qml.RY(params[cnt], wires=[i])
                cnt += 1
            for i in range(qubits):
                qml.RZ(params[cnt], wires=[i])
                cnt += 1
            for i in range(qubits-1)[(index%2)::2]:
                qml.CNOT(wires=[i, i+1]);
            qml.Barrier(wires=range(qubits))
        return qml.expval(H)
    
    def ansatzState(params):
        cnt = 0
        for index in range(reps):
            for i in range(qubits):
                qml.RY(params[cnt], wires=[i])
                cnt += 1
            for i in range(qubits):
                qml.RZ(params[cnt], wires=[i])
                cnt += 1
            for i in range(qubits-1)[(index%2)::2]:
                qml.CNOT(wires=[i, i+1]);
            qml.Barrier(wires=range(qubits))
        return qml.state()

    history = []
    plt.figure()
    def callBack(energy):
        plt.clf()
        plt.ion()
        history.append(energy)
        plt.title("Objective function value against iteration")
        plt.xlabel("Iteration")
        plt.ylabel("Objective function value")
        plt.plot(range(len(history)), history)
        plt.axhline(y=energy, color='black', linestyle='--')
        plt.text(0.8,0.2, f'Latest : {energy:.4f}', color='black', ha='center', transform=plt.gcf().transFigure)
        plt.draw()
        plt.pause(0.15)

    hermitian = qml.Hermitian(matrixReal, wires=range(qubits))
    H = qml.Hamiltonian((1, ), (hermitian, ))
    
    def train(params):
        opt = torch.optim.Adam([params], lr=rate)
        scheduler = StepLR(opt, step_size=10, gamma=0.99)

        def closure():
            opt.zero_grad()
            loss = ansatz(params, H)
            loss.backward()
            return loss
        
        for n in range(maxIter):
            l = opt.step(closure)
            timeEnd = time.time()
            value = l.item()
            callBack(value)
            print(f"Step = {n},  Value = {value:.8f}, Time = {(timeEnd - timeStart):.2f}")
            scheduler.step()

        return params
    
    params = train(base)
    psiQuantum = ansatzState(params)
    psi = realToComplexEigen(psiQuantum.cpu().detach().numpy().reshape(-1, 1))
    plt.ioff()
    return psi

Thanks for any assistance!

Hi @Chenjia , welcome to the Forum!

It looks like the error is arising from sparse_matrix but I’m not sure where the error is coming from.

Could you please provide the following information? It can help us understand the problem and find possible solutions:

  1. The output of qml.about()

  2. A minimal (but self-contained) working example
    This is the simplest version of the code that reproduces the problem. It should include all necessary imports, data, functions, etc., so that we can copy-paste the code and reproduce the problem. However it shouldn’t contain any unnecessary data, functions, …, for example gates and functions that can be removed to simplify the code.

  3. The full error traceback.

If you’re not sure what these mean then make sure to check out this video.

I look forward to seeing your answers and please let me know if you have any additional questions!

1 Like

Thanks. Here are my code and other information.

  • qml.about()
    0.00s - Debugger warning: It seems that frozen modules are being used, which may
    0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
    0.00s - to python to disable frozen modules.
    0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.
    Name: PennyLane
    Version: 0.35.0
    Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
    Home-page: https://github.com/PennyLaneAI/pennylane
    Author: 
    Author-email: 
    License: Apache License 2.0
    Location: /home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages
    Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
    Required-by: PennyLane_Lightning
    
    Platform info:           Linux-6.5.0-41-generic-x86_64-with-glibc2.35
    Python version:          3.11.8
    Numpy version:           1.26.4
    Scipy version:           1.12.0
    Installed devices:
    - default.clifford (PennyLane-0.35.0)
    - default.gaussian (PennyLane-0.35.0)
    - default.mixed (PennyLane-0.35.0)
    - default.qubit (PennyLane-0.35.0)
    - default.qubit.autograd (PennyLane-0.35.0)
    - default.qubit.jax (PennyLane-0.35.0)
    - default.qubit.legacy (PennyLane-0.35.0)
    - default.qubit.tf (PennyLane-0.35.0)
    - default.qubit.torch (PennyLane-0.35.0)
    - default.qutrit (PennyLane-0.35.0)
    - null.qubit (PennyLane-0.35.0)
    - lightning.qubit (PennyLane_Lightning-0.35.0)
    None
    
  • An example of my problem
    import numpy as np
    import pennylane as qml
    import matplotlib.pyplot as plt
    import time
    import torch
    from torch.optim.lr_scheduler import StepLR
    
    def complexToRealMatrix(A):
        import numpy as np
        n = A.shape[0]
        B = np.zeros((2*n, 2*n))
        B[::2, ::2] = A.real
        B[::2, 1::2] = -A.imag
        B[1::2, ::2] = A.imag
        B[1::2, 1::2] = A.real
        return B
    
    def realToComplexEigen(eigvecs):
        import numpy as np
        real = eigvecs[::2]
        imaginary = eigvecs[1::2]
        finalEigvec = real + 1j * imaginary
        return finalEigvec
    
    def qmlVQE(matrix, maxIter=800, rate=0.1, reps=60):
        timeStart = time.time()
        
        matrixReal = complexToRealMatrix(matrix)
        qubits = round(np.log2(matrixReal.shape[0]))
    
        dev = qml.device('default.qubit.torch', wires=qubits, torch_device="cuda:0")
        base = torch.tensor(np.random.random(size=qubits * 2 * reps), device='cuda')
        base.requires_grad = True
        
    
        @qml.qnode(dev, interface='torch')
        def ansatz(params, H):
            cnt = 0
            for index in range(reps):
                for i in range(qubits):
                    qml.RY(params[cnt], wires=[i])
                    cnt += 1
                for i in range(qubits):
                    qml.RZ(params[cnt], wires=[i])
                    cnt += 1
                for i in range(qubits-1)[(index%2)::2]:
                    qml.CNOT(wires=[i, i+1]);
                qml.Barrier(wires=range(qubits))
            return qml.expval(H)
        
        def ansatzState(params):
            cnt = 0
            for index in range(reps):
                for i in range(qubits):
                    qml.RY(params[cnt], wires=[i])
                    cnt += 1
                for i in range(qubits):
                    qml.RZ(params[cnt], wires=[i])
                    cnt += 1
                for i in range(qubits-1)[(index%2)::2]:
                    qml.CNOT(wires=[i, i+1]);
                qml.Barrier(wires=range(qubits))
            return qml.state()
    
        history = []
        plt.figure()
        def callBack(energy):
            plt.clf()
            plt.ion()
            history.append(energy)
            plt.title("Objective function value against iteration")
            plt.xlabel("Iteration")
            plt.ylabel("Objective function value")
            plt.plot(range(len(history)), history)
            plt.axhline(y=energy, color='black', linestyle='--')
            plt.text(0.8,0.2, f'Latest : {energy:.4f}', color='black', ha='center', transform=plt.gcf().transFigure)
            plt.draw()
            plt.pause(0.15)
    
        hermitian = qml.Hermitian(matrixReal, wires=range(qubits))
        H = qml.Hamiltonian((1, ), (hermitian, ))
        
        def train(params):
            opt = torch.optim.Adam([params], lr=rate)
            scheduler = StepLR(opt, step_size=10, gamma=0.99)
    
            def closure():
                opt.zero_grad()
                loss = ansatz(params, H)
                loss.backward()
                return loss
            
            for n in range(maxIter):
                l = opt.step(closure)
                timeEnd = time.time()
                value = l.item()
                callBack(value)
                print(f"Step = {n},  Value = {value:.8f}, Time = {(timeEnd - timeStart):.2f}")
                scheduler.step()
    
            return params
        
        params = train(base)
        psiQuantum = ansatzState(params)
        psi = realToComplexEigen(psiQuantum.cpu().detach().numpy().reshape(-1, 1))
        plt.ioff()
        return psi
    
    
    print(qml.about())
    n = 2 ** 10
    A = np.random.rand(n, n) + 1j * np.random.rand(n, n)
    matrix = (A + A.conj().T) / 2 # Assume H is a random Hermite matrix in numpy
    psi = qmlVQE(matrix = matrix)
    print(psi)
    
  • Full error traceback
    Traceback (most recent call last):
    File "/home/zcjrony/桌面/PennnyLane/vqes.py", line 118, in <module>
    psi = qmlVQE(matrix = H)
            ^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/桌面/PennnyLane/vqes.py", line 107, in qmlVQE
    params = train(base)
                ^^^^^^^^^^^
    File "/home/zcjrony/桌面/PennnyLane/vqes.py", line 98, in train
    l = opt.step(closure)
        ^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/torch/optim/lr_scheduler.py", line 75, in wrapper
    return wrapped(*args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/torch/optim/optimizer.py", line 391, in wrapper
    out = func(*args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/torch/optim/optimizer.py", line 76, in _use_grad
    ret = func(self, *args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/torch/optim/adam.py", line 148, in step
    loss = closure()
            ^^^^^^^^^
    File "/home/zcjrony/桌面/PennnyLane/vqes.py", line 93, in closure
    loss = ansatz(params, H)
            ^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/workflow/qnode.py", line 1048, in __call__
    res = qml.execute(
            ^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/workflow/execution.py", line 684, in execute
    results = inner_execute(tapes)
                ^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/workflow/execution.py", line 283, in inner_execute
    return cached_device_execution(tapes)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/workflow/execution.py", line 361, in wrapper
    res = list(fn(tapes, **kwargs))
                ^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/contextlib.py", line 81, in inner
    return func(*args, **kwds)
            ^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/_qubit_device.py", line 459, in batch_execute
    res = self.execute(circuit)
            ^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/devices/default_qubit_torch.py", line 245, in execute
    return super().execute(circuit, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/_qubit_device.py", line 289, in execute
    results = self.statistics(circuit)
                ^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/_qubit_device.py", line 630, in statistics
    result = self.expval(obs, shot_range=shot_range, bin_size=bin_size)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/devices/default_qubit_legacy.py", line 632, in expval
    coo = qml.operation.Tensor(op).sparse_matrix(wire_order=self.wires, format="coo")
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/zcjrony/anaconda3/envs/pennylane/lib/python3.11/site-packages/pennylane/operation.py", line 2474, in sparse_matrix
    raise ValueError(
    ValueError: Can only compute sparse representation for tensors whose operations act on consecutive wires; got Hermitian(array([[ 0.6530607 , -0.        ,  0.43956737, ..., -0.01520758,
            0.58009441,  0.15327382],
        [ 0.        ,  0.6530607 , -0.04909861, ...,  0.38300196,
        -0.15327382,  0.58009441],
        [ 0.43956737, -0.04909861,  0.51031064, ...,  0.11782081,
            0.87449403, -0.01589164],
        ...,
        [-0.01520758,  0.38300196,  0.11782081, ...,  0.03700643,
        -0.38992576,  0.55237325],
        [ 0.58009441, -0.15327382,  0.87449403, ..., -0.38992576,
            0.97597393, -0.        ],
        [ 0.15327382,  0.58009441, -0.01589164, ...,  0.55237325,
            0.        ,  0.97597393]]), wires=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).
    

Hi @Chenjia ,

It looks like your error is due to the version of the packages that you’re using.

I’d recommend updating your version of PennyLane with python -m pip install pennylane --upgrade. Our latest stable version is v0.37.

I ran your code in Colab and got no issues up to the line: psi = realToComplexEigen(psiQuantum.cpu().detach().numpy().reshape(-1, 1))

Here you’ll get an error because psiQuantum is a state (‘StateMP’ object) so it has no attribute ‘cpu’.

I hope this helps you solve the issue you’re seeing!

It does work! Thanks for your assistance!