harishaseebat92 commited on
Commit
3cd4a37
·
2 Parent(s): b5dbacc 5d45402

EM: IBM QPU Version

Browse files
qlbm/qlbm_sample_app.py CHANGED
@@ -251,7 +251,7 @@ def stream(qc,pos_qr,dir_qr,n):
251
  qc.cp( np.pi / (2 ** m), forw_ctrl, pos_qr[i][m])
252
  qc.cp(-np.pi / (2 ** m), backw_ctrl, pos_qr[i][m])
253
 
254
- def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure=True):
255
 
256
  ux_str,uy_str,uz_str=None,None,None
257
  if type(ux)==str:
@@ -277,17 +277,31 @@ def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure
277
  for T_total in T_list:
278
  pos_qr=[QuantumRegister(n) for _ in range(dim)]
279
  pos_cr=[ClassicalRegister(n) for _ in range(dim)]
280
- dir_qr=QuantumRegister(2*dim)
281
- dir_cr=[ClassicalRegister(2*dim) for _ in range(T_total)]
 
 
 
 
282
 
283
- qc=QuantumCircuit(*pos_qr,dir_qr,*pos_cr,*dir_cr)
 
 
 
 
 
 
 
 
 
284
 
285
  qc.compose(init_state_prep_circ,[qubit for qr in pos_qr for qubit in list(qr)], inplace=True)
286
 
287
  uniform_bool=False
288
 
289
- if 'x' not in ux_str+uy_str+uz_str and 'y' not in ux_str+uy_str+uz_str and 'z' not in ux_str+uy_str+uz_str:
290
- uniform_bool=True
 
291
 
292
  if uniform_bool:
293
  for i in range(dim):
@@ -295,7 +309,14 @@ def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure
295
 
296
  for T in list(range(T_total))[::-1]:
297
 
 
 
 
298
  prep(qc,pos_qr,dir_qr)
 
 
 
 
299
  if not uniform_bool:
300
  for i in range(dim):
301
  qc.compose(QFT(n, inverse=False, do_swaps=False), pos_qr[i], inplace=True)
@@ -303,9 +324,18 @@ def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure
303
  if not uniform_bool:
304
  for i in range(dim):
305
  qc.compose(QFT(n, inverse=True, do_swaps=False), pos_qr[i], inplace=True)
 
 
 
306
  unprep(qc,pos_qr,dir_qr)
307
 
308
- qc.measure(dir_qr,dir_cr[T])
 
 
 
 
 
 
309
 
310
  if uniform_bool:
311
  for i in range(dim):
@@ -314,7 +344,7 @@ def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure
314
  if measure:
315
  for i in range(dim):
316
  qc.measure(pos_qr[i],pos_cr[i])
317
-
318
  qc_list+=[qc]
319
 
320
  return qc_list
@@ -481,6 +511,7 @@ def run_sampling_hw_ibm(
481
  vel_resolution=32,
482
  output_resolution=40,
483
  logger=None,
 
484
  ):
