[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
@@ -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
|
||||||
```
|
```
|
||||||
|
|||||||
9
setup.py
9
setup.py
@@ -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__ = ['\"]([^'\"]*)['\"]"
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user