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)
–
-
assigned_qubits
(list)
–
-
state_vector
(ndarray)
–
-
qubits
(int)
–
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:
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:
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:
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:
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:
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)
–
-
qubits
(int)
–
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)
–
-
qubits
(int)
–
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
|