Spaces:
Runtime error
Runtime error
harishaseebat92 commited on
Commit ·
d6abeb6
1
Parent(s): 732829e
Enforce snap to grid behavior for both Delta and Gaussian excitations in the simulator, matching QPU semantics.
Browse files- em/simulation.py +5 -3
- qlbm/qlbm_sample_app.py +2 -2
- qlbm_embedded.py +4 -4
- utils/delta_impulse_generator.py +52 -7
em/simulation.py
CHANGED
|
@@ -215,7 +215,7 @@ def redraw_surface_plot():
|
|
| 215 |
mesh,
|
| 216 |
scalars='scalars',
|
| 217 |
# clim=g.surface_clims[field],
|
| 218 |
-
cmap="
|
| 219 |
show_scalar_bar=False,
|
| 220 |
show_edges=True,
|
| 221 |
edge_color='grey',
|
|
@@ -307,13 +307,15 @@ def run_simulation_only():
|
|
| 307 |
if state.dist_type == "Delta":
|
| 308 |
initial_state = create_impulse_state_from_pos(
|
| 309 |
(nx, nx),
|
| 310 |
-
(float(state.impulse_x), float(state.impulse_y))
|
|
|
|
| 311 |
)
|
| 312 |
else:
|
| 313 |
initial_state = create_gaussian_state_from_pos(
|
| 314 |
(nx, nx),
|
| 315 |
(float(state.mu_x), float(state.mu_y)),
|
| 316 |
-
(float(state.sigma_x), float(state.sigma_y))
|
|
|
|
| 317 |
)
|
| 318 |
except ValueError as e:
|
| 319 |
state.error_message = f"Initial State Error: {e}"
|
|
|
|
| 215 |
mesh,
|
| 216 |
scalars='scalars',
|
| 217 |
# clim=g.surface_clims[field],
|
| 218 |
+
cmap="turbo",
|
| 219 |
show_scalar_bar=False,
|
| 220 |
show_edges=True,
|
| 221 |
edge_color='grey',
|
|
|
|
| 307 |
if state.dist_type == "Delta":
|
| 308 |
initial_state = create_impulse_state_from_pos(
|
| 309 |
(nx, nx),
|
| 310 |
+
(float(state.impulse_x), float(state.impulse_y)),
|
| 311 |
+
snap_to_grid=True,
|
| 312 |
)
|
| 313 |
else:
|
| 314 |
initial_state = create_gaussian_state_from_pos(
|
| 315 |
(nx, nx),
|
| 316 |
(float(state.mu_x), float(state.mu_y)),
|
| 317 |
+
(float(state.sigma_x), float(state.sigma_y)),
|
| 318 |
+
snap_to_grid=True,
|
| 319 |
)
|
| 320 |
except ValueError as e:
|
| 321 |
state.error_message = f"Initial State Error: {e}"
|
qlbm/qlbm_sample_app.py
CHANGED
|
@@ -509,7 +509,7 @@ def run_sampling_hw_ibm(
|
|
| 509 |
uz,
|
| 510 |
init_state_prep_circ,
|
| 511 |
T_list,
|
| 512 |
-
shots=2**
|
| 513 |
vel_resolution=32,
|
| 514 |
output_resolution=40,
|
| 515 |
logger=None,
|
|
@@ -619,7 +619,7 @@ def run_sampling_hw_ionq(
|
|
| 619 |
uz,
|
| 620 |
init_state_prep_circ,
|
| 621 |
T_list,
|
| 622 |
-
shots=2**
|
| 623 |
vel_resolution=32,
|
| 624 |
output_resolution=40,
|
| 625 |
logger=None,
|
|
|
|
| 509 |
uz,
|
| 510 |
init_state_prep_circ,
|
| 511 |
T_list,
|
| 512 |
+
shots=2**14,
|
| 513 |
vel_resolution=32,
|
| 514 |
output_resolution=40,
|
| 515 |
logger=None,
|
|
|
|
| 619 |
uz,
|
| 620 |
init_state_prep_circ,
|
| 621 |
T_list,
|
| 622 |
+
shots=2**14,
|
| 623 |
vel_resolution=32,
|
| 624 |
output_resolution=40,
|
| 625 |
logger=None,
|
qlbm_embedded.py
CHANGED
|
@@ -1197,7 +1197,7 @@ def run_simulation():
|
|
| 1197 |
init_state_prep_circ=init_state_prep_circ,
|
| 1198 |
T_list=params["T_list"],
|
| 1199 |
# shots=2**14, # Reduced shots for responsiveness/quota
|
| 1200 |
-
shots=2**
|
| 1201 |
vel_resolution=min(params['grid_size'], 32),
|
| 1202 |
output_resolution=min(2*params['grid_size'], 40),
|
| 1203 |
logger=log_to_console
|
|
@@ -1290,7 +1290,7 @@ def run_simulation():
|
|
| 1290 |
uz=params["vz_expr"],
|
| 1291 |
init_state_prep_circ=init_state_prep_circ,
|
| 1292 |
T_list=params["T_list"],
|
| 1293 |
-
shots=2**
|
| 1294 |
vel_resolution=min(params['grid_size'], 32),
|
| 1295 |
output_resolution=min(2*params['grid_size'], 40),
|
| 1296 |
logger=log_to_console
|
|
@@ -1398,7 +1398,7 @@ def run_simulation():
|
|
| 1398 |
if grid_obj:
|
| 1399 |
_plotter.clear()
|
| 1400 |
isosurfaces = grid_obj.contour(isosurfaces=7, scalars="scalars")
|
| 1401 |
-
_plotter.add_mesh(isosurfaces, cmap="
|
| 1402 |
_plotter.add_axes()
|
| 1403 |
_plotter.show_grid()
|
| 1404 |
|
|
@@ -1837,7 +1837,7 @@ def _build_control_panels(plotter):
|
|
| 1837 |
with vuetify3.VCard(classes="mb-2"):
|
| 1838 |
vuetify3.VCardTitle("Time", classes="text-subtitle-2 font-weight-bold text-primary")
|
| 1839 |
with vuetify3.VCardText():
|
| 1840 |
-
vuetify3.VSlider(label="Total Time", v_model=("qlbm_time_steps", 10), min=0, max=
|
| 1841 |
thumb_label="always", show_ticks="always", color="primary", density="compact", hide_details=True)
|
| 1842 |
vuetify3.VAlert(v_if="qlbm_time_steps > 100", type="warning", variant="tonal", density="compact",
|
| 1843 |
children=["Warning: High time steps may increase runtime."], classes="mt-2")
|
|
|
|
| 1197 |
init_state_prep_circ=init_state_prep_circ,
|
| 1198 |
T_list=params["T_list"],
|
| 1199 |
# shots=2**14, # Reduced shots for responsiveness/quota
|
| 1200 |
+
shots=2**14,
|
| 1201 |
vel_resolution=min(params['grid_size'], 32),
|
| 1202 |
output_resolution=min(2*params['grid_size'], 40),
|
| 1203 |
logger=log_to_console
|
|
|
|
| 1290 |
uz=params["vz_expr"],
|
| 1291 |
init_state_prep_circ=init_state_prep_circ,
|
| 1292 |
T_list=params["T_list"],
|
| 1293 |
+
shots=2**14,
|
| 1294 |
vel_resolution=min(params['grid_size'], 32),
|
| 1295 |
output_resolution=min(2*params['grid_size'], 40),
|
| 1296 |
logger=log_to_console
|
|
|
|
| 1398 |
if grid_obj:
|
| 1399 |
_plotter.clear()
|
| 1400 |
isosurfaces = grid_obj.contour(isosurfaces=7, scalars="scalars")
|
| 1401 |
+
_plotter.add_mesh(isosurfaces, cmap="turbo", opacity=0.3, show_scalar_bar=True)
|
| 1402 |
_plotter.add_axes()
|
| 1403 |
_plotter.show_grid()
|
| 1404 |
|
|
|
|
| 1837 |
with vuetify3.VCard(classes="mb-2"):
|
| 1838 |
vuetify3.VCardTitle("Time", classes="text-subtitle-2 font-weight-bold text-primary")
|
| 1839 |
with vuetify3.VCardText():
|
| 1840 |
+
vuetify3.VSlider(label="Total Time", v_model=("qlbm_time_steps", 10), min=0, max=30, step=1,
|
| 1841 |
thumb_label="always", show_ticks="always", color="primary", density="compact", hide_details=True)
|
| 1842 |
vuetify3.VAlert(v_if="qlbm_time_steps > 100", type="warning", variant="tonal", density="compact",
|
| 1843 |
children=["Warning: High time steps may increase runtime."], classes="mt-2")
|
utils/delta_impulse_generator.py
CHANGED
|
@@ -107,16 +107,31 @@ def _normalize_to_unit(vec: np.ndarray) -> np.ndarray:
|
|
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
-
def create_impulse_state_from_pos(grid_dims, pos01):
|
| 111 |
"""
|
| 112 |
Create a delta-like initial state from continuous position pos01=(x,y) in [0,1].
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
Why grid_dims?
|
| 115 |
- Simulation runs on a discrete nx×ny lattice; the continuous position must be
|
| 116 |
discretized onto that grid to produce the state vector fed into the solver.
|
| 117 |
-
- grid_dims provides (nx, ny) so we can map (x,y)∈[0,1]→grid coordinates
|
| 118 |
-
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
The preview uses create_impulse_preview_state(), which renders a smooth bump on a
|
| 122 |
fixed unit-square grid independent of nx for visualization.
|
|
@@ -128,6 +143,25 @@ def create_impulse_state_from_pos(grid_dims, pos01):
|
|
| 128 |
|
| 129 |
gx = px * (grid_width - 1)
|
| 130 |
gy = py * (grid_height - 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
i0, j0 = int(np.floor(gx)), int(np.floor(gy))
|
| 132 |
i1, j1 = min(i0 + 1, grid_width - 1), min(j0 + 1, grid_height - 1)
|
| 133 |
dx, dy = gx - i0, gy - j0
|
|
@@ -137,8 +171,6 @@ def create_impulse_state_from_pos(grid_dims, pos01):
|
|
| 137 |
w01 = (1 - dx) * dy
|
| 138 |
w11 = dx * dy
|
| 139 |
|
| 140 |
-
grid_size = grid_width * grid_height
|
| 141 |
-
total_size = 4 * grid_size
|
| 142 |
field = np.zeros(grid_size)
|
| 143 |
field[j0 * grid_width + i0] += w00
|
| 144 |
field[j0 * grid_width + i1] += w10
|
|
@@ -151,11 +183,19 @@ def create_impulse_state_from_pos(grid_dims, pos01):
|
|
| 151 |
return initial_state
|
| 152 |
|
| 153 |
|
| 154 |
-
def create_gaussian_state_from_pos(grid_dims, mu01, sigma01):
|
| 155 |
"""
|
| 156 |
Create a Gaussian initial state with center mu01=(x,y) and spreads sigma01=(sx,sy)
|
| 157 |
in [0,1] of the domain, then discretize to the solver grid given by grid_dims.
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
Why grid_dims?
|
| 160 |
- The quantum solver expects a vector aligned to the chosen nx×ny simulation grid.
|
| 161 |
We convert normalized μ and σ (fractions of the domain) into grid units using
|
|
@@ -177,6 +217,11 @@ def create_gaussian_state_from_pos(grid_dims, mu01, sigma01):
|
|
| 177 |
|
| 178 |
mu_x = mu_x01 * (grid_width - 1)
|
| 179 |
mu_y = mu_y01 * (grid_height - 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
sigma_x = sig_x01 * (grid_width - 1)
|
| 181 |
sigma_y = sig_y01 * (grid_height - 1)
|
| 182 |
|
|
|
|
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
+
def create_impulse_state_from_pos(grid_dims, pos01, snap_to_grid=True):
|
| 111 |
"""
|
| 112 |
Create a delta-like initial state from continuous position pos01=(x,y) in [0,1].
|
| 113 |
|
| 114 |
+
Args:
|
| 115 |
+
grid_dims: Tuple (nx, ny) defining the simulation grid dimensions.
|
| 116 |
+
pos01: Tuple (x, y) with continuous position in [0, 1] range.
|
| 117 |
+
snap_to_grid: If True (default), snaps the impulse to the nearest grid node
|
| 118 |
+
for an exact delta with peak value = 1.0. If False, uses
|
| 119 |
+
bilinear interpolation which distributes amplitude to 4 nodes.
|
| 120 |
+
|
| 121 |
Why grid_dims?
|
| 122 |
- Simulation runs on a discrete nx×ny lattice; the continuous position must be
|
| 123 |
discretized onto that grid to produce the state vector fed into the solver.
|
| 124 |
+
- grid_dims provides (nx, ny) so we can map (x,y)∈[0,1]→grid coordinates.
|
| 125 |
+
|
| 126 |
+
When snap_to_grid=True (default):
|
| 127 |
+
- The impulse is placed exactly on the nearest grid node.
|
| 128 |
+
- Peak amplitude = 1.0 (exact delta function on the discrete grid).
|
| 129 |
+
- This is recommended for visualization and accurate peak value display.
|
| 130 |
+
|
| 131 |
+
When snap_to_grid=False:
|
| 132 |
+
- Uses bilinear interpolation to distribute amplitude to the 4 neighboring nodes.
|
| 133 |
+
- Peak amplitude depends on position (e.g., 0.5 when exactly between 4 nodes).
|
| 134 |
+
- Total energy is preserved (L2 norm = 1).
|
| 135 |
|
| 136 |
The preview uses create_impulse_preview_state(), which renders a smooth bump on a
|
| 137 |
fixed unit-square grid independent of nx for visualization.
|
|
|
|
| 143 |
|
| 144 |
gx = px * (grid_width - 1)
|
| 145 |
gy = py * (grid_height - 1)
|
| 146 |
+
|
| 147 |
+
grid_size = grid_width * grid_height
|
| 148 |
+
total_size = 4 * grid_size
|
| 149 |
+
|
| 150 |
+
if snap_to_grid:
|
| 151 |
+
# Snap to nearest grid node for exact delta with peak = 1.0
|
| 152 |
+
i0 = int(round(gx))
|
| 153 |
+
j0 = int(round(gy))
|
| 154 |
+
i0 = max(0, min(i0, grid_width - 1))
|
| 155 |
+
j0 = max(0, min(j0, grid_height - 1))
|
| 156 |
+
|
| 157 |
+
field = np.zeros(grid_size)
|
| 158 |
+
field[j0 * grid_width + i0] = 1.0 # Peak value = 1.0
|
| 159 |
+
|
| 160 |
+
initial_state = np.zeros(total_size)
|
| 161 |
+
initial_state[:grid_size] = field
|
| 162 |
+
return initial_state
|
| 163 |
+
|
| 164 |
+
# Bilinear interpolation mode (snap_to_grid=False)
|
| 165 |
i0, j0 = int(np.floor(gx)), int(np.floor(gy))
|
| 166 |
i1, j1 = min(i0 + 1, grid_width - 1), min(j0 + 1, grid_height - 1)
|
| 167 |
dx, dy = gx - i0, gy - j0
|
|
|
|
| 171 |
w01 = (1 - dx) * dy
|
| 172 |
w11 = dx * dy
|
| 173 |
|
|
|
|
|
|
|
| 174 |
field = np.zeros(grid_size)
|
| 175 |
field[j0 * grid_width + i0] += w00
|
| 176 |
field[j0 * grid_width + i1] += w10
|
|
|
|
| 183 |
return initial_state
|
| 184 |
|
| 185 |
|
| 186 |
+
def create_gaussian_state_from_pos(grid_dims, mu01, sigma01, snap_to_grid=True):
|
| 187 |
"""
|
| 188 |
Create a Gaussian initial state with center mu01=(x,y) and spreads sigma01=(sx,sy)
|
| 189 |
in [0,1] of the domain, then discretize to the solver grid given by grid_dims.
|
| 190 |
|
| 191 |
+
Args:
|
| 192 |
+
grid_dims: Tuple (nx, ny) defining the simulation grid dimensions.
|
| 193 |
+
mu01: Tuple (x, y) with Gaussian center in [0, 1].
|
| 194 |
+
sigma01: Tuple (sx, sy) with Gaussian std dev as fraction of domain in [0, 1].
|
| 195 |
+
snap_to_grid: If True (default), snap the Gaussian center to the nearest grid
|
| 196 |
+
node before discretization. This makes the simulator behavior consistent
|
| 197 |
+
with the "nearest-node" semantics often used elsewhere in the app.
|
| 198 |
+
|
| 199 |
Why grid_dims?
|
| 200 |
- The quantum solver expects a vector aligned to the chosen nx×ny simulation grid.
|
| 201 |
We convert normalized μ and σ (fractions of the domain) into grid units using
|
|
|
|
| 217 |
|
| 218 |
mu_x = mu_x01 * (grid_width - 1)
|
| 219 |
mu_y = mu_y01 * (grid_height - 1)
|
| 220 |
+
if snap_to_grid:
|
| 221 |
+
mu_x = float(int(round(mu_x)))
|
| 222 |
+
mu_y = float(int(round(mu_y)))
|
| 223 |
+
mu_x = float(max(0, min(int(mu_x), grid_width - 1)))
|
| 224 |
+
mu_y = float(max(0, min(int(mu_y), grid_height - 1)))
|
| 225 |
sigma_x = sig_x01 * (grid_width - 1)
|
| 226 |
sigma_y = sig_y01 * (grid_height - 1)
|
| 227 |
|