485
  """
486
  Run QLBM simulation on IBM quantum hardware.
@@ -525,7 +556,7 @@ def run_sampling_hw_ibm(
525
  # if type(init_state_prep_circ)==str:
526
  # init_state_prep_circ=get_named_init_state_circuit(n,init_state_prep_circ)
527
 
528
- qc_list=get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution)
529
 
530
  pm_optimization_level = 3
531
 
@@ -545,7 +576,7 @@ def run_sampling_hw_ibm(
545
  # Create Sampler primitive bound to the backend
546
  sampler = Sampler(mode=backend)
547
 
548
- # Submit job: pass a list of PUBs (we send one PUB [qc_compiled])
549
  job = sampler.run(qc_compiled_list, shots=shots)
550
  log("Job submitted; waiting for result...")
551
 
@@ -566,7 +597,7 @@ def run_sampling_hw_ibm(
566
  joined_counts = None
567
 
568
  # Suppress verbose logging by passing None as logger
569
- pts, counts = load_samples(joined_counts, T_total, logger=None)
570
  output+=[estimate_density(pts, counts, bandwidth=0.05, grid_size=output_resolution)]
571
 
572
  log(f"Processing complete: {len(output)} timestep(s)")
@@ -575,6 +606,104 @@ def run_sampling_hw_ibm(
575
 
576
  return job,get_job_result
577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
 
579
  from qiskit_aer import AerSimulator
580
 
@@ -936,52 +1065,47 @@ def show_initial_distribution(
936
 
937
  if __name__=="__main__":
938
 
939
- n=4
940
 
941
- # # Step 1: Create the initial state circuit ONCE with all parameters
942
  # init_state_prep_circ = get_named_init_state_circuit(
943
  # n=n,
944
  # init_state_name="multi_dirac_delta", # or "gaussian", "dirac_delta"
945
- # sine_k_x=1.0,
946
- # sine_k_y=1.0,
947
- # sine_k_z=1.0
948
- # # gauss_cx=0.5, # Uncomment for Gaussian
949
- # # gauss_cy=0.5,
950
- # # gauss_cz=0.5,
951
- # # gauss_sigma=0.2,
952
  # )
953
-
954
- # Alternative: Run on local simulator
955
- output, fig = run_sampling_sim(
956
- n=n,
957
- ux="sin(-2*pi*z)",
958
- uy="1",
959
- uz="sin(2*pi*x)",
960
- init_state_prep_circ="multi_dirac_delta",
961
- T_list=[1,3,5,7,9],
962
- vel_resolution=16
963
- )
964
- print(output)
965
- fig.show(renderer="browser")
 
 
966
 
967
  # Step 2: (Optional) Preview the initial distribution
968
  # show_initial_distribution(n=n, init_state_name="sin", sine_k_x=1, sine_k_y=1, sine_k_z=1)
969
 
970
  # Step 3: Run simulation - pass the pre-built circuit
971
- # job, get_job_result = run_sampling_hw_ibm(
972
- # n=n,
973
- # ux=lambda x,y,z: 1,
974
- # uy=lambda x,y,z: 1,
975
- # uz=lambda x,y,z: 1,
976
- # init_state_prep_circ=init_state_prep_circ, # Pass the circuit directly
977
- # T_list=[1],
978
- # shots=2**19,
979
- # vel_resolution=2,
980
- # )
 
981
 
982
- # output = get_job_result(job)
983
- # for xx, yy, zz, dens in output:
984
- # plot_density_isosurface(xx, yy, zz, dens)
985
 
986
 
987
 
 
251
  qc.cp( np.pi / (2 ** m), forw_ctrl, pos_qr[i][m])
252
  qc.cp(-np.pi / (2 ** m), backw_ctrl, pos_qr[i][m])
253
 
254
+ def get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution=32,measure=True,flag_qubits=False,midcircuit_meas=True):
255
 
256
  ux_str,uy_str,uz_str=None,None,None
257
  if type(ux)==str:
 
277
  for T_total in T_list:
278
  pos_qr=[QuantumRegister(n) for _ in range(dim)]
279
  pos_cr=[ClassicalRegister(n) for _ in range(dim)]
280
+ if midcircuit_meas:
281
+ dir_qr=QuantumRegister(2*dim)
282
+ else:
283
+ dir_qr_list=[QuantumRegister(2*dim) for _ in range(T_total)]
284
+ dir_qr_flag=QuantumRegister(2*dim)
285
+ dir_cr=[ClassicalRegister((4 if flag_qubits and midcircuit_meas else 2)*dim) for _ in range(T_total+int(flag_qubits and not midcircuit_meas))]
286
 
287
+ if flag_qubits:
288
+ if midcircuit_meas:
289
+ qc=QuantumCircuit(*pos_qr,dir_qr,dir_qr_flag,*pos_cr,*dir_cr)
290
+ else:
291
+ qc=QuantumCircuit(*pos_qr,*dir_qr_list,dir_qr_flag,*pos_cr,*dir_cr)
292
+ else:
293
+ if midcircuit_meas:
294
+ qc=QuantumCircuit(*pos_qr,dir_qr,*pos_cr,*dir_cr)
295
+ else:
296
+ qc=QuantumCircuit(*pos_qr,*dir_qr_list,*pos_cr,*dir_cr)
297
 
298
  qc.compose(init_state_prep_circ,[qubit for qr in pos_qr for qubit in list(qr)], inplace=True)
299
 
300
  uniform_bool=False
301
 
302
+ if ux_str is not None:
303
+ if 'x' not in ux_str+uy_str+uz_str and 'y' not in ux_str+uy_str+uz_str and 'z' not in ux_str+uy_str+uz_str:
304
+ uniform_bool=True
305
 
306
  if uniform_bool:
307
  for i in range(dim):
 
309
 
310
  for T in list(range(T_total))[::-1]:
311
 
312
+ if not midcircuit_meas:
313
+ dir_qr=dir_qr_list[T]
314
+
315
  prep(qc,pos_qr,dir_qr)
316
+
317
+ if flag_qubits:
318
+ for q1,q2 in zip(dir_qr,dir_qr_flag):
319
+ qc.cx(q1,q2)
320
  if not uniform_bool:
321
  for i in range(dim):
322
  qc.compose(QFT(n, inverse=False, do_swaps=False), pos_qr[i], inplace=True)
 
324
  if not uniform_bool:
325
  for i in range(dim):
326
  qc.compose(QFT(n, inverse=True, do_swaps=False), pos_qr[i], inplace=True)
327
+ if flag_qubits:
328
+ for q1,q2 in zip(dir_qr,dir_qr_flag):
329
+ qc.cx(q1,q2)
330
  unprep(qc,pos_qr,dir_qr)
331
 
332
+ if flag_qubits and midcircuit_meas:
333
+ qc.measure(list(dir_qr)+list(dir_qr_flag),dir_cr[T])
334
+ else:
335
+ qc.measure(dir_qr,dir_cr[T])
336
+
337
+ if not midcircuit_meas and flag_qubits:
338
+ qc.measure(dir_qr_flag,dir_cr[T_total])
339
 
340
  if uniform_bool:
341
  for i in range(dim):
 
344
  if measure:
345
  for i in range(dim):
346
  qc.measure(pos_qr[i],pos_cr[i])
347
+
348
  qc_list+=[qc]
349
 
350
  return qc_list
 
511
  vel_resolution=32,
512
  output_resolution=40,
513
  logger=None,
514
+ flag_qubits=True
515
  ):
516
  """
