mps基础脚本
Some checks failed
Build wheels / build (ubuntu-latest, 3.11) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.12) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / check (push) Has been cancelled
Tests / build (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.13) (push) Has been cancelled
Some checks failed
Build wheels / build (ubuntu-latest, 3.11) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.12) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / check (push) Has been cancelled
Tests / build (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.13) (push) Has been cancelled
This commit is contained in:
83
baseline_mps_expectation.py
Normal file
83
baseline_mps_expectation.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
"""Baseline MPS expectation scan with the qmatchatea backend."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import math
|
||||||
|
import time
|
||||||
|
|
||||||
|
from qibo import Circuit, gates, hamiltonians
|
||||||
|
from qibo.symbols import X, Z
|
||||||
|
|
||||||
|
from qibotn.backends.qmatchatea import QMatchaTeaBackend
|
||||||
|
|
||||||
|
|
||||||
|
def parse_bonds(value):
|
||||||
|
return [int(item) for item in value.split(",") if item.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def build_circuit(nqubits, nlayers, seed):
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
rng = np.random.default_rng(seed)
|
||||||
|
circuit = Circuit(nqubits)
|
||||||
|
for _ in range(nlayers):
|
||||||
|
for qubit in range(nqubits):
|
||||||
|
circuit.add(gates.RY(qubit, theta=rng.uniform(-math.pi, math.pi)))
|
||||||
|
circuit.add(gates.RZ(qubit, theta=rng.uniform(-math.pi, math.pi)))
|
||||||
|
for qubit in range(0, nqubits - 1, 2):
|
||||||
|
circuit.add(gates.CNOT(qubit, qubit + 1))
|
||||||
|
for qubit in range(1, nqubits - 1, 2):
|
||||||
|
circuit.add(gates.CNOT(qubit, qubit + 1))
|
||||||
|
return circuit
|
||||||
|
|
||||||
|
|
||||||
|
def build_observable(nqubits):
|
||||||
|
form = 0
|
||||||
|
for qubit in range(nqubits - 1):
|
||||||
|
form += 0.5 * Z(qubit) * Z(qubit + 1)
|
||||||
|
form += 0.25 * X(0)
|
||||||
|
return hamiltonians.SymbolicHamiltonian(form=form)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--nqubits", type=int, default=20)
|
||||||
|
parser.add_argument("--nlayers", type=int, default=8)
|
||||||
|
parser.add_argument("--bonds", type=parse_bonds, default=parse_bonds("2,4,8,16,32"))
|
||||||
|
parser.add_argument("--seed", type=int, default=42)
|
||||||
|
parser.add_argument("--cut-ratio", type=float, default=1e-12)
|
||||||
|
parser.add_argument("--svd-control", default="V")
|
||||||
|
parser.add_argument("--no-exact", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
logging.getLogger("qibo.config").setLevel(logging.ERROR)
|
||||||
|
logging.getLogger("qtealeaves").setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
circuit = build_circuit(args.nqubits, args.nlayers, args.seed)
|
||||||
|
observable = build_observable(args.nqubits)
|
||||||
|
exact = None
|
||||||
|
if not args.no_exact:
|
||||||
|
exact = float(observable.expectation_from_state(circuit().state()).real)
|
||||||
|
|
||||||
|
print(f"nqubits={args.nqubits} nlayers={args.nlayers} seed={args.seed}")
|
||||||
|
if exact is not None:
|
||||||
|
print(f"exact={exact:.16e}")
|
||||||
|
print("bond_dim expval abs_error rel_error seconds")
|
||||||
|
|
||||||
|
backend = QMatchaTeaBackend()
|
||||||
|
for bond in args.bonds:
|
||||||
|
backend.configure_tn_simulation(
|
||||||
|
ansatz="MPS",
|
||||||
|
max_bond_dimension=bond,
|
||||||
|
cut_ratio=args.cut_ratio,
|
||||||
|
svd_control=args.svd_control,
|
||||||
|
)
|
||||||
|
start = time.perf_counter()
|
||||||
|
value = float(backend.expectation(circuit, observable, preprocess=False).real)
|
||||||
|
elapsed = time.perf_counter() - start
|
||||||
|
abs_error = float("nan") if exact is None else abs(value - exact)
|
||||||
|
rel_error = float("nan") if exact is None else abs_error / max(abs(exact), 1e-15)
|
||||||
|
print(f"{bond:d} {value:.16e} {abs_error:.6e} {rel_error:.6e} {elapsed:.3f}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -11,6 +11,7 @@ from qibo.backends import NumpyBackend
|
|||||||
from qibo.config import raise_error
|
from qibo.config import raise_error
|
||||||
|
|
||||||
from qibotn.backends.abstract import QibotnBackend
|
from qibotn.backends.abstract import QibotnBackend
|
||||||
|
from qibotn.observables import check_observable
|
||||||
from qibotn.result import TensorNetworkResult
|
from qibotn.result import TensorNetworkResult
|
||||||
|
|
||||||
|
|
||||||
@@ -75,6 +76,8 @@ class QMatchaTeaBackend(QibotnBackend, NumpyBackend):
|
|||||||
ini_bond_dimension=ini_bond_dimension,
|
ini_bond_dimension=ini_bond_dimension,
|
||||||
)
|
)
|
||||||
self.ansatz = ansatz
|
self.ansatz = ansatz
|
||||||
|
if hasattr(self, "qmatchatea_backend"):
|
||||||
|
self._setup_backend_specifics()
|
||||||
|
|
||||||
def _setup_backend_specifics(self):
|
def _setup_backend_specifics(self):
|
||||||
"""Configure qmatchatea QCBackend object."""
|
"""Configure qmatchatea QCBackend object."""
|
||||||
@@ -193,7 +196,7 @@ class QMatchaTeaBackend(QibotnBackend, NumpyBackend):
|
|||||||
statevector=statevector,
|
statevector=statevector,
|
||||||
)
|
)
|
||||||
|
|
||||||
def expectation(self, circuit, observable):
|
def expectation(self, circuit, observable, preprocess=True):
|
||||||
"""Compute the expectation value of a Qibo-friendly ``observable`` on
|
"""Compute the expectation value of a Qibo-friendly ``observable`` on
|
||||||
the Tensor Network constructed from a Qibo ``circuit``.
|
the Tensor Network constructed from a Qibo ``circuit``.
|
||||||
|
|
||||||
@@ -216,8 +219,10 @@ class QMatchaTeaBackend(QibotnBackend, NumpyBackend):
|
|||||||
simulation setup.
|
simulation setup.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
observable = check_observable(observable, circuit.nqubits)
|
||||||
|
|
||||||
# From Qibo to Qiskit
|
# From Qibo to Qiskit
|
||||||
circuit = self._qibocirc_to_qiskitcirc(circuit)
|
circuit = self._qibocirc_to_qiskitcirc(circuit, preprocess=preprocess)
|
||||||
run_qk_params = qmatchatea.preprocessing.qk_transpilation_params(False)
|
run_qk_params = qmatchatea.preprocessing.qk_transpilation_params(False)
|
||||||
|
|
||||||
operators = qmatchatea.QCOperators()
|
operators = qmatchatea.QCOperators()
|
||||||
@@ -236,12 +241,17 @@ class QMatchaTeaBackend(QibotnBackend, NumpyBackend):
|
|||||||
|
|
||||||
return np.real(results.observables["custom_hamiltonian"])
|
return np.real(results.observables["custom_hamiltonian"])
|
||||||
|
|
||||||
def _qibocirc_to_qiskitcirc(self, qibo_circuit) -> qiskit.QuantumCircuit:
|
def _qibocirc_to_qiskitcirc(
|
||||||
|
self, qibo_circuit, preprocess=True
|
||||||
|
) -> qiskit.QuantumCircuit:
|
||||||
"""Convert a Qibo Circuit into a Qiskit Circuit."""
|
"""Convert a Qibo Circuit into a Qiskit Circuit."""
|
||||||
# Convert the circuit to QASM 2.0 to qiskit
|
# Convert the circuit to QASM 2.0 to qiskit
|
||||||
qasm_circuit = qibo_circuit.to_qasm()
|
qasm_circuit = qibo_circuit.to_qasm()
|
||||||
qiskit_circuit = qiskit.QuantumCircuit.from_qasm_str(qasm_circuit)
|
qiskit_circuit = qiskit.QuantumCircuit.from_qasm_str(qasm_circuit)
|
||||||
|
|
||||||
|
if not preprocess:
|
||||||
|
return qiskit_circuit
|
||||||
|
|
||||||
# Transpile the circuit to adapt it to the linear structure of the MPS,
|
# Transpile the circuit to adapt it to the linear structure of the MPS,
|
||||||
# with the constraint of having only the gates basis_gates
|
# with the constraint of having only the gates basis_gates
|
||||||
qiskit_circuit = qmatchatea.preprocessing.preprocess(
|
qiskit_circuit = qmatchatea.preprocessing.preprocess(
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ def check_observable(observable, circuit_nqubit):
|
|||||||
return create_hamiltonian_from_dict(observable, circuit_nqubit)
|
return create_hamiltonian_from_dict(observable, circuit_nqubit)
|
||||||
if isinstance(observable, hamiltonians.SymbolicHamiltonian):
|
if isinstance(observable, hamiltonians.SymbolicHamiltonian):
|
||||||
return observable
|
return observable
|
||||||
raise TypeError("Invalid observable type.")
|
try:
|
||||||
|
return hamiltonians.SymbolicHamiltonian(form=observable)
|
||||||
|
except Exception as exc:
|
||||||
|
raise TypeError("Invalid observable type.") from exc
|
||||||
|
|
||||||
|
|
||||||
def build_observable(circuit_nqubit):
|
def build_observable(circuit_nqubit):
|
||||||
|
|||||||
Reference in New Issue
Block a user