From 898ca877e9a4f3d566b90f44ab903bbc8cf0647f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:18:18 +0000 Subject: [PATCH] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- README.md | 4 +- setup.py | 4 +- src/qibotn/MPSUtils.py | 11 +--- src/qibotn/QiboCircuitConvertor.py | 14 ++--- src/qibotn/backends/__init__.py | 2 +- src/qibotn/backends/cpu.py | 5 +- src/qibotn/backends/gpu.py | 4 +- src/qibotn/eval.py | 89 ++++++++++++++++++---------- src/qibotn/eval_qu.py | 20 ++++--- src/qibotn/mps_contraction_helper.py | 17 +++--- 10 files changed, 93 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 070ccb3..9f60ad3 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ import qibo # Below shows how to set the computation_settings # Note that for MPS_enabled and expectation_enabled parameters the accepted inputs are boolean or a dictionary with the format shown below. -# If computation_settings is not specified, the default setting is used in which all booleans will be False. +# If computation_settings is not specified, the default setting is used in which all booleans will be False. # This will trigger the dense vector computation of the tensornet. computation_settings = { @@ -92,4 +92,4 @@ Multi-node is enabled by setting either the MPI or NCCL enabled flag to True in ```sh mpirun -n 4 -hostfile $node_list python test.py -``` \ No newline at end of file +``` diff --git a/setup.py b/setup.py index e44a906..0f619a5 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,8 @@ PACKAGE = "qibotn" # Returns the qibotn version def version(): - """Gets the version from the package's __init__ file - if there is some problem, let it happily fail""" + """Gets the version from the package's __init__ file if there is some + problem, let it happily fail.""" version_file = HERE / "src" / PACKAGE / "__init__.py" version_regex = r"^__version__ = ['\"]([^'\"]*)['\"]" diff --git a/src/qibotn/MPSUtils.py b/src/qibotn/MPSUtils.py index 1d37c42..e8068f7 100644 --- a/src/qibotn/MPSUtils.py +++ b/src/qibotn/MPSUtils.py @@ -6,18 +6,14 @@ from cuquantum.cutensornet.experimental import contract_decompose def initial(num_qubits, dtype): - """ - Generate the MPS with an initial state of |00...00> - """ + """Generate the MPS with an initial state of |00...00>""" state_tensor = cp.asarray([1, 0], dtype=dtype).reshape(1, 2, 1) mps_tensors = [state_tensor] * num_qubits return mps_tensors def mps_site_right_swap(mps_tensors, i, **kwargs): - """ - Perform the swap operation between the ith and i+1th MPS tensors. - """ + """Perform the swap operation between the ith and i+1th MPS tensors.""" # contraction followed by QR decomposition a, _, b = contract_decompose( "ipj,jqk->iqj,jpk", @@ -30,8 +26,7 @@ def mps_site_right_swap(mps_tensors, i, **kwargs): def apply_gate(mps_tensors, gate, qubits, **kwargs): - """ - Apply the gate operand to the MPS tensors in-place. + """Apply the gate operand to the MPS tensors in-place. Args: mps_tensors: A list of rank-3 ndarray-like tensor objects. diff --git a/src/qibotn/QiboCircuitConvertor.py b/src/qibotn/QiboCircuitConvertor.py index e1aabea..f67fb8e 100644 --- a/src/qibotn/QiboCircuitConvertor.py +++ b/src/qibotn/QiboCircuitConvertor.py @@ -5,9 +5,9 @@ import numpy as np class QiboCircuitToEinsum: - """Convert a circuit to a Tensor Network (TN) representation. - The circuit is first processed to an intermediate form by grouping each gate - matrix with its corresponding qubit it is acting on to a list. It is then + """Convert a circuit to a Tensor Network (TN) representation. The circuit + is first processed to an intermediate form by grouping each gate matrix + with its corresponding qubit it is acting on to a list. It is then converted to an equivalent TN expression through the class function state_vector_operands() following the Einstein summation convention in the interleave format. @@ -79,9 +79,8 @@ class QiboCircuitToEinsum: return mode_labels, operands def op_shape_from_qubits(self, nqubits): - """Modify tensor to cuQuantum shape - (qubit_states,input_output) * qubits_involved - """ + """Modify tensor to cuQuantum shape (qubit_states,input_output) * + qubits_involved.""" return (2, 2) * nqubits def init_intermediate_circuit(self, circuit): @@ -134,8 +133,7 @@ class QiboCircuitToEinsum: self.active_qubits_inverse = np.unique(gates_qubits_inverse) def get_pauli_gates(self, pauli_map, dtype="complex128", backend=cp): - """ - Populate the gates for all pauli operators. + """Populate the gates for all pauli operators. Args: pauli_map: A dictionary mapping qubits to pauli operators. diff --git a/src/qibotn/backends/__init__.py b/src/qibotn/backends/__init__.py index f927932..e5d68de 100644 --- a/src/qibotn/backends/__init__.py +++ b/src/qibotn/backends/__init__.py @@ -1,2 +1,2 @@ -from qibotn.backends.gpu import CuTensorNet from qibotn.backends.cpu import QuTensorNet +from qibotn.backends.gpu import CuTensorNet diff --git a/src/qibotn/backends/cpu.py b/src/qibotn/backends/cpu.py index 7115b39..a85dfd9 100644 --- a/src/qibotn/backends/cpu.py +++ b/src/qibotn/backends/cpu.py @@ -1,8 +1,6 @@ -import numpy as np - from qibo.backends.numpy import NumpyBackend -from qibo.states import CircuitResult from qibo.config import raise_error +from qibo.states import CircuitResult class QuTensorNet(NumpyBackend): @@ -60,7 +58,6 @@ class QuTensorNet(NumpyBackend): Returns: xxx. - """ import qibotn.eval_qu as eval diff --git a/src/qibotn/backends/gpu.py b/src/qibotn/backends/gpu.py index 5777fe9..2c3f8d4 100644 --- a/src/qibotn/backends/gpu.py +++ b/src/qibotn/backends/gpu.py @@ -1,8 +1,7 @@ import numpy as np - from qibo.backends.numpy import NumpyBackend -from qibo.states import CircuitResult from qibo.config import raise_error +from qibo.states import CircuitResult class CuTensorNet(NumpyBackend): # pragma: no cover @@ -107,7 +106,6 @@ class CuTensorNet(NumpyBackend): # pragma: no cover Returns: xxx. - """ import qibotn.eval as eval diff --git a/src/qibotn/eval.py b/src/qibotn/eval.py index 98c87a2..5fcb66f 100644 --- a/src/qibotn/eval.py +++ b/src/qibotn/eval.py @@ -1,10 +1,6 @@ -import multiprocessing - import cupy as cp from cupy.cuda.runtime import getDeviceCount from cuquantum import contract -from cupy.cuda.runtime import getDeviceCount -import cupy as cp from qibotn.mps_contraction_helper import MPSContractionHelper from qibotn.QiboCircuitConvertor import QiboCircuitToEinsum @@ -12,13 +8,15 @@ from qibotn.QiboCircuitToMPS import QiboCircuitToMPS def dense_vector_tn(qibo_circ, datatype): - """Convert qibo circuit to tensornet (TN) format and perform contraction to dense vector.""" + """Convert qibo circuit to tensornet (TN) format and perform contraction to + dense vector.""" myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) return contract(*myconvertor.state_vector_operands()) def expectation_pauli_tn(qibo_circ, datatype, pauli_string_pattern): - """Convert qibo circuit to tensornet (TN) format and perform contraction to expectation of given Pauli string.""" + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string.""" myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) return contract( *myconvertor.expectation_operands( @@ -28,14 +26,19 @@ def expectation_pauli_tn(qibo_circ, datatype, pauli_string_pattern): def dense_vector_tn_MPI(qibo_circ, datatype, n_samples=8): - """Convert qibo circuit to tensornet (TN) format and perform contraction using multi node and multi GPU through MPI. - The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. - The pathfinder looks at user defined number of samples (n_samples) iteratively to select the least costly contraction path. This is sped up with multi thread. - After pathfinding the optimal path is used in the actual contraction to give a dense vector representation of the TN. + """Convert qibo circuit to tensornet (TN) format and perform contraction + using multi node and multi GPU through MPI. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The pathfinder looks + at user defined number of samples (n_samples) iteratively to select + the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give a dense vector representation of the TN. """ - from mpi4py import MPI from cuquantum import Network + from mpi4py import MPI root = 0 comm = MPI.COMM_WORLD @@ -90,14 +93,19 @@ def dense_vector_tn_MPI(qibo_circ, datatype, n_samples=8): def dense_vector_tn_nccl(qibo_circ, datatype, n_samples=8): - """Convert qibo circuit to tensornet (TN) format and perform contraction using multi node and multi GPU through NCCL. - The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. - The pathfinder looks at user defined number of samples (n_samples) iteratively to select the least costly contraction path. This is sped up with multi thread. - After pathfinding the optimal path is used in the actual contraction to give a dense vector representation of the TN. + """Convert qibo circuit to tensornet (TN) format and perform contraction + using multi node and multi GPU through NCCL. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The pathfinder looks + at user defined number of samples (n_samples) iteratively to select + the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give a dense vector representation of the TN. """ - from mpi4py import MPI - from cuquantum import Network from cupy.cuda import nccl + from cuquantum import Network + from mpi4py import MPI root = 0 comm_mpi = MPI.COMM_WORLD @@ -163,15 +171,22 @@ def dense_vector_tn_nccl(qibo_circ, datatype, n_samples=8): def expectation_pauli_tn_nccl(qibo_circ, datatype, pauli_string_pattern, n_samples=8): - """Convert qibo circuit to tensornet (TN) format and perform contraction to expectation of given Pauli string using multi node and multi GPU through NCCL. - The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. - The pauli_string_pattern is used to generate the pauli string corresponding to the number of qubits of the system. - The pathfinder looks at user defined number of samples (n_samples) iteratively to select the least costly contraction path. This is sped up with multi thread. - After pathfinding the optimal path is used in the actual contraction to give an expectation value. + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string using multi node and multi GPU through + NCCL. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The + pauli_string_pattern is used to generate the pauli string + corresponding to the number of qubits of the system. The pathfinder + looks at user defined number of samples (n_samples) iteratively to + select the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give an expectation value. """ - from mpi4py import MPI - from cuquantum import Network from cupy.cuda import nccl + from cuquantum import Network + from mpi4py import MPI root = 0 comm_mpi = MPI.COMM_WORLD @@ -239,14 +254,21 @@ def expectation_pauli_tn_nccl(qibo_circ, datatype, pauli_string_pattern, n_sampl def expectation_pauli_tn_MPI(qibo_circ, datatype, pauli_string_pattern, n_samples=8): - """Convert qibo circuit to tensornet (TN) format and perform contraction to expectation of given Pauli string using multi node and multi GPU through MPI. - The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. - The pauli_string_pattern is used to generate the pauli string corresponding to the number of qubits of the system. - The pathfinder looks at user defined number of samples (n_samples) iteratively to select the least costly contraction path. This is sped up with multi thread. - After pathfinding the optimal path is used in the actual contraction to give an expectation value. + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string using multi node and multi GPU through + MPI. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The + pauli_string_pattern is used to generate the pauli string + corresponding to the number of qubits of the system. The pathfinder + looks at user defined number of samples (n_samples) iteratively to + select the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give an expectation value. """ - from mpi4py import MPI # this line initializes MPI from cuquantum import Network + from mpi4py import MPI # this line initializes MPI root = 0 comm = MPI.COMM_WORLD @@ -303,7 +325,8 @@ def expectation_pauli_tn_MPI(qibo_circ, datatype, pauli_string_pattern, n_sample def dense_vector_mps(qibo_circ, gate_algo, datatype): - """Convert qibo circuit to matrix product state (MPS) format and perform contraction to dense vector.""" + """Convert qibo circuit to matrix product state (MPS) format and perform + contraction to dense vector.""" myconvertor = QiboCircuitToMPS(qibo_circ, gate_algo, dtype=datatype) mps_helper = MPSContractionHelper(myconvertor.num_qubits) @@ -313,7 +336,9 @@ def dense_vector_mps(qibo_circ, gate_algo, datatype): def pauli_string_gen(nqubits, pauli_string_pattern): - """Used internally to generate the string based on given pattern and number of qubit. + """Used internally to generate the string based on given pattern and number + of qubit. + Example: pattern: "XZ", number of qubit: 7, output = XZXZXZX """ if nqubits <= 0: diff --git a/src/qibotn/eval_qu.py b/src/qibotn/eval_qu.py index 579a42a..7b603b5 100644 --- a/src/qibotn/eval_qu.py +++ b/src/qibotn/eval_qu.py @@ -3,9 +3,15 @@ import quimb.tensor as qtn from qibo.models import Circuit as QiboCircuit -def from_qibo(circuit: QiboCircuit, is_mps: False, psi0=None, method='svd', - cutoff=1e-6, cutoff_mode='abs'): - """Create a tensornetwork representation of the circuit""" +def from_qibo( + circuit: QiboCircuit, + is_mps: False, + psi0=None, + method="svd", + cutoff=1e-6, + cutoff_mode="abs", +): + """Create a tensornetwork representation of the circuit.""" nqubits = circuit.nqubits gate_opt = {} @@ -30,19 +36,17 @@ def from_qibo(circuit: QiboCircuit, is_mps: False, psi0=None, method='svd', def init_state_tn(nqubits, init_state_sv): - - """Create a matrixproductstate directly from a dense vector""" + """Create a matrixproductstate directly from a dense vector.""" dims = tuple(2 * np.ones(nqubits, dtype=int)) return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims) -def dense_vector_tn_qu(qasm: str, initial_state, is_mps, backend="numpy"): - """Evaluate QASM with Quimb +def dense_vector_tn_qu(qasm: str, initial_state, is_mps, backend="numpy"): + """Evaluate QASM with Quimb. backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. - """ circuit = QiboCircuit.from_qasm(qasm) if initial_state is not None: diff --git a/src/qibotn/mps_contraction_helper.py b/src/qibotn/mps_contraction_helper.py index 9d667cf..1c004de 100644 --- a/src/qibotn/mps_contraction_helper.py +++ b/src/qibotn/mps_contraction_helper.py @@ -1,11 +1,10 @@ -from cuquantum import CircuitToEinsum, contract, contract_path, tensor +from cuquantum import contract, contract_path # Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb class MPSContractionHelper: - """ - A helper class to compute various quantities for a given MPS. + """A helper class to compute various quantities for a given MPS. Interleaved format is used to construct the input args for `cuquantum.contract`. A concrete example on how the modes are populated for a 7-site MPS is provided below: @@ -43,8 +42,8 @@ class MPSContractionHelper: ] def contract_norm(self, mps_tensors, options=None): - """ - Contract the corresponding tensor network to form the norm of the MPS. + """Contract the corresponding tensor network to form the norm of the + MPS. Args: mps_tensors: A list of rank-3 ndarray-like tensor objects. @@ -64,8 +63,8 @@ class MPSContractionHelper: return self._contract(interleaved_inputs, options=options).real def contract_state_vector(self, mps_tensors, options=None): - """ - Contract the corresponding tensor network to form the state vector representation of the MPS. + """Contract the corresponding tensor network to form the state vector + representation of the MPS. Args: mps_tensors: A list of rank-3 ndarray-like tensor objects. @@ -86,8 +85,8 @@ class MPSContractionHelper: def contract_expectation( self, mps_tensors, operator, qubits, options=None, normalize=False ): - """ - Contract the corresponding tensor network to form the expectation of the MPS. + """Contract the corresponding tensor network to form the expectation of + the MPS. Args: mps_tensors: A list of rank-3 ndarray-like tensor objects.