517
  Run QLBM simulation on IBM quantum hardware.
 
556
  # if type(init_state_prep_circ)==str:
557
  # init_state_prep_circ=get_named_init_state_circuit(n,init_state_prep_circ)
558
 
559
+ qc_list=get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution,flag_qubits=flag_qubits)
560
 
561
  pm_optimization_level = 3
562
 
 
576
  # Create Sampler primitive bound to the backend
577
  sampler = Sampler(mode=backend)
578
 
579
+ # # Submit job: pass a list of PUBs (we send one PUB [qc_compiled])
580
  job = sampler.run(qc_compiled_list, shots=shots)
581
  log("Job submitted; waiting for result...")
582
 
 
597
  joined_counts = None
598
 
599
  # Suppress verbose logging by passing None as logger
600
+ pts, counts = load_samples(joined_counts, T_total, logger=None, flag_qubits=flag_qubits)
601
  output+=[estimate_density(pts, counts, bandwidth=0.05, grid_size=output_resolution)]
602
 
603
  log(f"Processing complete: {len(output)} timestep(s)")
 
606
 
607
  return job,get_job_result
608
 
609
+ from qiskit_ionq import IonQProvider
610
+
611
+ provider = IonQProvider("slZCfQN3gptIiuswZ3TULhRu37kOhrlW")
612
+
613
+ def run_sampling_hw_ionq(
614
+ n,
615
+ ux,
616
+ uy,
617
+ uz,
618
+ init_state_prep_circ,
619
+ T_list,
620
+ shots=2**19,
621
+ vel_resolution=32,
622
+ output_resolution=40,
623
+ logger=None,
624
+ flag_qubits=True
625
+ ):
626
+ """
627
+ Run QLBM simulation on IonQ quantum hardware.
628
+
629
+ Parameters
630
+ ----------
631
+ n : int
632
+ Number of qubits per spatial dimension
633
+ ux, uy, uz : callable or str
634
+ Velocity field components
635
+ init_state_prep_circ : QuantumCircuit
636
+ Pre-built initial state preparation circuit from get_named_init_state_circuit()
637
+ T_list : list[int]
638
+ List of timesteps to simulate
639
+ shots : int
640
+ Number of measurement shots (default: 2^19)
641
+ vel_resolution : int
642
+ Resolution for velocity field discretization
643
+ output_resolution : int
644
+ Grid resolution for density estimation output
645
+ logger : callable, optional
646
+ Function to log messages (e.g. print to console)
647
+
648
+ Returns
649
+ -------
650
+ job : IonQ Job
651
+ The submitted job object
652
+ get_job_result : callable
653
+ Callback function to retrieve and process results. Returns (output, fig).
654
+ """
655
+
656
+ def log(msg):
657
+ if logger:
658
+ logger(str(msg))
659
+ else:
660
+ print(msg)
661
+
662
+ # if type(ux)==str:
663
+ # ux,uy,uz=str_to_lambda(ux,uy,uz)
664
+
665
+ # # Convert string init_state_prep_circ to circuit if needed (matches original logic)
666
+ # if type(init_state_prep_circ)==str:
667
+ # init_state_prep_circ=get_named_init_state_circuit(n,init_state_prep_circ)
668
+
669
+ # backend = provider.get_backend("simulator")
670
+ backend = provider.get_backend("qpu.forte-enterprise-1")
671
+
672
+ qc_list=get_circuit(n,ux,uy,uz,init_state_prep_circ,T_list,vel_resolution,flag_qubits=flag_qubits,midcircuit_meas=False)
673
+
674
+ # Create Sampler primitive bound to the backend
675
+
676
+ job = backend.run(qc_list, shots=shots)
677
+
678
+ # job = backend.retrieve_job("019b0aec-36d7-749a-89f2-c36382b3aa1c")
679
+
680
+ # sampler = Sampler(mode=backend)
681
+
682
+ # # Submit job: pass a list of PUBs (we send one PUB [qc_compiled])
683
+ # job = sampler.run(qc_compiled_list, shots=shots)
684
+ log("Job submitted; waiting for result...")
685
+
686
+ def get_job_result(j):
687
+
688
+ log("Waiting for job results (this may take time)...")
689
+
690
+ output=[]
691
+
692
+ for i,T_total in enumerate(T_list):
693
+
694
+ counts = j.get_counts(i)
695
+
696
+ # Suppress verbose logging by passing None as logger
697
+ pts, counts = load_samples(counts, T_total, logger=None, flag_qubits=flag_qubits, midcircuit_meas=False)
698
+ output+=[estimate_density(pts, counts, bandwidth=0.05, grid_size=output_resolution)]
699
+
700
+ log(f"Processing complete: {len(output)} timestep(s)")
701
+ fig = plot_density_isosurface_slider(output, T_list)
702
+ return output, fig
703
+
704
+ return job,get_job_result
705
+
706
+
707
 
