15
15
16
16
import math
17
17
import warnings
18
- from typing import Optional
18
+ from typing import List , Optional
19
19
20
20
import numpy as np
21
21
import uncertainties
26
26
AnalysisResultData ,
27
27
Options ,
28
28
)
29
+ from qiskit_experiments .visualization import BasePlotter , MplDrawer
30
+
31
+
32
+ class QVPlotter (BasePlotter ):
33
+ @classmethod
34
+ def expected_series_data_keys (cls ) -> List [str ]:
35
+ return ["hops" ]
36
+
37
+ @classmethod
38
+ def expected_supplementary_data_keys (cls ) -> List [str ]:
39
+ return ["depth" ]
40
+
41
+ def set_supplementary_data (self , ** data_kwargs ):
42
+ if "depth" in data_kwargs :
43
+ self .set_figure_options (
44
+ figure_title = (
45
+ f"Quantum Volume experiment for depth { data_kwargs ['depth' ]} "
46
+ " - accumulative hop"
47
+ ),
48
+ )
49
+ super ().set_supplementary_data (** data_kwargs )
50
+
51
+ @classmethod
52
+ def _default_figure_options (cls ) -> Options :
53
+ options = super ()._default_figure_options ()
54
+ options .xlabel = "Number of Trials"
55
+ options .ylabel = "Heavy Output Probability"
56
+ options .figure_title = "Quantum Volume experiment - accumulative hop"
57
+ options .series_params = {
58
+ "hop" : {"color" : "gray" , "symbol" : "." },
59
+ "threshold" : {"color" : "black" , "linestyle" : "dashed" , "linewidth" : 1 },
60
+ "hop_cumulative" : {"color" : "r" },
61
+ "hop_twosigma" : {"color" : "lightgray" },
62
+ }
63
+ return options
64
+
65
+ @classmethod
66
+ def _default_options (cls ) -> Options :
67
+ options = super ()._default_options ()
68
+ options .style ["figsize" ] = (6.4 , 4.8 )
69
+ options .style ["axis_label_size" ] = 14
70
+ options .style ["symbol_size" ] = 2
71
+ return options
72
+
73
+ def _plot_figure (self ):
74
+ series = self .series [0 ]
75
+ hops , = self .data_for (series , ["hops" ])
76
+ trials = np .arange (1 , 1 + len (hops ))
77
+ hop_accumulative = np .cumsum (hops ) / trials
78
+ hop_twosigma = 2 * (hop_accumulative * (1 - hop_accumulative ) / trials ) ** 0.5
79
+
80
+ self .drawer .line (
81
+ trials ,
82
+ hop_accumulative ,
83
+ name = "hop_cumulative" ,
84
+ label = "Cumulative HOP" ,
85
+ legend = True ,
86
+ )
87
+ self .drawer .hline (
88
+ 2 / 3 ,
89
+ name = "threshold" ,
90
+ label = "Threshold" ,
91
+ legend = True ,
92
+ )
93
+ self .drawer .scatter (
94
+ trials ,
95
+ hops ,
96
+ name = "hop" ,
97
+ label = "Individual HOP" ,
98
+ legend = True ,
99
+ linewidth = 1.5 ,
100
+ )
101
+ self .drawer .filled_y_area (
102
+ trials ,
103
+ hop_accumulative - hop_twosigma ,
104
+ hop_accumulative + hop_twosigma ,
105
+ alpha = 0.5 ,
106
+ legend = True ,
107
+ name = "hop_twosigma" ,
108
+ label = "2σ" ,
109
+ )
110
+
111
+ self .drawer .set_figure_options (
112
+ ylim = (
113
+ max (hop_accumulative [- 1 ] - 4 * hop_twosigma [- 1 ], 0 ),
114
+ min (hop_accumulative [- 1 ] + 4 * hop_twosigma [- 1 ], 1 ),
115
+ ),
116
+ )
29
117
30
118
31
119
class QuantumVolumeAnalysis (BaseAnalysis ):
@@ -53,6 +141,7 @@ def _default_options(cls) -> Options:
53
141
options = super ()._default_options ()
54
142
options .plot = True
55
143
options .ax = None
144
+ options .plotter = QVPlotter (MplDrawer ())
56
145
return options
57
146
58
147
def _run_analysis (self , experiment_data ):
@@ -77,8 +166,9 @@ def _run_analysis(self, experiment_data):
77
166
hop_result , qv_result = self ._calc_quantum_volume (heavy_output_prob_exp , depth , num_trials )
78
167
79
168
if self .options .plot :
80
- ax = self ._format_plot (hop_result , ax = self .options .ax )
81
- figures = [ax .get_figure ()]
169
+ self .options .plotter .set_series_data ("hops" , hops = hop_result .extra ["HOPs" ])
170
+ self .options .plotter .set_supplementary_data (depth = hop_result .extra ["depth" ])
171
+ figures = [self .options .plotter .figure ()]
82
172
else :
83
173
figures = None
84
174
return [hop_result , qv_result ], figures
@@ -238,73 +328,3 @@ def _calc_quantum_volume(self, heavy_output_prob_exp, depth, trials):
238
328
},
239
329
)
240
330
return hop_result , qv_result
241
-
242
- @staticmethod
243
- def _format_plot (
244
- hop_result : AnalysisResultData , ax : Optional ["matplotlib.pyplot.AxesSubplot" ] = None
245
- ):
246
- """Format the QV plot
247
-
248
- Args:
249
- hop_result: the heavy output probability analysis result.
250
- ax: matplotlib axis to add plot to.
251
-
252
- Returns:
253
- AxesSubPlot: the matplotlib axes containing the plot.
254
- """
255
- trials = hop_result .extra ["trials" ]
256
- heavy_probs = hop_result .extra ["HOPs" ]
257
- trial_list = np .arange (1 , trials + 1 ) # x data
258
-
259
- hop_accumulative = np .cumsum (heavy_probs ) / trial_list
260
- two_sigma = 2 * (hop_accumulative * (1 - hop_accumulative ) / trial_list ) ** 0.5
261
-
262
- # Plot individual HOP as scatter
263
- ax = plot_scatter (
264
- trial_list ,
265
- heavy_probs ,
266
- ax = ax ,
267
- s = 3 ,
268
- zorder = 3 ,
269
- label = "Individual HOP" ,
270
- )
271
- # Plot accumulative HOP
272
- ax .plot (trial_list , hop_accumulative , color = "r" , label = "Cumulative HOP" )
273
-
274
- # Plot two-sigma shaded area
275
- ax = plot_errorbar (
276
- trial_list ,
277
- hop_accumulative ,
278
- two_sigma ,
279
- ax = ax ,
280
- fmt = "none" ,
281
- ecolor = "lightgray" ,
282
- elinewidth = 20 ,
283
- capsize = 0 ,
284
- alpha = 0.5 ,
285
- label = "2$\\ sigma$" ,
286
- )
287
- # Plot 2/3 success threshold
288
- ax .axhline (2 / 3 , color = "k" , linestyle = "dashed" , linewidth = 1 , label = "Threshold" )
289
-
290
- ax .set_ylim (
291
- max (hop_accumulative [- 1 ] - 4 * two_sigma [- 1 ], 0 ),
292
- min (hop_accumulative [- 1 ] + 4 * two_sigma [- 1 ], 1 ),
293
- )
294
-
295
- ax .set_xlabel ("Number of Trials" , fontsize = 14 )
296
- ax .set_ylabel ("Heavy Output Probability" , fontsize = 14 )
297
-
298
- ax .set_title (
299
- "Quantum Volume experiment for depth "
300
- + str (hop_result .extra ["depth" ])
301
- + " - accumulative hop" ,
302
- fontsize = 14 ,
303
- )
304
-
305
- # Re-arrange legend order
306
- handles , labels = ax .get_legend_handles_labels ()
307
- handles = [handles [1 ], handles [2 ], handles [0 ], handles [3 ]]
308
- labels = [labels [1 ], labels [2 ], labels [0 ], labels [3 ]]
309
- ax .legend (handles , labels )
310
- return ax
0 commit comments