QuantumWalkSimulation 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,88 @@
1
+ Metadata-Version: 2.4
2
+ Name: QuantumWalkSimulation
3
+ Version: 0.1.0
4
+ Summary: Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI) por dispatcher de estrutura (hipercubo, grade, ...)
5
+ Author-email: Igor <igorgomesdeoliveira@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Igoro2016/QuantumWalkSimulation
8
+ Project-URL: Repository, https://github.com/Igoro2016/QuantumWalkSimulation
9
+ Project-URL: Bug Tracker, https://github.com/Igoro2016/QuantumWalkSimulation/issues
10
+ Keywords: quantum walk,quantum computing,hypercube,grid,lackadaisical,simulation,physics
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Physics
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: numpy>=1.21
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
27
+ Requires-Dist: build; extra == "dev"
28
+ Requires-Dist: twine; extra == "dev"
29
+
30
+ # QuantumWalkSimulation
31
+
32
+ Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI —
33
+ Multi-self-loop Lackadaisical Quantum Walk com Inversao Parcial de Fase,
34
+ Souza et al., arXiv:2305.19614) via uma unica funcao `qw()`, parametrizada
35
+ por `base`, `degree` e `structure`. A moeda lackadaisical e o oraculo de
36
+ inversao parcial sao os mesmos independente da estrutura; apenas o
37
+ deslocamento (shift) muda, escolhido internamente por dispatcher:
38
+
39
+ - `structure="hypercube"` -> shift por distancia de Hamming (bit flip)
40
+ - `structure="grid"` -> shift por distancia de Manhattan (grade periodica)
41
+
42
+ ## Instalacao
43
+
44
+ ```bash
45
+ pip install QuantumWalkSimulation
46
+ ```
47
+
48
+ ## Uso
49
+
50
+ ```python
51
+ from QuantumWalkSimulation import qw
52
+
53
+ # Hipercubo Q_3 (N = 2**3 = 8 vertices)
54
+ r = qw(
55
+ base=2, degree=3, num_selfloop=3, t_f=100,
56
+ weight_value=1/8, marked_vertices=[0],
57
+ inverted_self_loops=2, structure="hypercube",
58
+ )
59
+
60
+ # Grade 4x4 (N = 4**2 = 16 vertices; degree = 2*n_dims)
61
+ r = qw(
62
+ base=4, degree=4, num_selfloop=3, t_f=100,
63
+ weight_value=1/16, marked_vertices=[0],
64
+ inverted_self_loops=2, structure="grid",
65
+ )
66
+
67
+ r.probs # (t_f, N)
68
+ r.det_times # (t_f,)
69
+ r.peak_detection
70
+ r.peak_step
71
+ ```
72
+
73
+ ## Parametros
74
+
75
+ | Parametro | Tipo | Descricao |
76
+ |---|---|---|
77
+ | `base` | `int` | N = base ** n_dims. Hipercubo exige base=2. |
78
+ | `degree` | `int` | Grau do vertice. Hipercubo: degree = n_dims. Grade: degree = 2 * n_dims (par). |
79
+ | `num_selfloop` | `int` | m self-loops por vertice. |
80
+ | `t_f` | `int` | Passos de simulacao. |
81
+ | `weight_value` | `float` | Peso l do self-loop. |
82
+ | `marked_vertices` | `list[int]` | Vertices marcados. |
83
+ | `inverted_self_loops` | `int` | s: quantos dos m self-loops tem fase invertida (1 <= s <= m). |
84
+ | `structure` | `str` | `"hypercube"` ou `"grid"`. |
85
+
86
+ ## Licenca
87
+
88
+ MIT
@@ -0,0 +1,59 @@
1
+ # QuantumWalkSimulation
2
+
3
+ Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI —
4
+ Multi-self-loop Lackadaisical Quantum Walk com Inversao Parcial de Fase,
5
+ Souza et al., arXiv:2305.19614) via uma unica funcao `qw()`, parametrizada
6
+ por `base`, `degree` e `structure`. A moeda lackadaisical e o oraculo de
7
+ inversao parcial sao os mesmos independente da estrutura; apenas o
8
+ deslocamento (shift) muda, escolhido internamente por dispatcher:
9
+
10
+ - `structure="hypercube"` -> shift por distancia de Hamming (bit flip)
11
+ - `structure="grid"` -> shift por distancia de Manhattan (grade periodica)
12
+
13
+ ## Instalacao
14
+
15
+ ```bash
16
+ pip install QuantumWalkSimulation
17
+ ```
18
+
19
+ ## Uso
20
+
21
+ ```python
22
+ from QuantumWalkSimulation import qw
23
+
24
+ # Hipercubo Q_3 (N = 2**3 = 8 vertices)
25
+ r = qw(
26
+ base=2, degree=3, num_selfloop=3, t_f=100,
27
+ weight_value=1/8, marked_vertices=[0],
28
+ inverted_self_loops=2, structure="hypercube",
29
+ )
30
+
31
+ # Grade 4x4 (N = 4**2 = 16 vertices; degree = 2*n_dims)
32
+ r = qw(
33
+ base=4, degree=4, num_selfloop=3, t_f=100,
34
+ weight_value=1/16, marked_vertices=[0],
35
+ inverted_self_loops=2, structure="grid",
36
+ )
37
+
38
+ r.probs # (t_f, N)
39
+ r.det_times # (t_f,)
40
+ r.peak_detection
41
+ r.peak_step
42
+ ```
43
+
44
+ ## Parametros
45
+
46
+ | Parametro | Tipo | Descricao |
47
+ |---|---|---|
48
+ | `base` | `int` | N = base ** n_dims. Hipercubo exige base=2. |
49
+ | `degree` | `int` | Grau do vertice. Hipercubo: degree = n_dims. Grade: degree = 2 * n_dims (par). |
50
+ | `num_selfloop` | `int` | m self-loops por vertice. |
51
+ | `t_f` | `int` | Passos de simulacao. |
52
+ | `weight_value` | `float` | Peso l do self-loop. |
53
+ | `marked_vertices` | `list[int]` | Vertices marcados. |
54
+ | `inverted_self_loops` | `int` | s: quantos dos m self-loops tem fase invertida (1 <= s <= m). |
55
+ | `structure` | `str` | `"hypercube"` ou `"grid"`. |
56
+
57
+ ## Licenca
58
+
59
+ MIT
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "QuantumWalkSimulation"
7
+ version = "0.1.0"
8
+ description = "Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI) por dispatcher de estrutura (hipercubo, grade, ...)"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [
12
+ { name = "Igor", email = "igorgomesdeoliveira@gmail.com" }
13
+ ]
14
+ keywords = [
15
+ "quantum walk",
16
+ "quantum computing",
17
+ "hypercube",
18
+ "grid",
19
+ "lackadaisical",
20
+ "simulation",
21
+ "physics",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "Intended Audience :: Science/Research",
26
+ "Topic :: Scientific/Engineering :: Physics",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.9",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Operating System :: OS Independent",
34
+ ]
35
+ requires-python = ">=3.9"
36
+ dependencies = [
37
+ "numpy>=1.21",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ dev = [
42
+ "pytest>=7.0",
43
+ "pytest-cov>=4.0",
44
+ "build",
45
+ "twine",
46
+ ]
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/Igoro2016/QuantumWalkSimulation"
50
+ Repository = "https://github.com/Igoro2016/QuantumWalkSimulation"
51
+ "Bug Tracker" = "https://github.com/Igoro2016/QuantumWalkSimulation/issues"
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.pytest.ini_options]
57
+ testpaths = ["tests"]
58
+ addopts = "-v --tb=short"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.4
2
+ Name: QuantumWalkSimulation
3
+ Version: 0.1.0
4
+ Summary: Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI) por dispatcher de estrutura (hipercubo, grade, ...)
5
+ Author-email: Igor <igorgomesdeoliveira@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Igoro2016/QuantumWalkSimulation
8
+ Project-URL: Repository, https://github.com/Igoro2016/QuantumWalkSimulation
9
+ Project-URL: Bug Tracker, https://github.com/Igoro2016/QuantumWalkSimulation/issues
10
+ Keywords: quantum walk,quantum computing,hypercube,grid,lackadaisical,simulation,physics
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Physics
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: numpy>=1.21
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
27
+ Requires-Dist: build; extra == "dev"
28
+ Requires-Dist: twine; extra == "dev"
29
+
30
+ # QuantumWalkSimulation
31
+
32
+ Simulacao generica de caminhadas quanticas discretas (MSLQW-PPI —
33
+ Multi-self-loop Lackadaisical Quantum Walk com Inversao Parcial de Fase,
34
+ Souza et al., arXiv:2305.19614) via uma unica funcao `qw()`, parametrizada
35
+ por `base`, `degree` e `structure`. A moeda lackadaisical e o oraculo de
36
+ inversao parcial sao os mesmos independente da estrutura; apenas o
37
+ deslocamento (shift) muda, escolhido internamente por dispatcher:
38
+
39
+ - `structure="hypercube"` -> shift por distancia de Hamming (bit flip)
40
+ - `structure="grid"` -> shift por distancia de Manhattan (grade periodica)
41
+
42
+ ## Instalacao
43
+
44
+ ```bash
45
+ pip install QuantumWalkSimulation
46
+ ```
47
+
48
+ ## Uso
49
+
50
+ ```python
51
+ from QuantumWalkSimulation import qw
52
+
53
+ # Hipercubo Q_3 (N = 2**3 = 8 vertices)
54
+ r = qw(
55
+ base=2, degree=3, num_selfloop=3, t_f=100,
56
+ weight_value=1/8, marked_vertices=[0],
57
+ inverted_self_loops=2, structure="hypercube",
58
+ )
59
+
60
+ # Grade 4x4 (N = 4**2 = 16 vertices; degree = 2*n_dims)
61
+ r = qw(
62
+ base=4, degree=4, num_selfloop=3, t_f=100,
63
+ weight_value=1/16, marked_vertices=[0],
64
+ inverted_self_loops=2, structure="grid",
65
+ )
66
+
67
+ r.probs # (t_f, N)
68
+ r.det_times # (t_f,)
69
+ r.peak_detection
70
+ r.peak_step
71
+ ```
72
+
73
+ ## Parametros
74
+
75
+ | Parametro | Tipo | Descricao |
76
+ |---|---|---|
77
+ | `base` | `int` | N = base ** n_dims. Hipercubo exige base=2. |
78
+ | `degree` | `int` | Grau do vertice. Hipercubo: degree = n_dims. Grade: degree = 2 * n_dims (par). |
79
+ | `num_selfloop` | `int` | m self-loops por vertice. |
80
+ | `t_f` | `int` | Passos de simulacao. |
81
+ | `weight_value` | `float` | Peso l do self-loop. |
82
+ | `marked_vertices` | `list[int]` | Vertices marcados. |
83
+ | `inverted_self_loops` | `int` | s: quantos dos m self-loops tem fase invertida (1 <= s <= m). |
84
+ | `structure` | `str` | `"hypercube"` ou `"grid"`. |
85
+
86
+ ## Licenca
87
+
88
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/QuantumWalkSimulation.egg-info/PKG-INFO
4
+ src/QuantumWalkSimulation.egg-info/SOURCES.txt
5
+ src/QuantumWalkSimulation.egg-info/dependency_links.txt
6
+ src/QuantumWalkSimulation.egg-info/requires.txt
7
+ src/QuantumWalkSimulation.egg-info/top_level.txt
8
+ src/quantumwalksimulation/__init__.py
9
+ src/quantumwalksimulation/core.py
@@ -0,0 +1,7 @@
1
+ numpy>=1.21
2
+
3
+ [dev]
4
+ pytest>=7.0
5
+ pytest-cov>=4.0
6
+ build
7
+ twine
@@ -0,0 +1,32 @@
1
+ """
2
+ QuantumWalkSimulation
3
+ ======================
4
+ Nucleo generico de Multi-self-loop Lackadaisical Quantum Walk com
5
+ Inversao Parcial de Fase (MSLQW-PPI), parametrizado por `base`, `degree`
6
+ e `structure` -- uma unica funcao `qw()` cobre hipercubo e grade (e
7
+ outras estruturas no futuro), com o shift escolhido por dispatcher
8
+ interno (hamming para hipercubo, manhattan para grade).
9
+
10
+ >>> from QuantumWalkSimulation import qw
11
+ >>> r = qw(
12
+ ... base=2, degree=3, num_selfloop=3, t_f=100,
13
+ ... weight_value=1/8, marked_vertices=[0],
14
+ ... inverted_self_loops=2, structure="hypercube",
15
+ ... )
16
+ >>> r.probs.shape
17
+ (100, 8)
18
+ """
19
+
20
+ from importlib.metadata import version, PackageNotFoundError
21
+
22
+ try:
23
+ __version__: str = version("QuantumWalkSimulation")
24
+ except PackageNotFoundError: # pragma: no cover
25
+ __version__ = "0.1.0"
26
+
27
+ __author__ = "Igor"
28
+ __license__ = "MIT"
29
+
30
+ from QuantumWalkSimulation.core import qw, QWResult
31
+
32
+ __all__ = ["qw", "QWResult"]
@@ -0,0 +1,281 @@
1
+ """
2
+ qw_core.py
3
+ ==========
4
+ Nucleo generico de MSLQW-PPI (Multi-self-loop Lackadaisical Quantum Walk
5
+ com Inversao Parcial de Fase), parametrizado por `base`, `degree` e
6
+ `structure`, conforme especificacao de Igor.
7
+
8
+ Ideia central: a moeda lackadaisical (Eq. 12-13 do artigo de Souza et al.,
9
+ arXiv:2305.19614) e o oraculo de inversao parcial (Eq. 18-26) sao os
10
+ MESMOS independente da estrutura do grafo -- o que muda e apenas o
11
+ operador de deslocamento (S), que depende de como os vertices se
12
+ conectam. Por isso a funcao `qw()` decide, a partir de `structure`, qual
13
+ "shift provider" usar:
14
+
15
+ structure == "hypercube" -> shift por distancia de Hamming (bit flip)
16
+ structure == "grid" -> shift por distancia de Manhattan
17
+ (coordenada +-1, periodico/toroidal para
18
+ manter grau uniforme em todos os vertices
19
+ -- necessario porque a moeda lackadaisical
20
+ e a MESMA em todo vertice, o que exige
21
+ grau uniforme; grade com reflexao de
22
+ borda teria grau variavel e exigiria uma
23
+ moeda por vertice, fora do escopo do
24
+ MSLQW-PPI original)
25
+
26
+ A moeda, o oraculo e o loop de evolucao ficam em UM SO lugar (nao
27
+ duplicados por estrutura); so o shift e "plugavel".
28
+
29
+ Interface
30
+ ---------
31
+ from qw_core import qw
32
+
33
+ # Hipercubo Q_3 -> N = 2**3 = 8 vertices
34
+ r = qw(
35
+ base=2, degree=3, num_selfloop=3, t_f=100,
36
+ weight_value=1/8, marked_vertices=[0],
37
+ inverted_self_loops=2, structure="hypercube",
38
+ )
39
+
40
+ # Grade 4x4 -> N = 4**2 = 16 vertices (degree=4 = grau 2*n_dims)
41
+ r = qw(
42
+ base=4, degree=4, num_selfloop=3, t_f=100,
43
+ weight_value=1/16, marked_vertices=[0],
44
+ inverted_self_loops=2, structure="grid",
45
+ )
46
+
47
+ r.probs, r.det_times # mesmo formato de biblioteca_qw: (t_f, N) / (t_f,)
48
+ """
49
+
50
+ from __future__ import annotations
51
+
52
+ from dataclasses import dataclass
53
+ from typing import Callable, List, Optional, Tuple
54
+
55
+ import numpy as np
56
+
57
+
58
+ # ---------------------------------------------------------------------------
59
+ # Resultado
60
+ # ---------------------------------------------------------------------------
61
+
62
+ @dataclass
63
+ class QWResult:
64
+ probs: np.ndarray
65
+ det_times: np.ndarray
66
+ structure: str
67
+ N: int
68
+ n_dims: int
69
+ coin_dim: int
70
+
71
+ def __iter__(self):
72
+ yield self.probs
73
+ yield self.det_times
74
+
75
+ @property
76
+ def peak_step(self) -> int:
77
+ return int(np.argmax(self.det_times))
78
+
79
+ @property
80
+ def peak_detection(self) -> float:
81
+ return float(self.det_times.max())
82
+
83
+
84
+ # ---------------------------------------------------------------------------
85
+ # Shift providers -- um por structure. Cada um recebe (N, n_dims, base) e
86
+ # devolve uma funcao vetorizada shift(state) -> state (shape (N, coin_dim)),
87
+ # que move as `n_dims`*2 ou `n_dims` primeiras colunas (arestas normais) e
88
+ # preserva as colunas de self-loop.
89
+ # ---------------------------------------------------------------------------
90
+
91
+ def _hamming_shift_targets(N: int, n_dims: int) -> List[np.ndarray]:
92
+ """Hipercubo Q_n: degree = n_dims arestas, uma por bit invertido."""
93
+ return [np.arange(N) ^ (1 << d) for d in range(n_dims)]
94
+
95
+
96
+ def _manhattan_shift_targets(N: int, n_dims: int, base: int) -> List[np.ndarray]:
97
+ """Grade base^n_dims periodica: degree = 2*n_dims arestas (+1/-1 por
98
+ dimensao). Coordenadas em base mista (digitos de 0..base-1)."""
99
+ strides = [base ** (n_dims - 1 - i) for i in range(n_dims)]
100
+ vertices = np.arange(N)
101
+ # decompoe cada vertice em digitos na base `base`
102
+ coords = np.zeros((N, n_dims), dtype=np.int64)
103
+ tmp = vertices.copy()
104
+ for i in range(n_dims):
105
+ coords[:, i] = tmp // strides[i]
106
+ tmp = tmp % strides[i]
107
+
108
+ targets = []
109
+ for dim in range(n_dims):
110
+ for delta in (+1, -1):
111
+ nc = coords.copy()
112
+ nc[:, dim] = (nc[:, dim] + delta) % base # periodico (toroidal)
113
+ idx = np.zeros(N, dtype=np.int64)
114
+ for i in range(n_dims):
115
+ idx += nc[:, i] * strides[i]
116
+ targets.append(idx)
117
+ return targets
118
+
119
+
120
+ _SHIFT_PROVIDERS: dict = {
121
+ "hypercube": _hamming_shift_targets,
122
+ "grid": _manhattan_shift_targets,
123
+ }
124
+
125
+
126
+ # ---------------------------------------------------------------------------
127
+ # Moeda lackadaisical (identica para as duas estruturas, Eq. 12-13)
128
+ # ---------------------------------------------------------------------------
129
+
130
+ def _lackadaisical_sc(degree: int, m: int, l: float) -> np.ndarray:
131
+ coin_dim = degree + m
132
+ l_prime = l / m if m > 0 else 0.0
133
+ s_c = np.empty(coin_dim, dtype=complex)
134
+ s_c[:degree] = 1.0
135
+ if m > 0:
136
+ s_c[degree:] = np.sqrt(l_prime)
137
+ s_c /= np.sqrt(degree + l)
138
+ return s_c
139
+
140
+
141
+ def _build_coin(degree: int, m: int, l: float) -> np.ndarray:
142
+ s_c = _lackadaisical_sc(degree, m, l)
143
+ coin_dim = degree + m
144
+ return 2.0 * np.outer(s_c, s_c.conj()) - np.eye(coin_dim, dtype=complex)
145
+
146
+
147
+ def _oracle_mask(degree: int, m: int, s: int) -> np.ndarray:
148
+ coin_dim = degree + m
149
+ mask = np.zeros(coin_dim, dtype=bool)
150
+ mask[:degree] = True # arestas normais sempre invertidas
151
+ mask[degree:degree + s] = True # s dos m self-loops
152
+ return mask
153
+
154
+
155
+ # ---------------------------------------------------------------------------
156
+ # qw() -- funcao fabrica generica, com o dispatcher pedido:
157
+ # if structure == "grid": shift = manhattan
158
+ # if structure == "hypercube": shift = hamming
159
+ # ---------------------------------------------------------------------------
160
+
161
+ def qw(
162
+ *,
163
+ base: int,
164
+ degree: int,
165
+ num_selfloop: int,
166
+ t_f: int,
167
+ weight_value: float,
168
+ marked_vertices: List[int],
169
+ inverted_self_loops: int = 1,
170
+ structure: str,
171
+ ) -> QWResult:
172
+ """Executa a MSLQW-PPI generica na estrutura indicada.
173
+
174
+ Parameters
175
+ ----------
176
+ base : int
177
+ "L" da estrutura. N = base ** n_dims.
178
+ - hypercube: base DEVE ser 2 (hipercubo binario Q_n).
179
+ - grid: qualquer base >= 2 (grade base x base x ... periodica).
180
+ degree : int
181
+ Grau do vertice (numero de arestas "normais" da moeda).
182
+ - hypercube: degree == n_dims (grau de Q_n e n).
183
+ - grid: degree == 2 * n_dims (grau de uma grade n-dimensional
184
+ periodica), portanto deve ser par.
185
+ num_selfloop : int
186
+ Numero m de self-loops por vertice (>= 0).
187
+ t_f : int
188
+ Passos de simulacao.
189
+ weight_value : float
190
+ Peso l do self-loop (Eq. 13). Ignorado se num_selfloop == 0.
191
+ marked_vertices : list[int]
192
+ Vertices marcados, indices em [0, N).
193
+ inverted_self_loops : int
194
+ s: quantos dos m self-loops tem a fase invertida no oraculo,
195
+ 1 <= s <= num_selfloop (Eq. 18-26). Ignorado se num_selfloop == 0.
196
+ structure : {"hypercube", "grid"}
197
+ Estrutura do grafo -- decide o shift usado (dispatcher).
198
+
199
+ Returns
200
+ -------
201
+ QWResult com .probs (t_f, N), .det_times (t_f,), .peak_step, .peak_detection.
202
+ """
203
+ if structure not in _SHIFT_PROVIDERS:
204
+ raise ValueError(
205
+ f"structure={structure!r} nao suportada. "
206
+ f"Use uma de {list(_SHIFT_PROVIDERS)}."
207
+ )
208
+ if t_f < 1:
209
+ raise ValueError("t_f deve ser >= 1.")
210
+ if num_selfloop < 0:
211
+ raise ValueError("num_selfloop deve ser >= 0.")
212
+
213
+ # ---------------- dispatcher: deriva n_dims e os shift targets -------
214
+ if structure == "hypercube":
215
+ if base != 2:
216
+ raise ValueError("structure='hypercube' exige base=2 (Q_n binario).")
217
+ n_dims = degree
218
+ N = base ** n_dims
219
+ shift_targets = _hamming_shift_targets(N, n_dims)
220
+ else: # "grid"
221
+ if degree % 2 != 0:
222
+ raise ValueError(
223
+ "structure='grid': degree deve ser par (degree = 2*n_dims)."
224
+ )
225
+ n_dims = degree // 2
226
+ N = base ** n_dims
227
+ shift_targets = _manhattan_shift_targets(N, n_dims, base)
228
+
229
+ m = num_selfloop
230
+ coin_dim = degree + m
231
+
232
+ if m > 0:
233
+ if not (1 <= inverted_self_loops <= m):
234
+ raise ValueError(
235
+ f"inverted_self_loops deve estar em [1, num_selfloop={m}]; "
236
+ f"recebido {inverted_self_loops}."
237
+ )
238
+ l = float(weight_value)
239
+ C = _build_coin(degree, m, l)
240
+ oracle = _oracle_mask(degree, m, inverted_self_loops)
241
+ else:
242
+ s_c = np.full(degree, 1.0 / np.sqrt(degree), dtype=complex)
243
+ C = 2.0 * np.outer(s_c, s_c.conj()) - np.eye(degree, dtype=complex)
244
+ oracle = np.ones(degree, dtype=bool)
245
+
246
+ marked_mask = np.zeros(N, dtype=bool)
247
+ marked_mask[marked_vertices] = True
248
+
249
+ # ---------------- estado inicial (Eq. 14-15) --------------------------
250
+ if m > 0:
251
+ s_c0 = _lackadaisical_sc(degree, m, float(weight_value))
252
+ else:
253
+ s_c0 = np.full(degree, 1.0 / np.sqrt(degree), dtype=complex)
254
+ state = np.tile(s_c0, (N, 1)) / np.sqrt(N) # shape (N, coin_dim)
255
+
256
+ # ---------------- loop de evolucao (identico p/ qualquer structure) --
257
+ probs = np.empty((t_f, N), dtype=float)
258
+ det_times = np.empty(t_f, dtype=float)
259
+
260
+ for t in range(t_f):
261
+ # oraculo
262
+ state = state.copy()
263
+ state[np.ix_(marked_mask, oracle)] *= -1.0
264
+ # moeda
265
+ state = state @ C.T
266
+ # shift (plugavel: hamming ou manhattan)
267
+ new_state = np.empty_like(state)
268
+ for d, targets in enumerate(shift_targets):
269
+ new_state[targets, d] = state[:, d]
270
+ if coin_dim > degree:
271
+ new_state[:, degree:] = state[:, degree:] # self-loops nao movem
272
+ state = new_state
273
+
274
+ vertex_probs = np.sum(np.abs(state) ** 2, axis=1)
275
+ probs[t] = vertex_probs
276
+ det_times[t] = float(np.sum(vertex_probs[marked_mask]))
277
+
278
+ return QWResult(
279
+ probs=probs, det_times=det_times,
280
+ structure=structure, N=N, n_dims=n_dims, coin_dim=coin_dim,
281
+ )