708
  from qiskit_aer import AerSimulator
709
 
 
1065
 
1066
  if __name__=="__main__":
1067
 
1068
+ n=3
1069
 
1070
+ # Step 1: Create the initial state circuit ONCE with all parameters
1071
  # init_state_prep_circ = get_named_init_state_circuit(
1072
  # n=n,
1073
  # init_state_name="multi_dirac_delta", # or "gaussian", "dirac_delta"
 
 
 
 
 
 
 
1074
  # )
1075
+
1076
+ # # Alternative: Run on local simulator
1077
+ # output, fig = run_sampling_sim(
1078
+ # n=n,
1079
+ # ux="sin(-2*pi*z)",
1080
+ # uy="1",
1081
+ # uz="sin(2*pi*x)",
1082
+ # init_state_prep_circ="multi_dirac_delta",
1083
+ # T_list=[1,3,5,7,9],
1084
+ # vel_resolution=16
1085
+ # )
1086
+
1087
+ # print(output)
1088
+
1089
+ # fig.show(renderer="browser")
1090
 
1091
  # Step 2: (Optional) Preview the initial distribution
1092
  # show_initial_distribution(n=n, init_state_name="sin", sine_k_x=1, sine_k_y=1, sine_k_z=1)
1093
 
1094
  # Step 3: Run simulation - pass the pre-built circuit
1095
+ job, get_job_result = run_sampling_hw_ionq(
1096
+ n=n,
1097
+ ux="1",
1098
+ uy="1",
1099
+ uz="1",
1100
+ init_state_prep_circ="multi_dirac_delta", # Pass the circuit directly
1101
+ T_list=[1,2],
1102
+ shots=2**15,
1103
+ vel_resolution=2,
1104
+ output_resolution=16
1105
+ )
1106
 
1107
+ output,fig = get_job_result(job)
1108
+ fig.show(renderer="browser")
 
1109
 
1110
 
1111
 
qlbm/visualize_counts.py CHANGED
@@ -22,7 +22,7 @@ def bitstring_to_xyz(bs):
22
  maxv = (1 << t)
23
  return ix / maxv, iy / maxv, iz / maxv
24
 
