common.title

Docs
Quantum Circuit
TYTAN CLOUD

QUANTUM GAMING


Desktop RAG

Overview
Terms of service

Privacy policy

Contact
Research

Sign in
Sign up
common.title

cuStateVec from blueqat SDK

Yuichiro Minato

2022/11/13 01:16

NVIDIA has released a quantum computer simulator, cuStateVec. It shows its power on multiple GPUs, but blueqat does not currently consider multi-GPU support, and we recommend using it with cirq + qsim from google. However, if you want to use cirq or qsim on a standalone GPU, I think it is difficult to use cirq or cuStateVec directly.

Since I have not been able to explore cuStateVec in depth (as we are working on cuTensorNet a lot), but I will try to connect it to blueqat in the sense that it can be used for the time being.

1,Prepare the state vector in the initial state.

2, Define and apply gates at each gate stage.

This is all. It is easy to do.

import numpy as np
from blueqat.backends.backendbase import Backend
from blueqat import BlueqatGlobalSetting
from blueqat import Circuit
import cupy as cp
import cuquantum
from cuquantum import custatevec as cusv

class CuSv(Backend):

def \_preprocess\_run(self, gates, n\_qubits, args, kwargs):
    
    h\_sv = np.asarray(np.full(2\*\*n\_qubits,0.0+0.0j), dtype=np.complex64)
    h\_sv\[0\] = 1.0+0.0j
    d\_sv = cp.asarray(h\_sv)
    return gates, (d\_sv, n\_qubits)

def \_postprocess\_run(self, ctx):
    print(ctx\[0\])
    return 

def \_one\_qubit\_gate\_noargs(self, gate, ctx):
    for idx in gate.target\_iter(ctx\[1\]):
        
        #if you want a new gate please write down here.
        if gate.lowername == "x":
            matrix = cp.asarray(\[0.0+0.0j, 1.0+0.0j, 1.0+0.0j, 0.0+0.0j\], dtype=np.complex64)                
        else:
            matrix = cp.asarray(\[1.0+0.0j, 0.0+0.0j, 0.0+0.0j, 1.0+0.0j\], dtype=np.complex64)                

        nIndexBits = ctx\[1\]
        nSvSize    = (1 << nIndexBits)
        nTargets   = 1
        nControls  = 0
        adjoint    = 0

        targets    = np.asarray(\[idx\], dtype=np.int32)
        controls   = np.asarray(\[\], dtype=np.int32)

        if isinstance(matrix, cp.ndarray):
            matrix\_ptr = matrix.data.ptr
        elif isinstance(matrix, np.ndarray):
            matrix\_ptr = matrix.ctypes.data
        else:
            raise ValueError

        # cuStateVec handle initialization
        handle = cusv.create()
        workspaceSize = cusv.apply\_matrix\_get\_workspace\_size(
            handle, cuquantum.cudaDataType.CUDA\_C\_32F, nIndexBits, matrix\_ptr, cuquantum.cudaDataType.CUDA\_C\_32F,
            cusv.MatrixLayout.ROW, adjoint, nTargets, nControls, cuquantum.ComputeType.COMPUTE\_32F)

        # check the size of external workspace
        if workspaceSize > 0:
            workspace = cp.cuda.memory.alloc(workspaceSize)
            workspace\_ptr = workspace.ptr
        else:
            workspace\_ptr = 0

        # apply gate
        cusv.apply\_matrix(
            handle, ctx\[0\].data.ptr, cuquantum.cudaDataType.CUDA\_C\_32F, nIndexBits, matrix\_ptr, cuquantum.cudaDataType.CUDA\_C\_32F,
            cusv.MatrixLayout.ROW, adjoint, targets.ctypes.data, nTargets, controls.ctypes.data, 0, nControls,
            cuquantum.ComputeType.COMPUTE\_32F, workspace\_ptr, workspaceSize)

        # destroy handle
        cusv.destroy(handle)

    return ctx

