harishaseebat92 commited on
Commit
b112afa
·
1 Parent(s): f4fc516

QLBM :IBM Jobs and Removed JSON file

Browse files
Files changed (2) hide show
  1. qlbm_embedded.py +237 -137
  2. requirements.txt +0 -0
qlbm_embedded.py CHANGED
@@ -313,18 +313,16 @@ def init_state():
313
  "qlbm_qiskit_backend_available": _QISKIT_BACKEND_AVAILABLE,
314
  "qlbm_qiskit_fig": None, # Stores the Plotly figure for Qiskit results
315
 
316
- # Job upload state (for loading previously saved QPU job results)
317
- "qlbm_job_upload": None, # File upload content (optional, for extracting job ID from filename)
318
- "qlbm_job_upload_filename": "", # Display the uploaded filename
319
- "qlbm_job_upload_error": "", # Error message for upload
320
- "qlbm_job_upload_success": "", # Success message for upload
321
- "qlbm_job_platform": "IonQ", # Platform: IonQ only now
322
  "qlbm_job_id": "", # Job ID text field for direct entry
323
  "qlbm_job_total_time": 3, # Total time T (generates T_list = [1..T])
324
  "qlbm_job_output_resolution": 40, # Grid resolution for density estimation
325
- "qlbm_job_is_processing": False, # True when processing uploaded job
326
  "qlbm_job_flag_qubits": True, # Whether flag qubits were used
327
- "qlbm_job_midcircuit_meas": False, # IonQ uses midcircuit_meas=False
328
  })
329
  _initialized = True
330
 
@@ -1200,12 +1198,12 @@ def _run_qiskit_simulation(progress_callback=None):
1200
  # --- Job Result Upload Processing ---
1201
  def process_uploaded_job_result():
1202
  """
1203
- Process an IonQ job by retrieving it directly using the Job ID.
1204
 
1205
  This function:
1206
  1. Takes the Job ID from user input (or extracts from uploaded filename)
1207
- 2. Connects to IonQ and retrieves the job
1208
- 3. Calls job.get_counts(i) for each timestep (same as run_sampling_hw_ionq)
1209
  4. Calls load_samples/estimate_density for each timestep
1210
  5. Generates the slider figure using plot_density_isosurface_slider
1211
  """
@@ -1220,41 +1218,28 @@ def process_uploaded_job_result():
1220
  log_to_console("Error: visualize_counts module not available")
1221
  return
1222
 
1223
- # Get job ID - either from text field or from uploaded filename
1224
  job_id = None
1225
 
1226
- # First try the text field
1227
  if _state.qlbm_job_id and str(_state.qlbm_job_id).strip():
1228
  job_id = str(_state.qlbm_job_id).strip()
1229
  # Remove .json extension if present
1230
  if job_id.endswith(".json"):
1231
  job_id = job_id[:-5]
1232
  log_to_console(f"Using Job ID from text field: {job_id}")
1233
- else:
1234
- # Fallback: try to get from uploaded file name
1235
- uploaded = _state.qlbm_job_upload
1236
- if uploaded:
1237
- file_data = uploaded[0] if isinstance(uploaded, list) else uploaded
1238
- filename = file_data.get("name", "") if isinstance(file_data, dict) else ""
1239
- if filename:
1240
- # Extract job ID from filename (remove .json and any extra text)
1241
- job_id = filename.replace(".json", "").strip()
1242
- # Handle filenames like "019b368e-6e22-7525-8512-fd16e0503673 (1).json"
1243
- # Remove any trailing parenthetical like " (1)"
1244
- import re
1245
- job_id = re.sub(r'\s*\(\d+\)\s*$', '', job_id)
1246
- log_to_console(f"Extracted Job ID from filename: {job_id}")
1247
 
1248
  if not job_id:
1249
- _state.qlbm_job_upload_error = "No Job ID provided. Please enter a Job ID or upload a JSON file."
1250
  return
1251
 
 
 
 
1252
  # Reset messages
1253
  _state.qlbm_job_upload_error = ""