25
- def load_samples(d, T_total, logger=None):
26
  """
27
  Load samples from measurement counts dictionary.
28
 
@@ -50,27 +50,37 @@ def load_samples(d, T_total, logger=None):
50
 
51
  pts = []
52
  counts = []
 
 
 
 
 
 
 
 
 
53
 
54
  if d is None or len(d) == 0:
55
- log("Warning: Empty counts dictionary")
56
- return np.array(pts), np.array(counts)
57
 
58
  # Debug: show sample bitstrings
59
  sample_keys = list(d.keys())[:3]
60
  log(f"Sample bitstrings (first 3): {sample_keys}")
61
  if sample_keys:
62
- log(f"Bitstring length: {len(sample_keys[0])}")
63
- log(f"Expected prefix length (6*T_total): {6*T_total}")
64
 
65
  for bs, cnt in d.items():
66
  # Check if the direction qubits (first 6*T_total bits) are all zeros
67
- prefix = bs[:6*T_total]
68
- expected_prefix = "0" * 6*T_total
 
69
 
70
  if prefix == expected_prefix:
71
  if cnt < 0:
72
  continue
73
- remaining_bits = bs[6*T_total:]
74
  # Check if remaining bits are divisible by 3
75
  if len(remaining_bits) % 3 != 0:
76
  log(f"Warning: Remaining bitstring length {len(remaining_bits)} not divisible by 3")
@@ -146,6 +156,8 @@ def estimate_density(pts, counts, bandwidth=0.05, grid_size=64):
146
  dens = np.exp(logdens)
147
  dens = dens.reshape(xx.shape)
148
 
 
 
149
  print("Mins:", mins)
150
  print("Maxs:", maxs)
151
  print("dens:", dens)
@@ -220,7 +232,7 @@ def plot_density_isosurface_slider(outputs, T_list=None):
220
  isomin=global_min,
221
  isomax=global_max,
222
  opacity=0.4,
223
- surface_count=5,
224
  caps=dict(x_show=False, y_show=False, z_show=False),
225
  colorscale='Blues',
226
  colorbar=dict(title="Density"),
@@ -257,7 +269,7 @@ def plot_density_isosurface_slider(outputs, T_list=None):
257
  ),
258
  sliders=sliders
259
  )
260
-
261
  # fig.show(renderer="browser")
262
  return fig
263
 
 
22
  maxv = (1 << t)
23
  return ix / maxv, iy / maxv, iz / maxv
24
 
25
+ def load_samples(d, T_total, logger=None, flag_qubits=False, midcircuit_meas=True):
26
  """
27
  Load samples from measurement counts dictionary.
28
 
 
50
 
51
  pts = []
52
  counts = []
53
+
54
+ if flag_qubits:
55
+ if midcircuit_meas:
56
+ pref_length=12*T_total
57
+ else:
58
+ pref_length=6*(T_total+1)
59
+ else:
60
+ pref_length=6*T_total
61
+
62
 
63
  if d is None or len(d) == 0:
64
+ log("Warning: Empty counts dictionary")
65
+ return np.array(pts), np.array(counts)
66
 
67
  # Debug: show sample bitstrings
68
  sample_keys = list(d.keys())[:3]
69
  log(f"Sample bitstrings (first 3): {sample_keys}")
70
  if sample_keys:
71
+ log(f"Bitstring length: {len(sample_keys[0])}")
72
+ log(f"Expected prefix length: {pref_length}")
73
 
74
  for bs, cnt in d.items():
75
  # Check if the direction qubits (first 6*T_total bits) are all zeros
76
+ bs=bs.replace(" ","")
77
+ prefix = bs[:pref_length]
78
+ expected_prefix = "0" * pref_length
79
 
80
  if prefix == expected_prefix:
81
  if cnt < 0:
82
  continue
83
+ remaining_bits = bs[pref_length:]
84
  # Check if remaining bits are divisible by 3
85
  if len(remaining_bits) % 3 != 0:
86
  log(f"Warning: Remaining bitstring length {len(remaining_bits)} not divisible by 3")
 
156
  dens = np.exp(logdens)
157
  dens = dens.reshape(xx.shape)
158
 
159
+ dens = (grid_size**3)*dens/np.sum(dens.flatten())
160
+
161
  print("Mins:", mins)
162
  print("Maxs:", maxs)
163
  print("dens:", dens)
 
232
  isomin=global_min,
233
  isomax=global_max,
234
  opacity=0.4,
235
+ surface_count=10,
236
  caps=dict(x_show=False, y_show=False, z_show=False),
237
  colorscale='Blues',
238
  colorbar=dict(title="Density"),
 
269
  ),
270
  sliders=sliders
271
  )
272
+
273
  # fig.show(renderer="browser")
274
  return fig
275
 
qlbm_embedded.py CHANGED
@@ -1189,7 +1189,7 @@ def run_simulation():
1189
  # shots=2**14, # Reduced shots for responsiveness/quota
1190
  shots=2**18,
1191
  vel_resolution=min(params['grid_size'], 32),
1192
- output_resolution=40,
1193
  logger=log_to_console
1194
  )
1195
 
 
1189
  # shots=2**14, # Reduced shots for responsiveness/quota
1190
  shots=2**18,
1191
  vel_resolution=min(params['grid_size'], 32),
1192
+ output_resolution=min(2*params['grid_size'], 40),
1193
  logger=log_to_console
1194
  )
1195