跳转至

GateSimulator

QuICT.simulation.utils.GateSimulator

GateSimulator(device, precision: str = 'double', gpu_device_id: int = 0, sync: bool = True, enable_gfunc: bool = True)

The class of simulation functions, including State Vector Creation, Density Matrix Creation, Quantum Gate's Matrix aggregation and Quantum Gate Algorithms.

Parameters:

  • device (str) –

    The device type, one of [CPU, GPU]. Defaults to "CPU".

  • precision (str, default: 'double' ) –

    The precision for the state vector, one of [single, double]. Defaults to "double".

  • gpu_device_id (int, default: 0 ) –

    The GPU device ID. Defaults to 0.

  • sync (bool, default: True ) –

    Sync mode or Async mode. Defaults to True.

  • enable_gfunc (bool, default: True ) –

    Whether use Quantum Gate Algorithm. Defaults to True.

Source code in QuICT/simulation/utils/apply_gate.py
def __init__(
    self,
    device,
    precision: str = "double",
    gpu_device_id: int = 0,
    sync: bool = True,
    enable_gfunc: bool = True
):
    """
    Args:
        device (str, optional): The device type, one of [CPU, GPU]. Defaults to "CPU".
        precision (str, optional): The precision for the state vector, one of [single, double].
            Defaults to "double".
        gpu_device_id (int, optional): The GPU device ID. Defaults to 0.
        sync (bool, optional): Sync mode or Async mode. Defaults to True.
        enable_gfunc (bool, optional): Whether use Quantum Gate Algorithm. Defaults to True.
    """
    if device not in ["CPU", "GPU"]:
        raise ValueError("Simulation.device", "[CPU, GPU]", device)

    if precision not in ["single", "double"]:
        raise ValueError("Simulation.precision", "[single, double]", precision)

    self._device = device
    self._precision = precision
    self._dtype = np.complex128 if precision == "double" else np.complex64
    self._gpu_device_id = gpu_device_id
    self._sync = sync

    # Gate's Matrix Store
    self._gate_matrix_generator = GateMatrixGenerator()
    self._gate_matrix_info: dict = {}   # Record gate's matrix info (location, length)
    self._gates_matrix = None

    # cupy/numpy and Gate Kernel functions
    self._algorithm = LinAlgLoader(device=device, enable_gate_kernel=enable_gfunc)
    if self._device == "GPU":
        import cupy as cp

        self._array_helper = cp
        cp.cuda.runtime.setDevice(self._gpu_device_id)
    else:
        self._array_helper = np

apply_gate

apply_gate(gate: BasicGate, assigned_qubits: list, state_vector: ndarray, qubits: int, fp: bool = True, parg_id: int = 0)

Apply the kernel function of Quantum Gate to the State Vector.

Parameters:

  • gate (BasicGate) –

    the Quantum Gate

  • assigned_qubits (list) –

    The gate's qubit indexes

  • state_vector (ndarray) –

    The State Vector

  • qubits (int) –

    the number of qubits

Source code in QuICT/simulation/utils/apply_gate.py
def apply_gate(
    self,
    gate: BasicGate,
    assigned_qubits: list,
    state_vector: np.ndarray,
    qubits: int,
    fp: bool = True,
    parg_id: int = 0,
):
    """ Apply the kernel function of Quantum Gate to the State Vector.

    Args:
        gate (BasicGate): the Quantum Gate
        assigned_qubits (list): The gate's qubit indexes
        state_vector (np.ndarray): The State Vector
        qubits (int): the number of qubits
    """
    gate_type = gate.type
    if gate_type in [GateType.id, GateType.barrier] or gate.is_identity():
        return

    gate_cargs = [qubits - 1 - assigned_qubits[i] for i in range(gate.controls)]
    gate_targs = [
        qubits - 1 - assigned_qubits[i]
        for i in range(gate.controls, len(assigned_qubits))
    ]

    if self._device == "CPU":
        return self._apply_gate_cpu(
            gate, gate_cargs, gate_targs, state_vector, fp, parg_id
        )
    else:
        return self._apply_gate_gpu(
            gate, gate_cargs, gate_targs, state_vector, qubits, fp, parg_id
        )