1254
  _state.qlbm_job_upload_success = ""
1255
  _state.qlbm_job_is_processing = True
1256
- _state.qlbm_job_upload_filename = job_id
1257
- log_to_console(f"Processing IonQ Job ID: {job_id}")
1258
 
1259
  try:
1260
  # Parse timesteps from user input
@@ -1272,102 +1257,219 @@ def process_uploaded_job_result():
1272
 
1273
  # Get processing parameters
1274
  output_resolution = int(_state.qlbm_job_output_resolution or 40)
1275
- # Fixed parameters for IonQ (same as run_sampling_hw_ionq)
1276
- flag_qubits = True
1277
- midcircuit_meas = False # IonQ uses midcircuit_meas=False
1278
-
1279
- log_to_console(f"Resolution: {output_resolution}, Flag qubits: {flag_qubits}, Midcircuit meas: {midcircuit_meas}")
1280
-
1281
- # === Connect to IonQ and retrieve the job ===
1282
- log_to_console("Connecting to IonQ...")
1283
-
1284
- try:
1285
- from qiskit_ionq import IonQProvider
1286
- except ImportError:
1287
- _state.qlbm_job_upload_error = "qiskit_ionq package not available. Please install it."
1288
- _state.qlbm_job_is_processing = False
1289
- log_to_console("Error: qiskit_ionq not installed")
1290
- return
1291
-
1292
- # Get API token from environment (same pattern as run_sampling_hw_ionq)
1293
- ionq_token = os.environ.get("API_KEY_IONQ_QLBM") or os.environ.get("IONQ_API_TOKEN")
1294
- if not ionq_token:
1295
- _state.qlbm_job_upload_error = "IonQ API token not found. Set API_KEY_IONQ_QLBM environment variable."
1296
- _state.qlbm_job_is_processing = False
1297
- log_to_console("Error: IonQ API token not found in environment")
1298
- return
1299
 
1300
- # Set the IONQ_API_TOKEN env var so IonQProvider() can find it (same as run_sampling_hw_ionq)
1301
- os.environ.setdefault("IONQ_API_TOKEN", ionq_token)
 
 
 
 
 
1302
 
1303
- # Set up the IonQ provider and backend (IonQProvider reads from IONQ_API_TOKEN env var)
1304
- provider = IonQProvider()
1305
- backend = provider.get_backend("qpu.forte-enterprise-1")
1306
- backend_name = backend.name if isinstance(backend.name, str) else backend.name()
1307
- log_to_console(f"Connected to IonQ backend: {backend_name}")
1308
 
1309
- # Retrieve the job
1310
- log_to_console(f"Retrieving job: {job_id}")
1311
- try:
1312
- job = backend.retrieve_job(job_id)
1313
- except Exception as e:
1314
- _state.qlbm_job_upload_error = f"Failed to retrieve job: {e}"
1315
- _state.qlbm_job_is_processing = False
1316
- log_to_console(f"Error retrieving job: {e}")
1317
- return
1318
 
1319
- # Check job status
1320
- try:
1321
- status = job.status()
1322
- status_name = status.name if hasattr(status, 'name') else str(status)
1323
- log_to_console(f"Job status: {status_name}")
1324
 
1325
- if status_name not in ('DONE', 'COMPLETED'):
1326
- _state.qlbm_job_upload_error = f"Job is not complete. Current status: {status_name}"
 
 
1327
  _state.qlbm_job_is_processing = False
 
1328
  return
1329
- except Exception as e:
1330
- log_to_console(f"Warning: Could not check job status: {e}")
1331
-
1332
- # === Process results (same as run_sampling_hw_ionq) ===
1333
- log_to_console("Processing job results...")
1334
- output = []
1335
-
1336
- for i, T_total in enumerate(T_list):
 
 
1337
  try:
