From 2c54840e7b61a5b2b129cb03f08ce0361eebec63 Mon Sep 17 00:00:00 2001 From: jaunatisblue Date: Mon, 27 Apr 2026 11:03:57 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=AE=8C=E6=88=90mps=E6=80=81=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E4=B8=8E=E5=8E=9F=E5=A7=8Bqibojit=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E6=AF=94=E5=AF=B9=E7=A1=AE=E5=AE=9Abond=20demension?= =?UTF-8?q?=E5=92=8Ccut=20off=E5=80=BC=EF=BC=9B2.=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=BA=86=E5=AE=98=E6=96=B9=E5=BA=93=EF=BC=9B3.=E6=96=B0?= =?UTF-8?q?=E5=A4=A7=E9=99=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- benchmark_mps.py | 93 ++++++++++++++++++++++++++++++++++++++++++++ doc/make.bat | 70 ++++++++++++++++----------------- poetry.lock | 6 +-- src/qibotn/result.py | 2 +- 5 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 benchmark_mps.py diff --git a/.gitignore b/.gitignore index 7f051b8..2fee375 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ __pycache__/ *.py[cod] *$py.class - +data/ # C extensions *.so diff --git a/benchmark_mps.py b/benchmark_mps.py new file mode 100644 index 0000000..c2342b5 --- /dev/null +++ b/benchmark_mps.py @@ -0,0 +1,93 @@ +"""Benchmark: qibojit (reference) vs qibotn/quimb MPS, with error comparison.""" +import time +import argparse +import numpy as np +import qibo +from qibo import Circuit, gates + + +def make_circuit(circuit_type, nqubits, nlayers=1): + c = Circuit(nqubits) + if circuit_type == "qft": + from qibo.models import QFT + return QFT(nqubits) + elif circuit_type == "variational": + for _ in range(nlayers): + for q in range(nqubits): + c.add(gates.RY(q, theta=np.random.uniform(0, 2 * np.pi))) + for q in range(0, nqubits - 1, 2): + c.add(gates.CZ(q, q + 1)) + elif circuit_type == "ghz": + c.add(gates.H(0)) + for q in range(nqubits - 1): + c.add(gates.CNOT(q, q + 1)) + else: + raise ValueError(f"Unknown circuit: {circuit_type}") + return c + + +def run_qibojit(circuit): + qibo.set_backend("qibojit", platform="numba") + t0 = time.time() + result = circuit() + elapsed = time.time() - t0 + sv = result.state() + return sv, elapsed + + +def run_quimb_mps(circuit, max_bond, svd_cutoff, optimizer): + qibo.set_backend("qibotn", platform="quimb") + b = qibo.get_backend() + b.configure_tn_simulation(ansatz="mps", max_bond_dimension=max_bond, svd_cutoff=svd_cutoff) + b.contractions_optimizer = optimizer + + t0 = time.time() + result = b.execute_circuit(circuit, return_array=True) + elapsed = time.time() - t0 + sv = result.state() + return sv, elapsed + + +def compare(sv_ref, sv_mps): + sv_ref = np.array(sv_ref).flatten() + sv_mps = np.array(sv_mps).flatten() + fidelity = abs(np.dot(sv_ref.conj(), sv_mps)) ** 2 + l2_err = np.linalg.norm(sv_ref - sv_mps) + return fidelity, l2_err + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--nqubits", type=int, default=10) + parser.add_argument("--circuit", type=str, default="ghz", + choices=["qft", "variational", "ghz"]) + parser.add_argument("--nlayers", type=int, default=3) + parser.add_argument("--max-bond", type=int, default=None, + help="Max bond dimension for MPS (None = unlimited)") + parser.add_argument("--svd-cutoff", type=float, default=1e-6) + parser.add_argument("--optimizer", type=str, default="auto-hq") + args = parser.parse_args() + + np.random.seed(42) + print(f"Circuit: {args.circuit}, nqubits={args.nqubits}, nlayers={args.nlayers}") + print(f"MPS config: max_bond={args.max_bond}, svd_cutoff={args.svd_cutoff}, optimizer={args.optimizer}") + + circuit_ref = make_circuit(args.circuit, args.nqubits, args.nlayers) + sv_ref, t_ref = run_qibojit(circuit_ref) + print(f"\n[qibojit] time={t_ref:.4f}s") + + circuit_mps = make_circuit(args.circuit, args.nqubits, args.nlayers) + try: + sv_mps, t_mps = run_quimb_mps(circuit_mps, args.max_bond, args.svd_cutoff, args.optimizer) + fidelity, l2_err = compare(sv_ref, sv_mps) + print(f"[quimb MPS] time={t_mps:.4f}s") + print(f"\nFidelity : {fidelity:.8f} (1=perfect)") + print(f"L2 error : {l2_err:.2e}") + print(f"Speedup : {t_ref/t_mps:.2f}x" if t_mps > 0 else "") + except Exception as e: + print(f"[quimb MPS] FAILED: {e}") + raise + + +if __name__ == "__main__": + main() diff --git a/doc/make.bat b/doc/make.bat index dc1312a..747ffb7 100644 --- a/doc/make.bat +++ b/doc/make.bat @@ -1,35 +1,35 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/poetry.lock b/poetry.lock index bbee0b8..1b8a3ce 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1733,14 +1733,14 @@ files = [ [[package]] name = "mako" -version = "1.3.10" +version = "1.3.11" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"}, - {file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"}, + {file = "mako-1.3.11-py3-none-any.whl", hash = "sha256:e372c6e333cf004aa736a15f425087ec977e1fcbd2966aae7f17c8dc1da27a77"}, + {file = "mako-1.3.11.tar.gz", hash = "sha256:071eb4ab4c5010443152255d77db7faa6ce5916f35226eb02dc34479b6858069"}, ] [package.dependencies] diff --git a/src/qibotn/result.py b/src/qibotn/result.py index 33be61c..98d58a6 100644 --- a/src/qibotn/result.py +++ b/src/qibotn/result.py @@ -58,7 +58,7 @@ class TensorNetworkResult: def state(self): """Return the statevector if the number of qubits is less than 20.""" - if self.nqubits < 20: + if self.nqubits < 32: return self.statevector raise_error( NotImplementedError,