gate_matrix_combined

gate_matrix_combined(circuit)

the aggregation of Quantum Gates' matrix in the given Quantum Circuit.

Parameters:

  • circuit (Circuit) –

    The Quantum Circuit.

Source code in QuICT/simulation/utils/apply_gate.py
def gate_matrix_combined(self, circuit):
    """ the aggregation of Quantum Gates' matrix in the given Quantum Circuit.

    Args:
        circuit (Circuit): The Quantum Circuit.
    """
    matrix_list_for_gpu_only = []
    total_matrix_size = 0 if self._gates_matrix is None else self._gates_matrix.size
    if total_matrix_size >= (1 << 10):
        return

    for gate in circuit.flatten_gates():
        if (
            not isinstance(gate, BasicGate)
            or gate.type in [
                GateType.measure, GateType.reset, GateType.barrier,
                GateType.unitary, GateType.kraus, GateType.perm
            ]
            or gate.matrix_type == MatrixType.special
        ):
            continue

        gate_name = self._generate_gate_name_for_matrix_stored(gate.type, gate.pargs)
        if gate_name not in self._gate_matrix_info.keys():
            matrix = self._gate_matrix_generator.get_matrix(gate, self._precision, True)

            if self._device == "CPU":
                self._gate_matrix_info[gate_name] = matrix
            else:
                self._gate_matrix_info[gate_name] = (total_matrix_size, matrix.size)
                total_matrix_size += matrix.size
                matrix_list_for_gpu_only.append(matrix)

    if len(matrix_list_for_gpu_only) > 0:
        self._concentrate_gate_matrixs(matrix_list_for_gpu_only, total_matrix_size)

get_allzero_density_matrix

get_allzero_density_matrix(qubits: int)

Return the empty Density Matrix with size equals 1 << qubits.

Parameters:

  • qubits (int) –

    The number of qubits.

Returns:

  • np.ndarray: the Density Matrix

Source code in QuICT/simulation/utils/apply_gate.py
def get_allzero_density_matrix(self, qubits: int):
    """ Return the empty Density Matrix with size equals 1 << qubits.

    Args:
        qubits (int): The number of qubits.

    Returns:
        np.ndarray: the Density Matrix
    """
    density_matrix = self._array_helper.zeros((1 << qubits, 1 << qubits), dtype=self._dtype)
    density_matrix[0, 0] = self._dtype(1)

    return density_matrix

get_allzero_state_vector

get_allzero_state_vector(qubits: int)

Return the State Vector with all-zeros state and size equals 1 << qubits.

Parameters:

  • qubits (int) –

    The number of qubits.

Returns:

  • np.ndarray: the State Vector

Source code in QuICT/simulation/utils/apply_gate.py
def get_allzero_state_vector(self, qubits: int):
    """ Return the State Vector with all-zeros state and size equals 1 << qubits.

    Args:
        qubits (int): The number of qubits.

    Returns:
        np.ndarray: the State Vector
    """
    state_vector = self.get_empty_state_vector(qubits)
    state_vector[0] = self._dtype(1)

    return state_vector

get_empty_density_matrix

get_empty_density_matrix(qubits: int)

Return the Density Matrix with all-zeros state and size equals 1 << qubits.

Parameters:

  • qubits (int) –

    The number of qubits.

Returns:

  • np.ndarray: the Density Matrix

Source code in QuICT/simulation/utils/apply_gate.py
def get_empty_density_matrix(self, qubits: int):
    """ Return the Density Matrix with all-zeros state and size equals 1 << qubits.

    Args:
        qubits (int): The number of qubits.

    Returns:
        np.ndarray: the Density Matrix
    """
    return self._array_helper.zeros((1 << qubits, 1 << qubits), dtype=self._dtype)

get_empty_state_vector

get_empty_state_vector(qubits: int)

Return the empty State Vector with size equals 1 << qubits.