1338
- log_to_console(f"Processing timestep T={T_total} (circuit {i})...")
1339
-
1340
- # Get counts directly from job (same as run_sampling_hw_ionq)
1341
- counts = job.get_counts(i)
1342
- log_to_console(f" Retrieved {len(counts)} unique bitstrings")
1343
-
1344
- # Debug: show a few sample bitstrings
1345
- sample_count = 0
1346
- for bs, cnt in counts.items():
1347
- if sample_count < 3:
1348
- log_to_console(f" Sample: {bs} (count={cnt})")
1349
- sample_count += 1
1350
-
1351
- # Process samples (same as run_sampling_hw_ionq)
1352
- pts, processed_counts = load_samples(
1353
- counts, T_total,
1354
- logger=log_to_console,
1355
- flag_qubits=flag_qubits,
1356
- midcircuit_meas=midcircuit_meas
1357
  )
1358
- log_to_console(f" load_samples returned {len(pts)} valid sample points")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1359
 
1360
- # Estimate density
1361
- density = estimate_density(pts, processed_counts, bandwidth=0.05, grid_size=output_resolution)
1362
- output.append(density)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1363
 
1364
- except IndexError:
1365
- log_to_console(f"Warning: No data found for timestep T={T_total} (circuit {i})")
1366
- break
 
1367
  except Exception as e:
1368
- log_to_console(f"Error processing timestep {i}: {e}")
1369
- import traceback
1370
- log_to_console(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1371
 
1372
  if not output:
1373
  _state.qlbm_job_upload_error = "No valid data extracted from job. Check timesteps parameter."
@@ -1383,7 +1485,7 @@ def process_uploaded_job_result():
1383
  _state.qlbm_qiskit_mode = True
1384
  _state.qlbm_qiskit_fig = fig
1385
  _state.qlbm_simulation_has_run = True
1386
- _state.qlbm_job_upload_success = f"✓ Successfully processed {len(output)} timestep(s) from job {job_id}"
1387
 
1388
  # Update the Plotly figure widget
1389
  if hasattr(_ctrl, "qlbm_qiskit_result_update"):
@@ -2393,16 +2495,32 @@ def _build_control_panels(plotter):
2393
 
2394
  # --- Job Result Upload Section ---
2395
  vuetify3.VDivider(classes="my-3")
2396
- html.Div("Retrieve IonQ Job Results", classes="text-subtitle-2 font-weight-bold text-primary mb-2")
2397
- html.Div("Enter the Job ID to retrieve results directly from IonQ",
2398
  classes="text-caption text-medium-emphasis mb-2")
2399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2400
  # Job ID input
2401
  with vuetify3.VTooltip(location="top"):
2402
  with vuetify3.Template(v_slot_activator="{ props }"):
2403
  vuetify3.VTextField(
2404
  v_bind="props",
2405
- label="IonQ Job ID",
2406
  v_model=("qlbm_job_id", ""),
2407
  density="compact",
2408
  hide_details=True,
@@ -2411,7 +2529,7 @@ def _build_control_panels(plotter):
2411
  placeholder="e.g., 019b368e-6e22-7525-8512-fd16e0503673",
2412
  prepend_icon="mdi-identifier",
2413
  )
2414
- html.Span("Enter the IonQ Job ID (UUID format)")
2415
 
2416
  # Output resolution and Total Time in a row
2417
  with vuetify3.VRow(dense=True, classes="mb-2"):
@@ -2455,24 +2573,6 @@ def _build_control_panels(plotter):
2455
  classes="mb-2",
2456
  )
2457
 
2458
- # Or use file upload (fallback)
2459
- with vuetify3.VExpansionPanels(variant="accordion", classes="mt-2"):
2460
- with vuetify3.VExpansionPanel():
2461
- vuetify3.VExpansionPanelTitle(children=["Or extract Job ID from JSON filename"])
2462
- with vuetify3.VExpansionPanelText():
2463
- vuetify3.VFileInput(
2464
- label="Upload JSON (for Job ID extraction)",
2465
- v_model=("qlbm_job_upload", None),
2466
- accept=".json",
2467
- prepend_icon="mdi-file-upload",
2468
- density="compact",
2469
- hide_details=True,
2470
- color="primary",
2471
- show_size=True,
2472
- clearable=True,
2473
- hint="The Job ID will be extracted from the filename",
2474
- )
2475
-
2476
  # Success message