gate\_x = \_one\_qubit\_gate\_noargs
gate\_y = \_one\_qubit\_gate\_noargs
gate\_z = \_one\_qubit\_gate\_noargs
gate\_h = \_one\_qubit\_gate\_noargs
gate\_t = \_one\_qubit\_gate\_noargs
gate\_s = \_one\_qubit\_gate\_noargs

def \_one\_qubit\_gate\_args\_theta(self, gate, ctx):
    return ctx

gate\_rx = \_one\_qubit\_gate\_args\_theta
gate\_ry = \_one\_qubit\_gate\_args\_theta
gate\_rz = \_one\_qubit\_gate\_args\_theta
gate\_phase = \_one\_qubit\_gate\_args\_theta

def \_two\_qubit\_gate\_noargs(self, gate, ctx):
    for control, target in gate.control\_target\_iter(ctx\[1\]):
        
        if gate.lowername == "cx":
            matrix = cp.asarray(\[0.0+0.0j, 1.0+0.0j, 1.0+0.0j, 0.0+0.0j\], dtype=np.complex64)                
        else:
            matrix = cp.asarray(\[1.0+0.0j, 0.0+0.0j, 0.0+0.0j, 1.0+0.0j\], dtype=np.complex64)                

        nIndexBits = ctx\[1\]
        nSvSize    = (1 << nIndexBits)
        nTargets   = 1
        nControls  = 1
        adjoint    = 0

        targets    = np.asarray(\[target\], dtype=np.int32)
        controls   = np.asarray(\[control\], dtype=np.int32)

        if isinstance(matrix, cp.ndarray):
            matrix\_ptr = matrix.data.ptr
        elif isinstance(matrix, np.ndarray):
            matrix\_ptr = matrix.ctypes.data
        else:
            raise ValueError

        # cuStateVec handle initialization
        handle = cusv.create()
        workspaceSize = cusv.apply\_matrix\_get\_workspace\_size(
            handle, cuquantum.cudaDataType.CUDA\_C\_32F, nIndexBits, matrix\_ptr, cuquantum.cudaDataType.CUDA\_C\_32F,
            cusv.MatrixLayout.ROW, adjoint, nTargets, nControls, cuquantum.ComputeType.COMPUTE\_32F)

        # check the size of external workspace
        if workspaceSize > 0:
            workspace = cp.cuda.memory.alloc(workspaceSize)
            workspace\_ptr = workspace.ptr
        else:
            workspace\_ptr = 0

        # apply gate
        cusv.apply\_matrix(
            handle, ctx\[0\].data.ptr, cuquantum.cudaDataType.CUDA\_C\_32F, nIndexBits, matrix\_ptr, cuquantum.cudaDataType.CUDA\_C\_32F,
            cusv.MatrixLayout.ROW, adjoint, targets.ctypes.data, nTargets, controls.ctypes.data, 0, nControls,
            cuquantum.ComputeType.COMPUTE\_32F, workspace\_ptr, workspaceSize)

        # destroy handle
        cusv.destroy(handle)
    return ctx

gate\_cx = gate\_cy = gate\_cz = \_two\_qubit\_gate\_noargs

def \_three\_qubit\_gate\_noargs(self, gate, ctx):
    return ctx

gate\_ccx = \_three\_qubit\_gate\_noargs
gate\_cswap = \_three\_qubit\_gate\_noargs

def gate\_measure(self, gate, ctx):
    return ctx

gate\_reset = \_one\_qubit\_gate\_noargs

BlueqatGlobalSetting.register_backend('cusv', CuSv)

it's done.

from blueqat import Circuit

Circuit(3).x[0,1,2].cx[0,1].run(backend="cusv")
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j]

It worked. If you add a sampling function or an expectation value calculation function, you can use it for NISQ as usual. You can use the existing blueqat application assets so please try it out. We will make more if there are any requests.

© 2025, blueqat Inc. All rights reserved