From 441e4ea529d1213a973b9e74d4efccd02c73db05 Mon Sep 17 00:00:00 2001 From: juacrumar Date: Wed, 29 Jan 2025 19:30:54 +0400 Subject: [PATCH 1/3] added first attempt at quantump integrator --- examples/quantum_mc.py | 35 ++++++++++++++++++++ pyproject.toml | 3 ++ src/vegasflow/quantum.py | 70 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 examples/quantum_mc.py create mode 100644 src/vegasflow/quantum.py diff --git a/examples/quantum_mc.py b/examples/quantum_mc.py new file mode 100644 index 0000000..81f91a7 --- /dev/null +++ b/examples/quantum_mc.py @@ -0,0 +1,35 @@ +""" +Run integration with qibo as the backend +""" + +from vegasflow.quantum import quantum_wrapper +from vegasflow import float_me +import time +import numpy as np +import tensorflow as tf + + +# MC integration setup +dim = 2 +ncalls = int(1e2) +n_iter = 5 + + +def symgauss(xarr): + """symgauss test function""" + n_dim = xarr.shape[-1] + a = float_me(0.1) + n100 = float_me(100 * n_dim) + pref = tf.pow(1.0 / a / np.sqrt(np.pi), n_dim) + coef = tf.reduce_sum(tf.range(n100 + 1)) + coef += tf.reduce_sum(tf.square((xarr - 1.0 / 2.0) / a), axis=1) + coef -= (n100 + 1) * n100 / 2.0 + return pref * tf.exp(-coef) + + +if __name__ == "__main__": + """Testing several different integrations""" + print(f"VEGAS MC, ncalls={ncalls}:") + start = time.time() + result = quantum_wrapper(symgauss, dim, n_iter, ncalls) + end = time.time() diff --git a/pyproject.toml b/pyproject.toml index bd43bc3..25d245a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,9 @@ dependencies = [ ] [project.optional-dependencies] +quantum = [ + "qibolab[qrng] @ git+https://github.com/qiboteam/qibolab@qrng" +] docs = [ 'sphinx', 'sphinx_rtd_theme', diff --git a/src/vegasflow/quantum.py b/src/vegasflow/quantum.py new file mode 100644 index 0000000..09cace9 --- /dev/null +++ b/src/vegasflow/quantum.py @@ -0,0 +1,70 @@ +""" +A Monte Carlo integrator built upon Qibo for quantum integration +""" + +from .monte_carlo import wrapper, sampler +from .plain import PlainFlow # start building upon a naive idiotic integrator +from .configflow import run_eager, DTYPE +import tensorflow as tf + + +class QuantumIntegrator(PlainFlow): + """ + Simple Monte Carlo integrator. + """ + + _CAN_RUN_VECTORIAL = False + + def __init__(self, *args, **kwargs): + # This integrator can only run for now in eager mode and needs qibolab to be installed + run_eager(True) + + try: + from qibolab.instruments.qrng import QRNG + from serial.serialutil import SerialException + except ModuleNotFoundError as e: + raise ModuleNotFoundError("You can do pip install vegasflow[quantum]") from e + + try: + qrng = QRNG(address="/dev/ttyACM0") + qrng.connect() + except SerialException as e: + raise SerialException("No quantum device found") from e + + self._quantum_sampler = qrng + super().__init__(*args, **kwargs) + + def run_integration(self, *args, **kwargs): + ret = super().run_integration(*args, **kwargs) + self._quantum_sampler.disconnect() + return ret + + def _generate_random_array(self, n_events, *args): + """ + Returns + ------- + `rnds`: array of (n_events, n_dim) random points + `idx` : index associated to each random point + `wgt` : wgt associated to the random point + """ + quantum_rnds_raw = self._quantum_sampler.random((n_events, self.n_dim)) + rnds_raw = tf.cast(quantum_rnds_raw, dtype=DTYPE) + + rnds, wgts_raw, *extra = self._digest_random_generation(rnds_raw, *args) + + wgts = wgts_raw * self.xjac + if self._xdelta is not None: + # Now apply integration limits + rnds = self._xmin + rnds * self._xdelta + wgts *= self._xdeltajac + return rnds, wgts, *extra + + +def quantum_wrapper(*args, **kwargs): + """Wrapper around QuantumIntegrator""" + return wrapper(QuantumIntegrator, *args, **kwargs) + + +def quantum_sampler(*args, **kwargs): + """Wrapper sampler around QuantumIntegrator""" + return sampler(QuantumIntegrator, *args, **kwargs) From 48d706edf8e316a1b0b207e5029628561d677e96 Mon Sep 17 00:00:00 2001 From: juacrumar Date: Thu, 30 Jan 2025 22:21:01 +0400 Subject: [PATCH 2/3] run all algorithms --- examples/quantum_mc.py | 27 +++++++++++----- src/vegasflow/configflow.py | 2 +- src/vegasflow/monte_carlo.py | 11 +++++-- src/vegasflow/plain.py | 2 +- src/vegasflow/quantum.py | 63 ++++++++++++++++++++---------------- src/vegasflow/vflow.py | 6 ++-- src/vegasflow/vflowplus.py | 8 ++--- 7 files changed, 71 insertions(+), 48 deletions(-) diff --git a/examples/quantum_mc.py b/examples/quantum_mc.py index 81f91a7..d125db0 100644 --- a/examples/quantum_mc.py +++ b/examples/quantum_mc.py @@ -1,17 +1,18 @@ """ Run integration with qibo as the backend +and compares it to other algorithms """ -from vegasflow.quantum import quantum_wrapper -from vegasflow import float_me +from vegasflow.quantum import quantum_wrapper, quantumflow_wrapper +from vegasflow import float_me, vegas_wrapper, plain_wrapper, run_eager import time import numpy as np import tensorflow as tf - +run_eager(True) # MC integration setup dim = 2 -ncalls = int(1e2) +ncalls = int(1e5) n_iter = 5 @@ -27,9 +28,19 @@ def symgauss(xarr): return pref * tf.exp(-coef) -if __name__ == "__main__": - """Testing several different integrations""" - print(f"VEGAS MC, ncalls={ncalls}:") +def test_me(wrapper, nev): + nev = int(nev) + algo = wrapper.__name__.split("_")[0] + print(f"> Running {algo} for {nev} events") start = time.time() - result = quantum_wrapper(symgauss, dim, n_iter, ncalls) + result = wrapper(symgauss, dim, n_iter, nev) end = time.time() + print(f"This run took {end-start}\n") + return result + + +if __name__ == "__main__": + test_me(plain_wrapper, ncalls) + test_me(vegas_wrapper, ncalls) + test_me(quantum_wrapper, ncalls) + test_me(quantumflow_wrapper, ncalls) diff --git a/src/vegasflow/configflow.py b/src/vegasflow/configflow.py index 06f2cf2..ec2d063 100644 --- a/src/vegasflow/configflow.py +++ b/src/vegasflow/configflow.py @@ -56,7 +56,7 @@ # Create and format the log handler _console_handler = logging.StreamHandler() _console_handler.setLevel(_log_level) -_console_format = logging.Formatter("[%(levelname)s] (%(name)s) %(message)s") +_console_format = logging.Formatter("[%(levelname)s] %(message)s") _console_handler.setFormatter(_console_format) logger.addHandler(_console_handler) diff --git a/src/vegasflow/monte_carlo.py b/src/vegasflow/monte_carlo.py index b826faf..2a22ad8 100644 --- a/src/vegasflow/monte_carlo.py +++ b/src/vegasflow/monte_carlo.py @@ -246,6 +246,12 @@ def generate_random_array(self, n_events, *args): xjac = xjac_raw / (self.xjac * n_events) return rnds, xjac + def _internal_sampler(self, n_events): + """Latent uniform sampler to be digested by the MC algorithm""" + return tf.random.uniform( + (n_events, self.n_dim), minval=TECH_CUT, maxval=1.0 - TECH_CUT, dtype=DTYPE + ) + def _generate_random_array(self, n_events, *args): """Generate a 2D array of (n_events, n_dim) points For the weight of the given point, this function is considered @@ -261,9 +267,8 @@ def _generate_random_array(self, n_events, *args): `idx` : index associated to each random point `wgt` : wgt associated to the random point """ - rnds_raw = tf.random.uniform( - (n_events, self.n_dim), minval=TECH_CUT, maxval=1.0 - TECH_CUT, dtype=DTYPE - ) + rnds_raw = self._internal_sampler(n_events) + # Now allow for the algorithm to produce the random numbers for the integration rnds, wgts_raw, *extra = self._digest_random_generation(rnds_raw, *args) diff --git a/src/vegasflow/plain.py b/src/vegasflow/plain.py index bc60e90..4a1e175 100644 --- a/src/vegasflow/plain.py +++ b/src/vegasflow/plain.py @@ -1,5 +1,5 @@ """ - Plain implementation of the plainest possible MonteCarlo +Plain implementation of the plainest possible MonteCarlo """ import tensorflow as tf diff --git a/src/vegasflow/quantum.py b/src/vegasflow/quantum.py index 09cace9..47cb0b0 100644 --- a/src/vegasflow/quantum.py +++ b/src/vegasflow/quantum.py @@ -2,15 +2,22 @@ A Monte Carlo integrator built upon Qibo for quantum integration """ -from .monte_carlo import wrapper, sampler -from .plain import PlainFlow # start building upon a naive idiotic integrator -from .configflow import run_eager, DTYPE import tensorflow as tf +from .configflow import DTYPE, run_eager +from .monte_carlo import MonteCarloFlow, sampler, wrapper +from .plain import PlainFlow +from .vflow import VegasFlow -class QuantumIntegrator(PlainFlow): + +class QuantumBase(MonteCarloFlow): """ - Simple Monte Carlo integrator. + This class serves as a basis for the quantum monte carlo integrator. + At initialization it tries to import qibolab and connect to the quantum device, + if successful, saves the reference to _quantum_sampler. + + This class is compatible with all ``MonteCarloFlow`` classes, it overrides + the uniform sampling and uses the quantum device instead. """ _CAN_RUN_VECTORIAL = False @@ -25,39 +32,35 @@ def __init__(self, *args, **kwargs): except ModuleNotFoundError as e: raise ModuleNotFoundError("You can do pip install vegasflow[quantum]") from e + qaddress = "/dev/ttyACM0" try: - qrng = QRNG(address="/dev/ttyACM0") + # Check whether the quantum device is available and we can connect + qrng = QRNG(address=qaddress) qrng.connect() + qrng.disconnect() except SerialException as e: - raise SerialException("No quantum device found") from e + raise SerialException(f"No quantum device found at {qaddress}") from e + + print(f"Sucessfuly connected to quantum device in {qaddress}") self._quantum_sampler = qrng super().__init__(*args, **kwargs) - def run_integration(self, *args, **kwargs): - ret = super().run_integration(*args, **kwargs) - self._quantum_sampler.disconnect() - return ret - - def _generate_random_array(self, n_events, *args): - """ - Returns - ------- - `rnds`: array of (n_events, n_dim) random points - `idx` : index associated to each random point - `wgt` : wgt associated to the random point - """ + def _internal_sampler(self, n_events): + """Sample ``n_events x n_dim`` numbers from the quantum device + and cast them to a TF DTYPE to pass down to the MC algorithm""" + self._quantum_sampler.connect() quantum_rnds_raw = self._quantum_sampler.random((n_events, self.n_dim)) - rnds_raw = tf.cast(quantum_rnds_raw, dtype=DTYPE) + self._quantum_sampler.disconnect() + return tf.cast(quantum_rnds_raw, dtype=DTYPE) - rnds, wgts_raw, *extra = self._digest_random_generation(rnds_raw, *args) - wgts = wgts_raw * self.xjac - if self._xdelta is not None: - # Now apply integration limits - rnds = self._xmin + rnds * self._xdelta - wgts *= self._xdeltajac - return rnds, wgts, *extra +class QuantumIntegrator(PlainFlow, QuantumBase): + pass + + +class QuantumFlow(VegasFlow, QuantumBase): + pass def quantum_wrapper(*args, **kwargs): @@ -65,6 +68,10 @@ def quantum_wrapper(*args, **kwargs): return wrapper(QuantumIntegrator, *args, **kwargs) +def quantumflow_wrapper(*args, **kwargs): + return wrapper(QuantumFlow, *args, **kwargs) + + def quantum_sampler(*args, **kwargs): """Wrapper sampler around QuantumIntegrator""" return sampler(QuantumIntegrator, *args, **kwargs) diff --git a/src/vegasflow/vflow.py b/src/vegasflow/vflow.py index 9096af6..9df58f9 100644 --- a/src/vegasflow/vflow.py +++ b/src/vegasflow/vflow.py @@ -1,8 +1,8 @@ """ - This module contains the VegasFlow class and all its auxiliary functions +This module contains the VegasFlow class and all its auxiliary functions - The main interfaces of this class are the class `VegasFlow` and the - `vegas_wrapper` +The main interfaces of this class are the class `VegasFlow` and the +`vegas_wrapper` """ import json diff --git a/src/vegasflow/vflowplus.py b/src/vegasflow/vflowplus.py index f329dec..2a833f9 100644 --- a/src/vegasflow/vflowplus.py +++ b/src/vegasflow/vflowplus.py @@ -1,10 +1,10 @@ """ - Implementation of vegas+ algorithm: +Implementation of vegas+ algorithm: - adaptive importance sampling + adaptive stratified sampling - from https://arxiv.org/abs/2009.05112 +adaptive importance sampling + adaptive stratified sampling +from https://arxiv.org/abs/2009.05112 - The main interface is the `VegasFlowPlus` class. +The main interface is the `VegasFlowPlus` class. """ from functools import partial From 02dc728c1f7b17d4a16516d98469aaa204aa8b9d Mon Sep 17 00:00:00 2001 From: juacrumar Date: Tue, 15 Apr 2025 07:29:19 +0000 Subject: [PATCH 3/3] update version of qibolab --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 25d245a..41dfe36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ [project.optional-dependencies] quantum = [ - "qibolab[qrng] @ git+https://github.com/qiboteam/qibolab@qrng" + "qibolab>=0.2.3" ] docs = [ 'sphinx',