Added comments and refactor codes
This commit is contained in:
@@ -3,31 +3,50 @@ import numpy as np
|
|||||||
|
|
||||||
|
|
||||||
class QiboCircuitToEinsum:
|
class QiboCircuitToEinsum:
|
||||||
|
"""This class takes a quantum circuit defined in Qibo (i.e. a Circuit object)
|
||||||
|
and convert it to an equivalent Tensor Network (TN) representation that is formatted for
|
||||||
|
cuQuantum' contract method to compute the state vectors.
|
||||||
|
See document for detail: https://docs.nvidia.com/cuda/cuquantum/python/api/generated/cuquantum.contract.html
|
||||||
|
|
||||||
|
When the class is constructed, it first process the circuit to an intermediate form by extracting the gate matrix
|
||||||
|
and grouping each gate with its corresponding qubit it is acting on to a list.
|
||||||
|
|
||||||
|
It is then converted it to an equivalent TN expression following the Einstein
|
||||||
|
summation convention through the class function state_vector_operand().
|
||||||
|
The output is to be used by cuQuantum's contract() for computation of the state vectors of the circuit.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, circuit, dtype="complex128"):
|
def __init__(self, circuit, dtype="complex128"):
|
||||||
|
def op_shape_from_qubits(nqubits):
|
||||||
|
"""This function is to modify the shape of the tensor to the required format by cuQuantum
|
||||||
|
(qubit_states,) * input_output * qubits_involved
|
||||||
|
"""
|
||||||
|
return (2,) * 2 * nqubits
|
||||||
|
|
||||||
self.backend = cp
|
self.backend = cp
|
||||||
self.dtype = getattr(self.backend, dtype)
|
self.dtype = getattr(self.backend, dtype)
|
||||||
|
|
||||||
self.input_tensor_counter = np.zeros((circuit.nqubits,))
|
|
||||||
self.gate_tensors = []
|
self.gate_tensors = []
|
||||||
|
gates_qubits = []
|
||||||
|
|
||||||
for gate in circuit.queue:
|
for gate in circuit.queue:
|
||||||
for target in gate.target_qubits:
|
|
||||||
self.input_tensor_counter[target] += 1
|
|
||||||
for control in gate.control_qubits:
|
|
||||||
self.input_tensor_counter[control] += 1
|
|
||||||
gate_qubits = gate.control_qubits + gate.target_qubits
|
gate_qubits = gate.control_qubits + gate.target_qubits
|
||||||
|
gates_qubits.extend(gate_qubits)
|
||||||
|
|
||||||
# self.gate_tensors is to extract into a list the gate matrix together with the qubit id that it is acting on
|
# self.gate_tensors is to extract into a list the gate matrix together with the qubit id that it is acting on
|
||||||
|
# https://github.com/NVIDIA/cuQuantum/blob/6b6339358f859ea930907b79854b90b2db71ab92/python/cuquantum/cutensornet/_internal/circuit_parser_utils_cirq.py#L32
|
||||||
|
required_shape = op_shape_from_qubits(len(gate_qubits))
|
||||||
self.gate_tensors.append(
|
self.gate_tensors.append(
|
||||||
(
|
(
|
||||||
cp.asarray(gate.matrix).reshape((2,) * 2 * len(gate_qubits)),
|
cp.asarray(gate.matrix).reshape(required_shape),
|
||||||
gate_qubits,
|
gate_qubits,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# self.active_qubits is to identify qubits with at least 1 gate acting on it in the whole circuit.
|
|
||||||
self.active_qubits = [
|
|
||||||
indx for indx, value in enumerate(self.input_tensor_counter) if value > 0
|
|
||||||
]
|
|
||||||
|
|
||||||
def state_vector(self):
|
# self.active_qubits is to identify qubits with at least 1 gate acting on it in the whole circuit.
|
||||||
|
self.active_qubits = np.unique(gates_qubits)
|
||||||
|
|
||||||
|
def state_vector_operands(self):
|
||||||
input_tensor_count = len(self.active_qubits)
|
input_tensor_count = len(self.active_qubits)
|
||||||
|
|
||||||
input_operands = self._get_bitstring_tensors(
|
input_operands = self._get_bitstring_tensors(
|
||||||
|
|||||||
Reference in New Issue
Block a user