fix: some small corrections
This commit is contained in:
1609
poetry.lock
generated
1609
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ packages = [{ include = "qibotn", from = "src" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.11,<3.14"
|
||||
qibo = "^0.2.17"
|
||||
qibo = { git="https://github.com/qiboteam/qibo", branch="expectation"}
|
||||
quimb = { version = "^1.10.0", extras = ["tensor"] }
|
||||
cupy-cuda11x = { version = "^13.1.0", optional = true }
|
||||
cuquantum-python-cu11 = { version = "^24.1.0", optional = true }
|
||||
|
||||
@@ -1,63 +1,55 @@
|
||||
from collections import Counter
|
||||
|
||||
import numpy as np
|
||||
|
||||
from qibo.models import Circuit
|
||||
from qibo.backends import NumpyBackend
|
||||
from qibo.config import raise_error
|
||||
from qibotn.backends.abstract import QibotnBackend
|
||||
from qibotn.result import TensorNetworkResult
|
||||
from qibo.gates.abstract import ParametrizedGate
|
||||
|
||||
import quimb as qu
|
||||
import quimb.tensor as qtn
|
||||
from qibo.backends import NumpyBackend
|
||||
from qibo.config import raise_error
|
||||
from qibo.gates.abstract import ParametrizedGate
|
||||
from qibo.models import Circuit
|
||||
|
||||
from qibotn.backends.abstract import QibotnBackend
|
||||
from qibotn.result import TensorNetworkResult
|
||||
|
||||
GATE_MAP = {
|
||||
"h": "H",
|
||||
"x": "X",
|
||||
"y": "Y",
|
||||
"z": "Z",
|
||||
"s": "S",
|
||||
"t": "T",
|
||||
"h": "H",
|
||||
"x": "X",
|
||||
"y": "Y",
|
||||
"z": "Z",
|
||||
"s": "S",
|
||||
"t": "T",
|
||||
"rx": "RX",
|
||||
"ry": "RY",
|
||||
"rz": "RZ",
|
||||
"u3": "U3", # TODO: check
|
||||
"cx": "CX",
|
||||
"cnot": "CNOT",
|
||||
"cy": "CY",
|
||||
"cz": "CZ",
|
||||
"iswap": "ISWAP",
|
||||
"swap": "SWAP",
|
||||
"ccx": "CCX",
|
||||
"ccy": "CCY",
|
||||
"ccz": "CCZ",
|
||||
"toffoli": "TOFFOLI",
|
||||
"cswap": "CSWAP",
|
||||
"fredkin": "FREDKIN",
|
||||
"fsim": "fsim",
|
||||
"measure": "measure",
|
||||
}
|
||||
|
||||
"rx": "RX",
|
||||
"ry": "RY",
|
||||
"rz": "RZ",
|
||||
|
||||
"u3": "U3", # TODO: check
|
||||
|
||||
"cx": "CX",
|
||||
"cnot": "CNOT",
|
||||
"cy": "CY",
|
||||
"cz": "CZ",
|
||||
|
||||
"iswap": "ISWAP",
|
||||
"swap": "SWAP",
|
||||
|
||||
"ccx": "CCX",
|
||||
"ccy": "CCY",
|
||||
"ccz": "CCZ",
|
||||
|
||||
"toffoli": "TOFFOLI",
|
||||
"cswap": "CSWAP",
|
||||
"fredkin": "FREDKIN",
|
||||
|
||||
"fsim": "fsim",
|
||||
|
||||
"measure": "measure"
|
||||
}
|
||||
|
||||
class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, engine="numpy"):
|
||||
super().__init__()
|
||||
|
||||
self.name = "qibotn"
|
||||
self.platform = "quimb"
|
||||
self.engine = engine
|
||||
|
||||
self.configure_tn_simulation()
|
||||
self.setup_backend_specifics()
|
||||
self.setup_backend_specifics(quimb_backend=engine)
|
||||
|
||||
def configure_tn_simulation(
|
||||
self,
|
||||
@@ -83,7 +75,9 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
self.max_bond_dimension = max_bond_dimension
|
||||
self.n_most_frequent_states = n_most_frequent_states
|
||||
|
||||
def setup_backend_specifics(self, qimb_backend="numpy", contractions_optimizer="auto-hq"):
|
||||
def setup_backend_specifics(
|
||||
self, quimb_backend="numpy", contractions_optimizer="auto-hq"
|
||||
):
|
||||
"""Setup backend specifics.
|
||||
Args:
|
||||
qimb_backend: str
|
||||
@@ -91,19 +85,22 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
contractions_optimizer: str, optional
|
||||
The contractions_optimizer to use for the quimb tensor network simulation.
|
||||
"""
|
||||
if qimb_backend == "jax":
|
||||
if quimb_backend == "jax":
|
||||
import jax.numpy as jnp
|
||||
|
||||
self.np = jnp
|
||||
elif qimb_backend == "numpy":
|
||||
elif quimb_backend == "numpy":
|
||||
import numpy as np
|
||||
|
||||
self.np = np
|
||||
elif qimb_backend == "torch":
|
||||
elif quimb_backend == "torch":
|
||||
import torch
|
||||
|
||||
self.np = torch
|
||||
else:
|
||||
raise_error(ValueError, f"Unsupported quimb backend: {qimb_backend}")
|
||||
raise_error(ValueError, f"Unsupported quimb backend: {quimb_backend}")
|
||||
|
||||
self.backend = qimb_backend
|
||||
self.backend = quimb_backend
|
||||
self.contractions_optimizer = contractions_optimizer
|
||||
|
||||
def execute_circuit(
|
||||
@@ -180,7 +177,9 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
measured_probabilities = None
|
||||
|
||||
statevector = (
|
||||
circ_quimb.to_dense(backend=self.backend, optimize=self.contractions_optimizer)
|
||||
circ_quimb.to_dense(
|
||||
backend=self.backend, optimize=self.contractions_optimizer
|
||||
)
|
||||
if return_array
|
||||
else None
|
||||
)
|
||||
@@ -193,7 +192,9 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
statevector=statevector,
|
||||
)
|
||||
|
||||
def expectation(self, circuit, operators_list, sites_list, coeffs_list):
|
||||
def expectation_observable_symbolic_from_state(
|
||||
self, circuit, operators_list, sites_list, coeffs_list, nqubits
|
||||
):
|
||||
"""
|
||||
Compute the expectation value of a symbolic Hamiltonian on a quantum circuit using tensor network contraction.
|
||||
This method takes a Qibo circuit, converts it to a Quimb tensor network circuit, and evaluates the expectation value
|
||||
@@ -216,27 +217,30 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
float
|
||||
The real part of the expectation value of the Hamiltonian on the given circuit state.
|
||||
"""
|
||||
quimb_circuit = self._qibo_circuit_to_quimb(circuit, quimb_circuit_type=qtn.Circuit)
|
||||
quimb_circuit = self._qibo_circuit_to_quimb(
|
||||
circuit, quimb_circuit_type=qtn.Circuit
|
||||
)
|
||||
|
||||
expectation_value = 0.0
|
||||
for opstr, sitesstr, coeffstr in zip(operators_list, sites_list, coeffs_list):
|
||||
for opstr, sites, coeff in zip(operators_list, sites_list, coeffs_list):
|
||||
|
||||
ops = self._string_to_quimb_operator(opstr)
|
||||
coeff = self._parse_coefficient(coeffstr)
|
||||
sites = tuple(int(q) for q in sitesstr)
|
||||
coeff = coeff.real
|
||||
|
||||
exp_values = quimb_circuit.local_expectation(
|
||||
ops,
|
||||
where=sites,
|
||||
backend=self.backend,
|
||||
optimize=self.contractions_optimizer
|
||||
optimize=self.contractions_optimizer,
|
||||
)
|
||||
|
||||
expectation_value = expectation_value + coeff * exp_values
|
||||
|
||||
return np.real(expectation_value)
|
||||
return self.np.real(expectation_value)
|
||||
|
||||
def _qibo_circuit_to_quimb(self, qibo_circ, quimb_circuit_type=qtn.Circuit, **circuit_kwargs):
|
||||
def _qibo_circuit_to_quimb(
|
||||
self, qibo_circ, quimb_circuit_type=qtn.Circuit, **circuit_kwargs
|
||||
):
|
||||
"""
|
||||
Convert a Qibo Circuit to a Quimb Circuit. Measurement gates are ignored. If are given gates not supported by Quimb, an error is raised.
|
||||
|
||||
@@ -268,17 +272,11 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
params = getattr(gate, "parameters", ())
|
||||
qubits = getattr(gate, "qubits", ())
|
||||
|
||||
is_parametrized = (
|
||||
isinstance(gate, ParametrizedGate)
|
||||
and getattr(gate, "trainable", True)
|
||||
)
|
||||
is_parametrized = isinstance(gate, ParametrizedGate) and getattr(
|
||||
gate, "trainable", True
|
||||
)
|
||||
if is_parametrized:
|
||||
circ.apply_gate(
|
||||
qname,
|
||||
*params,
|
||||
*qubits,
|
||||
parametrized=is_parametrized
|
||||
)
|
||||
circ.apply_gate(qname, *params, *qubits, parametrized=is_parametrized)
|
||||
else:
|
||||
circ.apply_gate(
|
||||
qname,
|
||||
@@ -287,28 +285,6 @@ class QuimbBackend(QibotnBackend, NumpyBackend):
|
||||
)
|
||||
return circ
|
||||
|
||||
def _parse_coefficient(self, s):
|
||||
"""Parse a coefficient from string to float, int, or complex.
|
||||
Args:
|
||||
s: str
|
||||
The string representation of the coefficient.
|
||||
Returns:
|
||||
The coefficient as float, int, or complex.
|
||||
"""
|
||||
try:
|
||||
return float(s)
|
||||
except ValueError:
|
||||
pass
|
||||
if s == "j":
|
||||
return 1j
|
||||
elif s == "-j":
|
||||
return -1j
|
||||
else:
|
||||
try:
|
||||
return complex(s)
|
||||
except ValueError:
|
||||
raise ValueError(f"Cannot parse coefficient: {s}")
|
||||
|
||||
def _string_to_quimb_operator(self, op_str):
|
||||
"""
|
||||
Convert a Pauli string (e.g. 'xzy') to a Quimb operator using '&' chaining.
|
||||
|
||||
Reference in New Issue
Block a user