Parameters:

  • qubits (int) –

    The number of qubits.

Returns:

  • np.ndarray: the State Vector

Source code in QuICT/simulation/utils/apply_gate.py
def get_empty_state_vector(self, qubits: int):
    """ Return the empty State Vector with size equals 1 << qubits.

    Args:
        qubits (int): The number of qubits.

    Returns:
        np.ndarray: the State Vector
    """
    return self._array_helper.zeros(1 << qubits, dtype=self._dtype)

is_identity

is_identity(unitary_matrix)

Whether the given unitary matrix is identity matrix.

Source code in QuICT/simulation/utils/apply_gate.py
def is_identity(self, unitary_matrix):
    """ Whether the given unitary matrix is identity matrix. """
    row = unitary_matrix.shape[0]
    if row > (1 << (THRESHOLD_QUBITS // 2)):
        return False

    identity_matrix = np.identity(row, dtype=self._dtype)
    if self.device == "GPU":
        return np.allclose(unitary_matrix.get(), identity_matrix)
    else:
        return np.allclose(unitary_matrix, identity_matrix)

normalized_matrix

normalized_matrix(unitary_matrix, qubits: int)

Normalized the Unitary Matrix

Parameters:

  • unitary_matrix (ndarray) –

    The Unitary Matrix

  • qubits (int) –

    The number of qubits.

Returns:

  • np.ndarray: the normalized Unitary Matrix

Source code in QuICT/simulation/utils/apply_gate.py
def normalized_matrix(self, unitary_matrix, qubits: int):
    """ Normalized the Unitary Matrix

    Args:
        unitary_matrix (np.ndarray): The Unitary Matrix
        qubits (int): The number of qubits.

    Returns:
        np.ndarray: the normalized Unitary Matrix
    """
    row, col = unitary_matrix.shape
    assert 1 << qubits == row and row == col, "The unitary matrix should be square."
    if not type(unitary_matrix) is self._array_helper.ndarray:
        unitary_matrix = self._array_helper.array(unitary_matrix, dtype=self._dtype)

    if unitary_matrix.dtype != self._dtype:
        unitary_matrix = unitary_matrix.astype(self._dtype)

    return unitary_matrix

normalized_state_vector

normalized_state_vector(state_vector, qubits: int)

Normalize the given State Vector, including the size check and type translate.

Parameters:

  • state_vector (ndarray) –

    The given State Vector

  • qubits (int) –

    The number of qubits

Returns:

  • np.ndarray: the normalized State Vector

Source code in QuICT/simulation/utils/apply_gate.py
def normalized_state_vector(self, state_vector, qubits: int):
    """ Normalize the given State Vector, including the size check and type translate.

    Args:
        state_vector (np.ndarray): The given State Vector
        qubits (int): The number of qubits

    Returns:
        np.ndarray: the normalized State Vector
    """
    assert 1 << qubits == state_vector.size, "The state vector should has the same qubits with the circuit."
    if not type(state_vector) is self._array_helper.ndarray:
        state_vector = self._array_helper.array(state_vector, dtype=self._dtype)

    if state_vector.dtype != self._dtype:
        state_vector = state_vector.astype(self._dtype)

    return state_vector

validate_density_matrix

validate_density_matrix(matrix) -> bool

Density Matrix Validation.

Source code in QuICT/simulation/utils/apply_gate.py
def validate_density_matrix(self, matrix) -> bool:
    """ Density Matrix Validation. """
    if not isinstance(matrix, np.ndarray):
        matrix = matrix.get()

    if not np.allclose(matrix.T.conjugate(), matrix):
        raise ValueError("The conjugate transpose of density matrix do not equal to itself.")

    eigenvalues = np.linalg.eig(matrix)[0]
    for ev in eigenvalues:
        if ev < 0 and not np.isclose(ev, 0, rtol=1e-4):
            raise ValueError("The eigenvalues of density matrix should be non-negative")

    if not np.isclose(matrix.trace(), 1, rtol=1e-4):
        raise ValueError("The sum of trace of density matrix should be 1.")

    return True