[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot]
2024-02-08 09:18:18 +00:00
parent e6a28ce573
commit 89e97b48e8
13 changed files with 118 additions and 98 deletions

View File

@@ -32,7 +32,7 @@ import qibo
# Below shows how to set the computation_settings # 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. # 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. # This will trigger the dense vector computation of the tensornet.
computation_settings = { computation_settings = {
@@ -92,4 +92,4 @@ Multi-node is enabled by setting either the MPI or NCCL enabled flag to True in
```sh ```sh
mpirun -n 4 -hostfile $node_list python test.py mpirun -n 4 -hostfile $node_list python test.py
``` ```

View File

@@ -1,6 +1,7 @@
from setuptools import setup, find_packages
import re
import pathlib import pathlib
import re
from setuptools import find_packages, setup
HERE = pathlib.Path(__file__).parent.absolute() HERE = pathlib.Path(__file__).parent.absolute()
PACKAGE = "qibotn" PACKAGE = "qibotn"
@@ -8,8 +9,8 @@ PACKAGE = "qibotn"
# Returns the qibotn version # Returns the qibotn version
def version(): def version():
"""Gets the version from the package's __init__ file """Gets the version from the package's __init__ file if there is some
if there is some problem, let it happily fail""" problem, let it happily fail."""
version_file = HERE / "src" / PACKAGE / "__init__.py" version_file = HERE / "src" / PACKAGE / "__init__.py"
version_regex = r"^__version__ = ['\"]([^'\"]*)['\"]" version_regex = r"^__version__ = ['\"]([^'\"]*)['\"]"

View File

@@ -1,23 +1,19 @@
import cupy as cp import cupy as cp
from cuquantum.cutensornet.experimental import contract_decompose
from cuquantum import contract from cuquantum import contract
from cuquantum.cutensornet.experimental import contract_decompose
# Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb # Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb
def initial(num_qubits, dtype): 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) state_tensor = cp.asarray([1, 0], dtype=dtype).reshape(1, 2, 1)
mps_tensors = [state_tensor] * num_qubits mps_tensors = [state_tensor] * num_qubits
return mps_tensors return mps_tensors
def mps_site_right_swap(mps_tensors, i, **kwargs): 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 # contraction followed by QR decomposition
a, _, b = contract_decompose( a, _, b = contract_decompose(
"ipj,jqk->iqj,jpk", "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): 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: Args:
mps_tensors: A list of rank-3 ndarray-like tensor objects. mps_tensors: A list of rank-3 ndarray-like tensor objects.

View File

@@ -5,9 +5,9 @@ import numpy as np
class QiboCircuitToEinsum: class QiboCircuitToEinsum:
"""Convert a circuit to a Tensor Network (TN) representation. """Convert a circuit to a Tensor Network (TN) representation. The circuit
The circuit is first processed to an intermediate form by grouping each gate is first processed to an intermediate form by grouping each gate matrix
matrix with its corresponding qubit it is acting on to a list. It is then with its corresponding qubit it is acting on to a list. It is then
converted to an equivalent TN expression through the class function converted to an equivalent TN expression through the class function
state_vector_operands() following the Einstein summation convention in the state_vector_operands() following the Einstein summation convention in the
interleave format. interleave format.
@@ -79,9 +79,8 @@ class QiboCircuitToEinsum:
return mode_labels, operands return mode_labels, operands
def op_shape_from_qubits(self, nqubits): def op_shape_from_qubits(self, nqubits):
"""Modify tensor to cuQuantum shape """Modify tensor to cuQuantum shape (qubit_states,input_output) *
(qubit_states,input_output) * qubits_involved qubits_involved."""
"""
return (2, 2) * nqubits return (2, 2) * nqubits
def init_intermediate_circuit(self, circuit): def init_intermediate_circuit(self, circuit):
@@ -134,8 +133,7 @@ class QiboCircuitToEinsum:
self.active_qubits_inverse = np.unique(gates_qubits_inverse) self.active_qubits_inverse = np.unique(gates_qubits_inverse)
def get_pauli_gates(self, pauli_map, dtype="complex128", backend=cp): 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: Args:
pauli_map: A dictionary mapping qubits to pauli operators. pauli_map: A dictionary mapping qubits to pauli operators.

View File

@@ -1,9 +1,9 @@
import cupy as cp import cupy as cp
import numpy as np import numpy as np
from cuquantum import cutensornet as cutn from cuquantum import cutensornet as cutn
from qibotn.MPSUtils import apply_gate, initial
from qibotn.QiboCircuitConvertor import QiboCircuitToEinsum from qibotn.QiboCircuitConvertor import QiboCircuitToEinsum
from qibotn.MPSUtils import initial, apply_gate
class QiboCircuitToMPS: class QiboCircuitToMPS:

View File

@@ -1,2 +1,2 @@
from qibotn.backends.gpu import CuTensorNet
from qibotn.backends.cpu import QuTensorNet from qibotn.backends.cpu import QuTensorNet
from qibotn.backends.gpu import CuTensorNet

View File

@@ -1,8 +1,6 @@
import numpy as np
from qibo.backends.numpy import NumpyBackend from qibo.backends.numpy import NumpyBackend
from qibo.states import CircuitResult
from qibo.config import raise_error from qibo.config import raise_error
from qibo.states import CircuitResult
class QuTensorNet(NumpyBackend): class QuTensorNet(NumpyBackend):
@@ -60,7 +58,6 @@ class QuTensorNet(NumpyBackend):
Returns: Returns:
xxx. xxx.
""" """
import qibotn.eval_qu as eval import qibotn.eval_qu as eval

View File

@@ -1,8 +1,7 @@
import numpy as np import numpy as np
from qibo.backends.numpy import NumpyBackend from qibo.backends.numpy import NumpyBackend
from qibo.states import CircuitResult
from qibo.config import raise_error from qibo.config import raise_error
from qibo.states import CircuitResult
class CuTensorNet(NumpyBackend): # pragma: no cover class CuTensorNet(NumpyBackend): # pragma: no cover
@@ -107,7 +106,6 @@ class CuTensorNet(NumpyBackend): # pragma: no cover
Returns: Returns:
xxx. xxx.
""" """
import qibotn.eval as eval import qibotn.eval as eval

View File

@@ -1,20 +1,22 @@
from qibotn.QiboCircuitConvertor import QiboCircuitToEinsum
from cuquantum import contract
from cupy.cuda.runtime import getDeviceCount
import cupy as cp import cupy as cp
from cupy.cuda.runtime import getDeviceCount
from cuquantum import contract
from qibotn.QiboCircuitToMPS import QiboCircuitToMPS
from qibotn.mps_contraction_helper import MPSContractionHelper from qibotn.mps_contraction_helper import MPSContractionHelper
from qibotn.QiboCircuitConvertor import QiboCircuitToEinsum
from qibotn.QiboCircuitToMPS import QiboCircuitToMPS
def dense_vector_tn(qibo_circ, datatype): 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) myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype)
return contract(*myconvertor.state_vector_operands()) return contract(*myconvertor.state_vector_operands())
def expectation_pauli_tn(qibo_circ, datatype, pauli_string_pattern): 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) myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype)
return contract( return contract(
*myconvertor.expectation_operands( *myconvertor.expectation_operands(
@@ -24,14 +26,19 @@ def expectation_pauli_tn(qibo_circ, datatype, pauli_string_pattern):
def dense_vector_tn_MPI(qibo_circ, datatype, n_samples=8): 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. """Convert qibo circuit to tensornet (TN) format and perform contraction
The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. using multi node and multi GPU through MPI.
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. 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 cuquantum import Network
from mpi4py import MPI
root = 0 root = 0
comm = MPI.COMM_WORLD comm = MPI.COMM_WORLD
@@ -86,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): 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. """Convert qibo circuit to tensornet (TN) format and perform contraction
The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. using multi node and multi GPU through NCCL.
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. 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 cupy.cuda import nccl
from cuquantum import Network
from mpi4py import MPI
root = 0 root = 0
comm_mpi = MPI.COMM_WORLD comm_mpi = MPI.COMM_WORLD
@@ -159,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): 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. """Convert qibo circuit to tensornet (TN) format and perform contraction to
The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. expectation of given Pauli string using multi node and multi GPU through
The pauli_string_pattern is used to generate the pauli string corresponding to the number of qubits of the system. NCCL.
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. 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 cupy.cuda import nccl
from cuquantum import Network
from mpi4py import MPI
root = 0 root = 0
comm_mpi = MPI.COMM_WORLD comm_mpi = MPI.COMM_WORLD
@@ -235,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): 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. """Convert qibo circuit to tensornet (TN) format and perform contraction to
The conversion is performed by QiboCircuitToEinsum(), after which it goes through 2 steps: pathfinder and execution. expectation of given Pauli string using multi node and multi GPU through
The pauli_string_pattern is used to generate the pauli string corresponding to the number of qubits of the system. MPI.
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. 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 cuquantum import Network
from mpi4py import MPI # this line initializes MPI
root = 0 root = 0
comm = MPI.COMM_WORLD comm = MPI.COMM_WORLD
@@ -299,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): 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) myconvertor = QiboCircuitToMPS(qibo_circ, gate_algo, dtype=datatype)
mps_helper = MPSContractionHelper(myconvertor.num_qubits) mps_helper = MPSContractionHelper(myconvertor.num_qubits)
@@ -309,7 +336,9 @@ def dense_vector_mps(qibo_circ, gate_algo, datatype):
def pauli_string_gen(nqubits, pauli_string_pattern): 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 Example: pattern: "XZ", number of qubit: 7, output = XZXZXZX
""" """
if nqubits <= 0: if nqubits <= 0:

View File

@@ -3,9 +3,15 @@ import quimb.tensor as qtn
from qibo.models import Circuit as QiboCircuit from qibo.models import Circuit as QiboCircuit
def from_qibo(circuit: QiboCircuit, is_mps: False, psi0=None, method='svd', def from_qibo(
cutoff=1e-6, cutoff_mode='abs'): circuit: QiboCircuit,
"""Create a tensornetwork representation of the circuit""" is_mps: False,
psi0=None,
method="svd",
cutoff=1e-6,
cutoff_mode="abs",
):
"""Create a tensornetwork representation of the circuit."""
nqubits = circuit.nqubits nqubits = circuit.nqubits
gate_opt = {} 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): 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)) dims = tuple(2 * np.ones(nqubits, dtype=int))
return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims) return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims)
def dense_vector_tn_qu(qasm: str, initial_state, is_mps, backend="numpy"): def dense_vector_tn_qu(qasm: str, initial_state, is_mps, backend="numpy"):
"""Evaluate QASM with Quimb """Evaluate QASM with Quimb.
backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``.
""" """
circuit = QiboCircuit.from_qasm(qasm) circuit = QiboCircuit.from_qasm(qasm)
if initial_state is not None: if initial_state is not None:

