diff --git a/README.md b/README.md index 9f60ad3..d22503c 100644 --- a/README.md +++ b/README.md @@ -5,26 +5,33 @@ To get started, `python setup.py install` to install the tools and dependencies. # Supported Computation Tensor Network Types: + - Tensornet (TN) - Matrix Product States (MPS) Tensor Network contractions to: + - dense vectors - expecation values of given Pauli string The supported HPC configurations are: + - single-node CPU - single-node GPU or GPUs - multi-node multi-GPU with Message Passing Interface (MPI) - multi-node multi-GPU with NVIDIA Collective Communications Library (NCCL) Currently, the supported tensor network libraries are: - - [cuQuantum](https://github.com/NVIDIA/cuQuantum), an NVIDIA SDK of optimized libraries and tools for accelerating quantum computing workflows. - - [quimb](https://quimb.readthedocs.io/en/latest/), an easy but fast python library for ‘quantum information many-body’ calculations, focusing primarily on tensor networks. + +- [cuQuantum](https://github.com/NVIDIA/cuQuantum), an NVIDIA SDK of optimized libraries and tools for accelerating quantum computing workflows. +- [quimb](https://quimb.readthedocs.io/en/latest/), an easy but fast python library for ‘quantum information many-body’ calculations, focusing primarily on tensor networks. # Sample Codes + ## Single-Node Example + The code below shows an example of how to activate the Cuquantum TensorNetwork backend of Qibo. + ```py import numpy as np from qibo import Circuit, gates @@ -36,20 +43,22 @@ import qibo # This will trigger the dense vector computation of the tensornet. computation_settings = { - 'MPI_enabled': False, - 'MPS_enabled': { - "qr_method": False, - "svd_method": { - "partition": "UV", - "abs_cutoff": 1e-12, - }, - } , - 'NCCL_enabled': False, - 'expectation_enabled': False + "MPI_enabled": False, + "MPS_enabled": { + "qr_method": False, + "svd_method": { + "partition": "UV", + "abs_cutoff": 1e-12, + }, + }, + "NCCL_enabled": False, + "expectation_enabled": False, } -qibo.set_backend(backend="qibotn", platform="cutensornet", runcard=computation_settings) #cuQuantum +qibo.set_backend( + backend="qibotn", platform="cutensornet", runcard=computation_settings +) # cuQuantum # qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=computation_settings) #quimb @@ -70,25 +79,26 @@ Other examples of setting the computation_settings ```py # Expectation computation with specific Pauli String pattern computation_settings = { - 'MPI_enabled': False, - 'MPS_enabled': False, - 'NCCL_enabled': False, - 'expectation_enabled': { - 'pauli_string_pattern': "IXZ" + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": { + "pauli_string_pattern": "IXZ", + }, } # Dense vector computation using multi node through MPI computation_settings = { - 'MPI_enabled': True, - 'MPS_enabled': False, - 'NCCL_enabled': False, - 'expectation_enabled': False + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": False, } ``` ## Multi-Node Example -Multi-node is enabled by setting either the MPI or NCCL enabled flag to True in the computation settings. Below shows the script to launch on 2 nodes with 2 GPUs each. $node_list contains the IP of the nodes assigned. +Multi-node is enabled by setting either the MPI or NCCL enabled flag to True in the computation settings. Below shows the script to launch on 2 nodes with 2 GPUs each. $node_list contains the IP of the nodes assigned. ```sh mpirun -n 4 -hostfile $node_list python test.py 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/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/tests/test_quimb_backend.py b/tests/test_quimb_backend.py index 81a0e2b..15ba652 100644 --- a/tests/test_quimb_backend.py +++ b/tests/test_quimb_backend.py @@ -1,5 +1,6 @@ import copy import os + import config import numpy as np import pytest @@ -8,8 +9,7 @@ from qibo.models import QFT def create_init_state(nqubits): - init_state = np.random.random(2**nqubits) + \ - 1j * np.random.random(2**nqubits) + init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) return init_state @@ -20,10 +20,11 @@ def qibo_qft(nqubits, init_state, swaps): return circ_qibo, state_vec -@pytest.mark.parametrize("nqubits, tolerance, is_mps", - [(1, 1e-6, True), (2, 1e-6, False), (5, 1e-3, True), (10, 1e-3, False)]) +@pytest.mark.parametrize( + "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): - """Evaluate circuit with Quimb backend. Args: @@ -41,20 +42,18 @@ def test_eval(nqubits: int, tolerance: float, is_mps: bool): init_state_tn = copy.deepcopy(init_state) # Test qibo - qibo.set_backend(backend=config.qibo.backend, - platform=config.qibo.platform) - - qibo_circ, result_sv= qibo_qft(nqubits, init_state, swaps=True) - + qibo.set_backend(backend=config.qibo.backend, platform=config.qibo.platform) + + qibo_circ, result_sv = qibo_qft(nqubits, init_state, swaps=True) # Convert to qasm for other backends qasm_circ = qibo_circ.to_qasm() # Test quimb result_tn = qibotn.eval_qu.dense_vector_tn_qu( - qasm_circ, init_state_tn, is_mps, backend=config.quimb.backend - ).flatten() - + qasm_circ, init_state_tn, is_mps, backend=config.quimb.backend + ).flatten() - assert np.allclose(result_sv, result_tn, - atol=tolerance), "Resulting dense vectors do not match" + assert np.allclose( + result_sv, result_tn, atol=tolerance + ), "Resulting dense vectors do not match"