2477
  vuetify3.VAlert(
2478
  v_if="qlbm_job_upload_success",
 
313
  "qlbm_qiskit_backend_available": _QISKIT_BACKEND_AVAILABLE,
314
  "qlbm_qiskit_fig": None, # Stores the Plotly figure for Qiskit results
315
 
316
+ # Job retrieval state (for loading previously saved QPU job results)
317
+ "qlbm_job_upload_error": "", # Error message for retrieval
318
+ "qlbm_job_upload_success": "", # Success message for retrieval
319
+ "qlbm_job_platform": "IonQ", # Platform: IonQ or IBM
 
 
320
  "qlbm_job_id": "", # Job ID text field for direct entry
321
  "qlbm_job_total_time": 3, # Total time T (generates T_list = [1..T])
322
  "qlbm_job_output_resolution": 40, # Grid resolution for density estimation
323
+ "qlbm_job_is_processing": False, # True when processing job
324
  "qlbm_job_flag_qubits": True, # Whether flag qubits were used
325
+ "qlbm_job_midcircuit_meas": False, # IonQ uses False, IBM uses True
326
  })
327
  _initialized = True
328
 
 
1198
  # --- Job Result Upload Processing ---
1199
  def process_uploaded_job_result():
1200
  """
1201
+ Process an IBM or IonQ job by retrieving it directly using the Job ID.
1202
 
1203
  This function:
1204
  1. Takes the Job ID from user input (or extracts from uploaded filename)
1205
+ 2. Connects to IBM/IonQ based on platform selection and retrieves the job
1206
+ 3. Processes the job results (IBM: job.result(), IonQ: job.get_counts(i))
1207
  4. Calls load_samples/estimate_density for each timestep
1208
  5. Generates the slider figure using plot_density_isosurface_slider
1209
  """
 
1218
  log_to_console("Error: visualize_counts module not available")
1219
  return
1220
 
1221
+ # Get job ID from text field
1222
  job_id = None
1223
 
 
1224
  if _state.qlbm_job_id and str(_state.qlbm_job_id).strip():
1225
  job_id = str(_state.qlbm_job_id).strip()
1226
  # Remove .json extension if present
1227
  if job_id.endswith(".json"):
1228
  job_id = job_id[:-5]