View File

@@ -1,11 +1,10 @@
from cuquantum import contract, contract_path, CircuitToEinsum, tensor from cuquantum import contract, contract_path
# Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb # Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb
class MPSContractionHelper: 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`. 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: 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): def contract_norm(self, mps_tensors, options=None):
""" """Contract the corresponding tensor network to form the norm of the
Contract the corresponding tensor network to form the norm of the MPS. MPS.
Args: Args:
mps_tensors: A list of rank-3 ndarray-like tensor objects. 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 return self._contract(interleaved_inputs, options=options).real
def contract_state_vector(self, mps_tensors, options=None): def contract_state_vector(self, mps_tensors, options=None):
""" """Contract the corresponding tensor network to form the state vector
Contract the corresponding tensor network to form the state vector representation of the MPS. representation of the MPS.
Args: Args:
mps_tensors: A list of rank-3 ndarray-like tensor objects. mps_tensors: A list of rank-3 ndarray-like tensor objects.
@@ -86,8 +85,8 @@ class MPSContractionHelper:
def contract_expectation( def contract_expectation(
self, mps_tensors, operator, qubits, options=None, normalize=False self, mps_tensors, operator, qubits, options=None, normalize=False
): ):
""" """Contract the corresponding tensor network to form the expectation of
Contract the corresponding tensor network to form the expectation of the MPS. the MPS.
Args: Args:
mps_tensors: A list of rank-3 ndarray-like tensor objects. mps_tensors: A list of rank-3 ndarray-like tensor objects.

View File

@@ -1,8 +1,8 @@
from timeit import default_timer as timer from timeit import default_timer as timer
import config import config
import numpy as np
import cupy as cp import cupy as cp
import numpy as np
import pytest import pytest
import qibo import qibo
from qibo.models import QFT from qibo.models import QFT

View File

@@ -1,5 +1,6 @@
import copy import copy
import os import os
import config import config
import numpy as np import numpy as np
import pytest import pytest
@@ -8,8 +9,7 @@ from qibo.models import QFT
def create_init_state(nqubits): def create_init_state(nqubits):
init_state = np.random.random(2**nqubits) + \ init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits)
1j * np.random.random(2**nqubits)
init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum())
return init_state return init_state
@@ -20,10 +20,11 @@ def qibo_qft(nqubits, init_state, swaps):
return circ_qibo, state_vec return circ_qibo, state_vec
@pytest.mark.parametrize("nqubits, tolerance, is_mps", @pytest.mark.parametrize(
[(1, 1e-6, True), (2, 1e-6, False), (5, 1e-3, True), (10, 1e-3, False)]) "nqubits, tolerance, is_mps",
[(1, 1e-6, True), (2, 1e-6, False), (5, 1e-3, True), (10, 1e-3, False)],
)
def test_eval(nqubits: int, tolerance: float, is_mps: bool): def test_eval(nqubits: int, tolerance: float, is_mps: bool):
"""Evaluate circuit with Quimb backend. """Evaluate circuit with Quimb backend.
Args: Args:
@@ -41,20 +42,18 @@ def test_eval(nqubits: int, tolerance: float, is_mps: bool):
init_state_tn = copy.deepcopy(init_state) init_state_tn = copy.deepcopy(init_state)
# Test qibo # Test qibo
qibo.set_backend(backend=config.qibo.backend, qibo.set_backend(backend=config.qibo.backend, platform=config.qibo.platform)
platform=config.qibo.platform)
qibo_circ, result_sv = qibo_qft(nqubits, init_state, swaps=True)
qibo_circ, result_sv= qibo_qft(nqubits, init_state, swaps=True)
# Convert to qasm for other backends # Convert to qasm for other backends
qasm_circ = qibo_circ.to_qasm() qasm_circ = qibo_circ.to_qasm()
# Test quimb # Test quimb
result_tn = qibotn.eval_qu.dense_vector_tn_qu( result_tn = qibotn.eval_qu.dense_vector_tn_qu(
qasm_circ, init_state_tn, is_mps, backend=config.quimb.backend qasm_circ, init_state_tn, is_mps, backend=config.quimb.backend
).flatten() ).flatten()
assert np.allclose(result_sv, result_tn, assert np.allclose(
atol=tolerance), "Resulting dense vectors do not match" result_sv, result_tn, atol=tolerance
), "Resulting dense vectors do not match"