lightrider 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ recursive-include lightrider/data *.npy
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: lightrider
3
+ Version: 0.1.0
4
+ Summary: Quantum random numbers from IQM hardware-generated bit pools
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy>=1.21
8
+
9
+ # lightrider
10
+
11
+ Quantum random numbers sourced from IQM hardware measurements.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install lightrider
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from lightrider import IQM_sirius
23
+
24
+ # 5 random integers between 1 and 100
25
+ IQM_sirius(5, 1, 100)
26
+ # → [42, 7, 88, 13, 56]
27
+
28
+ # 3 floats between 0.0 and 1.0 in steps of 0.1
29
+ IQM_sirius(3, 0.0, 1.0, step=0.1)
30
+ # → [0.3, 0.8, 0.1]
31
+
32
+ # 4 floats between 10.0 and 99.9 in steps of 0.1
33
+ IQM_sirius(4, 10.0, 99.9, step=0.1)
34
+ # → [23.4, 67.8, 45.1, 88.0]
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### `IQM_sirius(count, min_val, max_val, step=None)`
40
+
41
+ | Parameter | Type | Description |
42
+ |-----------|------|-------------|
43
+ | `count` | `int` | Number of values to return |
44
+ | `min_val` | `int` or `float` | Inclusive lower bound |
45
+ | `max_val` | `int` or `float` | Inclusive upper bound |
46
+ | `step` | `float` or `None` | Value granularity; `None` means integer steps |
47
+
48
+ Returns a `list` of quantum-random numbers in `[min_val, max_val]`.
49
+
50
+ ## Data source
51
+
52
+ The pool contains ~2 million bits collected from IQM quantum hardware via Hadamard coin-flip circuits across 10 qubits. Numbers are produced using rejection sampling for unbiased output.
@@ -0,0 +1,44 @@
1
+ # lightrider
2
+
3
+ Quantum random numbers sourced from IQM hardware measurements.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install lightrider
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from lightrider import IQM_sirius
15
+
16
+ # 5 random integers between 1 and 100
17
+ IQM_sirius(5, 1, 100)
18
+ # → [42, 7, 88, 13, 56]
19
+
20
+ # 3 floats between 0.0 and 1.0 in steps of 0.1
21
+ IQM_sirius(3, 0.0, 1.0, step=0.1)
22
+ # → [0.3, 0.8, 0.1]
23
+
24
+ # 4 floats between 10.0 and 99.9 in steps of 0.1
25
+ IQM_sirius(4, 10.0, 99.9, step=0.1)
26
+ # → [23.4, 67.8, 45.1, 88.0]
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### `IQM_sirius(count, min_val, max_val, step=None)`
32
+
33
+ | Parameter | Type | Description |
34
+ |-----------|------|-------------|
35
+ | `count` | `int` | Number of values to return |
36
+ | `min_val` | `int` or `float` | Inclusive lower bound |
37
+ | `max_val` | `int` or `float` | Inclusive upper bound |
38
+ | `step` | `float` or `None` | Value granularity; `None` means integer steps |
39
+
40
+ Returns a `list` of quantum-random numbers in `[min_val, max_val]`.
41
+
42
+ ## Data source
43
+
44
+ The pool contains ~2 million bits collected from IQM quantum hardware via Hadamard coin-flip circuits across 10 qubits. Numbers are produced using rejection sampling for unbiased output.
@@ -0,0 +1,8 @@
1
+ """
2
+ lightrider — Quantum random numbers from IQM hardware data.
3
+ """
4
+
5
+ from .core import IQM_sirius
6
+
7
+ __all__ = ["IQM_sirius"]
8
+ __version__ = "0.1.0"
@@ -0,0 +1,123 @@
1
+ """
2
+ Manages the quantum bit pool loaded from IQM hardware data.
3
+ Bits are consumed sequentially with wrap-around.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import math
9
+ import importlib.resources
10
+ from pathlib import Path
11
+ import threading
12
+
13
+ import numpy as np
14
+
15
+
16
+ _QUBIT_FILES = [f"qubit_{i}_sequence.npy" for i in range(10)]
17
+
18
+
19
+ def _load_bits() -> np.ndarray:
20
+ """Load and concatenate all qubit bit sequences into a single uint8 array."""
21
+ chunks = []
22
+ try:
23
+ # Python 3.9+ path
24
+ pkg_files = importlib.resources.files("lightrider.data")
25
+ for fname in _QUBIT_FILES:
26
+ data_bytes = (pkg_files / fname).read_bytes()
27
+ arr = np.frombuffer(data_bytes, dtype=np.uint8)
28
+ # npy files: reconstruct via np.load from bytes
29
+ import io
30
+ arr = np.load(io.BytesIO(data_bytes))
31
+ chunks.append(arr.astype(np.uint8).ravel())
32
+ except Exception:
33
+ # Fallback: load from package directory relative path
34
+ data_dir = Path(__file__).parent / "data"
35
+ for fname in _QUBIT_FILES:
36
+ arr = np.load(data_dir / fname)
37
+ chunks.append(arr.astype(np.uint8).ravel())
38
+ return np.concatenate(chunks)
39
+
40
+
41
+ class QuantumPool:
42
+ """Thread-safe sequential consumer of quantum random bits."""
43
+
44
+ def __init__(self) -> None:
45
+ self._bits: np.ndarray = _load_bits()
46
+ self._pos: int = 0
47
+ self._total: int = len(self._bits)
48
+ self._lock = threading.Lock()
49
+
50
+ @property
51
+ def total_bits(self) -> int:
52
+ return self._total
53
+
54
+ def consume(self, n: int) -> np.ndarray:
55
+ """Return the next *n* bits, wrapping around if the pool is exhausted."""
56
+ with self._lock:
57
+ if n > self._total:
58
+ raise ValueError(
59
+ f"Requested {n} bits but pool only has {self._total} bits total."
60
+ )
61
+ end = self._pos + n
62
+ if end <= self._total:
63
+ result = self._bits[self._pos : end].copy()
64
+ self._pos = end % self._total
65
+ else:
66
+ # Wrap around
67
+ tail = self._bits[self._pos :].copy()
68
+ head_n = n - len(tail)
69
+ head = self._bits[:head_n].copy()
70
+ result = np.concatenate([tail, head])
71
+ self._pos = head_n
72
+ return result
73
+
74
+ def bits_to_uint(self, bits: np.ndarray) -> int:
75
+ """Interpret a 1-D bit array (MSB first) as an unsigned integer."""
76
+ result = 0
77
+ for b in bits:
78
+ result = (result << 1) | int(b)
79
+ return result
80
+
81
+ def draw_integers(self, count: int, n_values: int) -> list[int]:
82
+ """
83
+ Draw *count* unbiased integers in [0, n_values) using rejection sampling.
84
+ Uses ceil(log2(n_values)) bits per candidate.
85
+ """
86
+ if n_values <= 0:
87
+ raise ValueError("n_values must be positive.")
88
+ if n_values == 1:
89
+ return [0] * count
90
+
91
+ bits_per = max(1, math.ceil(math.log2(n_values)))
92
+ # Upper power-of-two threshold for rejection
93
+ threshold = (1 << bits_per) # = 2**bits_per
94
+
95
+ results: list[int] = []
96
+ # Over-sample to reduce rejection loop iterations
97
+ batch = max(count * 2, 64)
98
+
99
+ while len(results) < count:
100
+ raw_bits = self.consume(batch * bits_per)
101
+ for i in range(batch):
102
+ segment = raw_bits[i * bits_per : (i + 1) * bits_per]
103
+ val = self.bits_to_uint(segment)
104
+ if val < n_values:
105
+ results.append(val)
106
+ if len(results) == count:
107
+ break
108
+
109
+ return results[:count]
110
+
111
+
112
+ # Module-level singleton
113
+ _pool: QuantumPool | None = None
114
+ _pool_lock = threading.Lock()
115
+
116
+
117
+ def get_pool() -> QuantumPool:
118
+ global _pool
119
+ if _pool is None:
120
+ with _pool_lock:
121
+ if _pool is None:
122
+ _pool = QuantumPool()
123
+ return _pool
@@ -0,0 +1,80 @@
1
+ """
2
+ Core API for the lightrider quantum random number generator.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import math
8
+ from typing import Union
9
+
10
+ from ._pool import get_pool
11
+
12
+ Number = Union[int, float]
13
+
14
+
15
+ def IQM_sirius(
16
+ count: int,
17
+ min_val: Number,
18
+ max_val: Number,
19
+ step: float | None = None,
20
+ ) -> list[Number]:
21
+ """
22
+ Return *count* quantum random numbers drawn from a hardware-generated bit pool.
23
+
24
+ Parameters
25
+ ----------
26
+ count : int
27
+ How many random values to return.
28
+ min_val : int or float
29
+ Inclusive lower bound.
30
+ max_val : int or float
31
+ Inclusive upper bound.
32
+ step : float or None
33
+ Granularity of values. ``None`` means integer steps (step=1).
34
+ Example: ``step=0.1`` produces values like 23.4, 67.8.
35
+
36
+ Returns
37
+ -------
38
+ list of int or float
39
+ Quantum-random values in [min_val, max_val].
40
+
41
+ Raises
42
+ ------
43
+ ValueError
44
+ If arguments are invalid.
45
+
46
+ Examples
47
+ --------
48
+ >>> IQM_sirius(5, 1, 100)
49
+ [42, 7, 88, 13, 56]
50
+
51
+ >>> IQM_sirius(3, 0.0, 1.0, step=0.1)
52
+ [0.3, 0.8, 0.1]
53
+ """
54
+ if count <= 0:
55
+ raise ValueError(f"count must be a positive integer, got {count!r}.")
56
+ if min_val > max_val:
57
+ raise ValueError(
58
+ f"min_val ({min_val}) must be <= max_val ({max_val})."
59
+ )
60
+
61
+ effective_step: float = step if step is not None else 1.0
62
+ if effective_step <= 0:
63
+ raise ValueError(f"step must be positive, got {step!r}.")
64
+
65
+ # Number of discrete values in the range (inclusive on both ends)
66
+ n_values = round((max_val - min_val) / effective_step) + 1
67
+
68
+ pool = get_pool()
69
+ indices = pool.draw_integers(count, n_values)
70
+
71
+ if step is None:
72
+ # Return plain ints when no step is specified and both bounds are int
73
+ if isinstance(min_val, int) and isinstance(max_val, int):
74
+ return [int(min_val) + idx for idx in indices]
75
+ else:
76
+ return [min_val + idx for idx in indices]
77
+ else:
78
+ # Round to avoid floating-point noise (e.g. 0.1+0.2 artifacts)
79
+ decimal_places = max(0, -math.floor(math.log10(step)))
80
+ return [round(min_val + idx * step, decimal_places) for idx in indices]
File without changes
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: lightrider
3
+ Version: 0.1.0
4
+ Summary: Quantum random numbers from IQM hardware-generated bit pools
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy>=1.21
8
+
9
+ # lightrider
10
+
11
+ Quantum random numbers sourced from IQM hardware measurements.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install lightrider
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from lightrider import IQM_sirius
23
+
24
+ # 5 random integers between 1 and 100
25
+ IQM_sirius(5, 1, 100)
26
+ # → [42, 7, 88, 13, 56]
27
+
28
+ # 3 floats between 0.0 and 1.0 in steps of 0.1
29
+ IQM_sirius(3, 0.0, 1.0, step=0.1)
30
+ # → [0.3, 0.8, 0.1]
31
+
32
+ # 4 floats between 10.0 and 99.9 in steps of 0.1
33
+ IQM_sirius(4, 10.0, 99.9, step=0.1)
34
+ # → [23.4, 67.8, 45.1, 88.0]
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### `IQM_sirius(count, min_val, max_val, step=None)`
40
+
41
+ | Parameter | Type | Description |
42
+ |-----------|------|-------------|
43
+ | `count` | `int` | Number of values to return |
44
+ | `min_val` | `int` or `float` | Inclusive lower bound |
45
+ | `max_val` | `int` or `float` | Inclusive upper bound |
46
+ | `step` | `float` or `None` | Value granularity; `None` means integer steps |
47
+
48
+ Returns a `list` of quantum-random numbers in `[min_val, max_val]`.
49
+
50
+ ## Data source
51
+
52
+ The pool contains ~2 million bits collected from IQM quantum hardware via Hadamard coin-flip circuits across 10 qubits. Numbers are produced using rejection sampling for unbiased output.
@@ -0,0 +1,23 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ lightrider/__init__.py
6
+ lightrider/_pool.py
7
+ lightrider/core.py
8
+ lightrider.egg-info/PKG-INFO
9
+ lightrider.egg-info/SOURCES.txt
10
+ lightrider.egg-info/dependency_links.txt
11
+ lightrider.egg-info/requires.txt
12
+ lightrider.egg-info/top_level.txt
13
+ lightrider/data/__init__.py
14
+ lightrider/data/qubit_0_sequence.npy
15
+ lightrider/data/qubit_1_sequence.npy
16
+ lightrider/data/qubit_2_sequence.npy
17
+ lightrider/data/qubit_3_sequence.npy
18
+ lightrider/data/qubit_4_sequence.npy
19
+ lightrider/data/qubit_5_sequence.npy
20
+ lightrider/data/qubit_6_sequence.npy
21
+ lightrider/data/qubit_7_sequence.npy
22
+ lightrider/data/qubit_8_sequence.npy
23
+ lightrider/data/qubit_9_sequence.npy
@@ -0,0 +1 @@
1
+ numpy>=1.21
@@ -0,0 +1,2 @@
1
+ dist
2
+ lightrider
@@ -0,0 +1,17 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "lightrider"
7
+ version = "0.1.0"
8
+ description = "Quantum random numbers from IQM hardware-generated bit pools"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = ["numpy>=1.21"]
12
+
13
+ [tool.setuptools.packages.find]
14
+ where = ["."]
15
+
16
+ [tool.setuptools.package-data]
17
+ lightrider = ["data/*.npy"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from setuptools import setup
2
+
3
+ setup()