1229
  log_to_console(f"Using Job ID from text field: {job_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1230
 
1231
  if not job_id:
1232
+ _state.qlbm_job_upload_error = "No Job ID provided. Please enter a Job ID."
1233
  return
1234
 
1235
+ # Get platform selection
1236
+ platform = _state.qlbm_job_platform or "IonQ"
1237
+
1238
  # Reset messages
1239
  _state.qlbm_job_upload_error = ""
1240
  _state.qlbm_job_upload_success = ""
1241
  _state.qlbm_job_is_processing = True
1242
+ log_to_console(f"Processing {platform} Job ID: {job_id}")
 
1243
 
1244
  try:
1245
  # Parse timesteps from user input
 
1257
 
1258
  # Get processing parameters
1259
  output_resolution = int(_state.qlbm_job_output_resolution or 40)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1260
 
1261
+ # Platform-specific parameters
1262
+ if platform == "IBM":
1263
+ flag_qubits = True
1264
+ midcircuit_meas = True # IBM uses midcircuit_meas=True
1265
+ else: # IonQ
1266
+ flag_qubits = True
1267
+ midcircuit_meas = False # IonQ uses midcircuit_meas=False
1268
 
1269
+ log_to_console(f"Platform: {platform}, Resolution: {output_resolution}, Flag qubits: {flag_qubits}, Midcircuit meas: {midcircuit_meas}")
 
 
 
 
1270
 
1271
+ output = []
 
 
 
 
 
 
 
 
1272
 
1273
+ if platform == "IBM":
1274
+ # === IBM Job Retrieval ===
1275
+ log_to_console("Connecting to IBM Quantum...")
 
 
1276
 
1277
+ try:
1278
+ from qiskit_ibm_runtime import QiskitRuntimeService
1279
+ except ImportError:
1280
+ _state.qlbm_job_upload_error = "qiskit_ibm_runtime package not available. Please install it."
1281
  _state.qlbm_job_is_processing = False
1282
+ log_to_console("Error: qiskit_ibm_runtime not installed")
1283
  return
1284
+
1285
+ # Get API token from environment
1286
+ ibm_token = os.environ.get("API_KEY_IBM_QLBM")
1287
+ if not ibm_token:
1288
+ _state.qlbm_job_upload_error = "IBM API token not found. Set API_KEY_IBM_QLBM environment variable."
1289
+ _state.qlbm_job_is_processing = False
1290
+ log_to_console("Error: IBM API token not found in environment")
1291
+ return
1292
+
1293
+ # Set up IBM service (same as run_sampling_hw_ibm)
1294
  try:
1295
+ service = QiskitRuntimeService(
1296
+ channel="ibm_cloud",
1297
+ token=ibm_token,
1298
+ instance="crn:v1:bluemix:public:quantum-computing:us-east:a/15157e4350c04a9dab51b8b8a4a93c86:e29afd91-64bf-4a82-8dbf-731e6c213595::",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1299
  )
1300
+ log_to_console("Connected to IBM Quantum service")
1301
+ except Exception as e:
1302
+ _state.qlbm_job_upload_error = f"Failed to connect to IBM Quantum: {e}"
1303
+ _state.qlbm_job_is_processing = False
1304
+ log_to_console(f"Error connecting to IBM: {e}")
1305
+ return
1306
+
1307
+ # Retrieve the job
1308
+ log_to_console(f"Retrieving IBM job: {job_id}")
1309
+ try:
1310
+ job = service.job(job_id)
1311
+ except Exception as e:
1312
+ _state.qlbm_job_upload_error = f"Failed to retrieve IBM job: {e}"
1313
+ _state.qlbm_job_is_processing = False
1314
+ log_to_console(f"Error retrieving job: {e}")
1315
+ return
1316
+
1317
+ # Check job status
1318
+ try:
1319
+ status = job.status()
1320
+ status_name = status.name if hasattr(status, 'name') else str(status)
1321
+ log_to_console(f"Job status: {status_name}")
1322
 
1323
+ if status_name not in ('DONE', 'COMPLETED'):
1324
+ _state.qlbm_job_upload_error = f"Job is not complete. Current status: {status_name}"
1325
+ _state.qlbm_job_is_processing = False
1326
+ return
1327
+ except Exception as e:
1328
+ log_to_console(f"Warning: Could not check job status: {e}")
1329
+
1330
+ # Get results (same as run_sampling_hw_ibm)
1331
+ log_to_console("Retrieving IBM job results...")
1332
+ try:
1333
+ result = job.result()
1334
+ log_to_console("Results retrieved successfully")
1335
+ except Exception as e:
1336
+ _state.qlbm_job_upload_error = f"Failed to get job results: {e}"
1337
+ _state.qlbm_job_is_processing = False
1338
+ log_to_console(f"Error getting results: {e}")
1339
+ return
1340
+
1341
+ # Process results (same pattern as run_sampling_hw_ibm)
1342
+ log_to_console("Processing IBM job results...")
1343
+
1344
+ for idx, (T_total, pub) in enumerate(zip(T_list, result)):
1345
+ try:
1346
+ log_to_console(f"Processing timestep T={T_total} (circuit {idx})...")
1347
+
1348
+ # Get counts (same as run_sampling_hw_ibm)
1349
+ try:
1350
+ joined = pub.join_data()
1351
+ counts = joined.get_counts()
1352
+ except Exception as e:
1353
+ log_to_console(f"Error retrieving counts for T={T_total}: {e}")
1354
+ continue
1355
+
1356
+ log_to_console(f" Retrieved {len(counts)} unique bitstrings")
1357
+
1358
+ # Debug: show a few sample bitstrings
1359
+ sample_count = 0
1360
+ for bs, cnt in counts.items():
1361
+ if sample_count < 3:
1362
+ log_to_console(f" Sample: {bs} (count={cnt})")
1363
+ sample_count += 1
1364
+
1365
+ # Process samples (same as run_sampling_hw_ibm)
1366
+ pts, processed_counts = load_samples(
1367
+ counts, T_total,
1368
+ logger=log_to_console,
1369
+ flag_qubits=flag_qubits,
1370
+ midcircuit_meas=midcircuit_meas
1371
+ )
1372
+ log_to_console(f" load_samples returned {len(pts)} valid sample points")
1373
+
1374
+ # Estimate density
1375
+ density = estimate_density(pts, processed_counts, bandwidth=0.05, grid_size=output_resolution)
1376
+ output.append(density)
1377
+
1378
+ except Exception as e:
1379
+ log_to_console(f"Error processing timestep {idx}: {e}")
1380
+ import traceback
1381
+ log_to_console(traceback.format_exc())
1382
+
1383
+ else:
1384
+ # === IonQ Job Retrieval ===
1385
+ log_to_console("Connecting to IonQ...")
1386
+
1387
+ try:
1388
+ from qiskit_ionq import IonQProvider
1389
+ except ImportError:
1390
+ _state.qlbm_job_upload_error = "qiskit_ionq package not available. Please install it."
1391
+ _state.qlbm_job_is_processing = False
1392
+ log_to_console("Error: qiskit_ionq not installed")
1393
+ return
1394
+
1395
+ # Get API token from environment (same pattern as run_sampling_hw_ionq)
1396
+ ionq_token = os.environ.get("API_KEY_IONQ_QLBM") or os.environ.get("IONQ_API_TOKEN")
1397
+ if not ionq_token:
1398
+ _state.qlbm_job_upload_error = "IonQ API token not found. Set API_KEY_IONQ_QLBM environment variable."
1399
+ _state.qlbm_job_is_processing = False
1400
+ log_to_console("Error: IonQ API token not found in environment")
1401
+ return
1402
+
1403
+ # Set the IONQ_API_TOKEN env var so IonQProvider() can find it (same as run_sampling_hw_ionq)
1404
+ os.environ.setdefault("IONQ_API_TOKEN", ionq_token)
1405
+
1406
+ # Set up the IonQ provider and backend (IonQProvider reads from IONQ_API_TOKEN env var)
1407
+ provider = IonQProvider()
1408
+ backend = provider.get_backend("qpu.forte-enterprise-1")
1409
+ backend_name = backend.name if isinstance(backend.name, str) else backend.name()
1410
+ log_to_console(f"Connected to IonQ backend: {backend_name}")
1411
+
1412
+ # Retrieve the job
1413
+ log_to_console(f"Retrieving IonQ job: {job_id}")
1414
+ try:
1415
+ job = backend.retrieve_job(job_id)
1416
+ except Exception as e:
1417
+ _state.qlbm_job_upload_error = f"Failed to retrieve IonQ job: {e}"
1418
+ _state.qlbm_job_is_processing = False
1419
+ log_to_console(f"Error retrieving job: {e}")
1420
+ return
1421
+
1422
+ # Check job status
1423
+ try:
1424
+ status = job.status()
1425
+ status_name = status.name if hasattr(status, 'name') else str(status)
1426
+ log_to_console(f"Job status: {status_name}")
1427
 
1428
+ if status_name not in ('DONE', 'COMPLETED'):
1429
+ _state.qlbm_job_upload_error = f"Job is not complete. Current status: {status_name}"
1430
+ _state.qlbm_job_is_processing = False
1431
+ return
1432
  except Exception as e:
1433
+ log_to_console(f"Warning: Could not check job status: {e}")
1434
+
1435
+ # Process results (same as run_sampling_hw_ionq)
1436
+ log_to_console("Processing IonQ job results...")
1437
+
1438
+ for i, T_total in enumerate(T_list):
1439
+ try:
1440
+ log_to_console(f"Processing timestep T={T_total} (circuit {i})...")
1441
+
1442
+ # Get counts directly from job (same as run_sampling_hw_ionq)
1443
+ counts = job.get_counts(i)
1444
+ log_to_console(f" Retrieved {len(counts)} unique bitstrings")
1445
+
1446
+ # Debug: show a few sample bitstrings
1447
+ sample_count = 0
1448
+ for bs, cnt in counts.items():
1449
+ if sample_count < 3:
1450
+ log_to_console(f" Sample: {bs} (count={cnt})")
1451
+ sample_count += 1
1452
+
1453
+ # Process samples (same as run_sampling_hw_ionq)
1454
+ pts, processed_counts = load_samples(
1455
+ counts, T_total,
1456
+ logger=log_to_console,
1457
+ flag_qubits=flag_qubits,
1458
+ midcircuit_meas=midcircuit_meas
1459
+ )
1460
+ log_to_console(f" load_samples returned {len(pts)} valid sample points")
1461
+
1462
+ # Estimate density
1463
+ density = estimate_density(pts, processed_counts, bandwidth=0.05, grid_size=output_resolution)
1464
+ output.append(density)
1465
+
1466
+ except IndexError:
1467
+ log_to_console(f"Warning: No data found for timestep T={T_total} (circuit {i})")
1468
+ break
1469
+ except Exception as e:
1470
+ log_to_console(f"Error processing timestep {i}: {e}")
1471
+ import traceback
1472
+ log_to_console(traceback.format_exc())
1473
 
1474
  if not output:
1475
  _state.qlbm_job_upload_error = "No valid data extracted from job. Check timesteps parameter."
 
1485
  _state.qlbm_qiskit_mode = True
1486
  _state.qlbm_qiskit_fig = fig
1487
  _state.qlbm_simulation_has_run = True
1488
+ _state.qlbm_job_upload_success = f"✓ Successfully processed {len(output)} timestep(s) from {platform} job {job_id}"
1489
 
1490
  # Update the Plotly figure widget
1491
  if hasattr(_ctrl, "qlbm_qiskit_result_update"):
 
2495
 
2496
  # --- Job Result Upload Section ---
2497
  vuetify3.VDivider(classes="my-3")
2498
+ html.Div("Upload Results", classes="text-subtitle-2 font-weight-bold text-primary mb-2")
2499
+ html.Div("Retrieve completed job results from IBM or IonQ using the Job ID",
2500
  classes="text-caption text-medium-emphasis mb-2")
2501
 
2502
+ # Platform selector
2503
+ with vuetify3.VTooltip(location="top"):
2504
+ with vuetify3.Template(v_slot_activator="{ props }"):
2505
+ vuetify3.VSelect(
2506
+ v_bind="props",
2507
+ label="Platform",
2508
+ v_model=("qlbm_job_platform", "IonQ"),
2509
+ items=("['IBM', 'IonQ']",),
2510
+ density="compact",
2511
+ hide_details=True,
2512
+ color="primary",
2513
+ classes="mb-2",
2514
+ prepend_icon="mdi-chip",
2515
+ )
2516
+ html.Span("Select the quantum hardware provider (IBM or IonQ)")
2517
+
2518
  # Job ID input
2519
  with vuetify3.VTooltip(location="top"):
2520
  with vuetify3.Template(v_slot_activator="{ props }"):
2521
  vuetify3.VTextField(
2522
  v_bind="props",
2523
+ label="Job ID",
2524
  v_model=("qlbm_job_id", ""),
2525
  density="compact",
2526
  hide_details=True,
 
2529
  placeholder="e.g., 019b368e-6e22-7525-8512-fd16e0503673",
2530
  prepend_icon="mdi-identifier",
2531
  )
2532
+ html.Span("Enter the Job ID (UUID format from IBM or IonQ)")
2533
 
2534
  # Output resolution and Total Time in a row
2535
  with vuetify3.VRow(dense=True, classes="mb-2"):
 
2573
  classes="mb-2",
2574
  )
2575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2576
  # Success message
2577
  vuetify3.VAlert(
2578
  v_if="qlbm_job_upload_success",
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