Qsurface¶
Qsurface is a simulation package for the surface code, and is designed to modularize 3 aspects of a surface code simulation.
The surface code
The error model
The used decoder
New types of surface codes, error modules and decoders can be added to Qsurface by using the included templates for each of the three core module categories.
The current included decoders are:
The Mininum-Weight Perfect Matching (
mwpm
) decoder.Delfosse’s and Nickerson’s Union-Find (
unionfind
) decoder, which has almost-linear worst-case time complexity.Our modification to the Union-Find decoder; the Union-Find Node-Suspension (
ufns
) decoder, which improves the threshold of the Union-Find decoder to near MWPM performance, while retaining quasi-linear worst-case time complexity.
The compatibility of these decoders with the included surface codes are listed below.
Decoders |
|
|
---|---|---|
|
✅ |
✅ |
|
✅ |
✅ |
|
✅ |
✅ |
Installation¶
All required packages can be installed through:
pip install qsurface
Requirements¶
Python 3.7+
Matplotlib 3.4+ for plotting on a 3D lattice (Refers to a future release of matplotlib, see pull request)
MWPM decoder¶
The MWPM decoder utilizes networkx
for finding the minimal weights in a fully connected graph. This implementation is however rather slow compared to Kolmogorov’s Blossom V algorithm. Blossom V has its own license and is thus not included with Qsurface. We do provided a single function to download and compile Blossom V, and to setup the integration with Qsurface automatically.
>>> from qsurface.decoders import mwpm
>>> mwpm.get_blossomv()
Usage¶
To simulate the toric code and simulate with bitflip error for 10 iterations and decode with the MWPM decoder:
>>> from qsurface.main import initialize, run
>>> code, decoder = initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"])
>>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1})
{'no_error': 8}
Benchmarking of decoders can be enabled by attaching a benchmarker object to the decoder. See the docs for the syntax and information to setup benchmarking.
>>> from qsurface.main import initialize, run
>>> benchmarker = BenchmarkDecoder({"decode":"duration"})
>>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1}, benchmark=benchmarker)
{'no_error': 8,
'benchmark': {'success_rate': [10, 10],
'seed': 12447.413636559,
'durations': {'decode': {'mean': 0.00244155000000319,
'std': 0.002170364089572033}}}}
Plotting¶
The figures in Qsurface allows for step-by-step visualization of the surface code simulation (and if supported the decoding process). Each figure logs its history such that the user can move backwards in time to view past states of the surface (and decoder). Press h
when the figure is open for more information.
>>> from qsurface.main import initialize, run
>>> code, decoder = initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"], plotting=True, initial_states=(0,0))
>>> run(code, decoder, error_rates = {"p_bitflip": 0.1, "p_phaseflip": 0.1}, decode_initial=False)

Plotting will be performed on a 3D axis if faulty measurements are enabled.
>>> code, decoder = initialize((3,3), "toric", "mwpm", enabled_errors=["pauli"], faulty_measurements=True, plotting=True, initial_states=(0,0))
>>> run(code, decoder, error_rates = {"p_bitflip": 0.05, "p_bitflip_plaq": 0.05}, decode_initial=False)

In IPython, inline images are created for each iteration of the plot, which can be tested in the example notebook.
Command line interface¶
Simulations can also be initiated from the command line
$ python -m qsurface -e pauli -D mwpm -C toric simulation --p_bitflip 0.1 -n 10
{'no_error': 8}
For more information on command line interface:
$ python -m qsurface -h
usage: qsurface
...
This project is proudly funded by the `Unitary Fund <https://unitary.fund/>`_.
Modules¶
Running simulations¶
Contains functions and classes to run and benchmark surface code simulations and visualizations. Use initialize
to prepare a surface code and a decoder instance, which can be passed on to run
and run_multiprocess
to simulate errors and to decode them with the decoder.
-
qsurface.main.
initialize
(size, Code, Decoder, enabled_errors=[], faulty_measurements=False, plotting=False, **kwargs)¶ Initializes a code and a decoder.
The function makes sure that the correct class is used to instance the surface code and decoder based on the arguments provided. A code instance must be initalized with
enabled_errors
byinitialize
after class instance to make sure that plot parameters are properly loaded before loading the plotting items included in each included error module, ifplotting
is enabled. Seeplot.Template2D
anderrors._template.Plot
for more information.- Parameters
size (
Union
[Tuple
[int
,int
],int
]) – The size of the surface in xy or (x,y).Code (
Union
[module
,str
]) – Any surface code module or module name from codes.Decoder (
Union
[module
,str
]) – Any decoder module or module name from decodersenabled_errors (
List
[Union
[str
,Sim
]]) – List of error modules fromerrors
.faulty_measurements (
bool
) – Enable faulty measurements (decode in a 3D lattice).plotting (
bool
) – Enable plotting for the surface code and/or decoder.kwargs – Keyword arguments are passed on to the chosen code,
initialize
, and the chosen decoder.
Examples
To initialize a 6x6 toric code with the MWPM decoder and Pauli errors:
>>> initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"], check_compatibility=True) (<toric (6, 6) PerfectMeasurements>, <Minimum-Weight Perfect Matching decoder (Toric)>) ✅ This decoder is compatible with the code.
Keyword arguments for the code and decoder classes can be included for further customization of class initialization. Note that default errors rates for error class initialization (see
init_errors
anderrors._template.Sim
) can also be provided as keyword arguments here.>>> enabled_errors = ["pauli"] >>> code_kwargs = { ... "initial_states": (0,0), ... "p_bitflip": 0.1, ... } >>> decoder_kwargs = { ... "check_compatibility": True, ... "weighted_union": False, ... "weighted_growth": False, ... } >>> initialize((6,6), "toric", "unionfind", enabled_errors=enabled_errors, **code_kwargs, **decoder_kwargs) ✅ This decoder is compatible with the code.
-
qsurface.main.
run
(code, decoder, error_rates={}, iterations=1, decode_initial=True, seed=None, benchmark=None, mp_queue=None, mp_process=0, **kwargs)¶ Runs surface code simulation.
Single command function to run a surface code simulation for a number of iterations.
- Parameters
code (
PerfectMeasurements
) – A surface code instance (seeinitialize
).decoder (
Sim
) – A decoder instance (seeinitialize
).iterations (
int
) – Number of iterations to run.error_rates (
dict
) – Dictionary of error rates (seeerrors
). Errors must have been loaded during code class initialization byinitialize
orinit_errors
.decode_initial (
bool
) – Decode initial code configuration before applying loaded errors. If random states are used for the data-qubits of thecode
at class initialization (default behavior), an initial round of decoding is required and is enabled through thedecode_initial
flag (default is enabled).seed (
Optional
[float
]) – Float to use as the seed for the random number generator.benchmark (
Optional
[BenchmarkDecoder
]) – Benchmarks decoder performance and analytics if attached.kwargs – Keyword arguments are passed on to
decode
.
Examples
To simulate the toric code and simulate with bitflip error for 10 iterations and decode with the MWPM decoder:
>>> code, decoder = initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"]) >>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1}) {'no_error': 8}
Benchmarked results are updated to the returned dictionary. See
BenchmarkDecoder
for the syntax and information to setup benchmarking.>>> code, decoder = initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"]) >>> benchmarker = BenchmarkDecoder({"decode":"duration"}) >>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1}, benchmark=benchmarker) {'no_error': 8, 'benchmark': {'decoded': 10, 'iterations': 10, 'seed': 12447.413636559, 'durations': {'decode': {'mean': 0.00244155000000319, 'std': 0.002170364089572033}}}}
-
qsurface.main.
run_multiprocess
(code, decoder, error_rates={}, iterations=1, decode_initial=True, seed=None, processes=1, benchmark=None, **kwargs)¶ Runs surface code simulation using multiple processes.
Using the standard module
multiprocessing
and itsProcess
class, several processes are created that each runs its on contained simulation usingrun
. Thecode
anddecoder
objects are copied such that each process has its own instance. The total number ofiterations
are divided for the number ofprocesses
indicated. If noprocesses
parameter is supplied, the number of available threads is determined viacpu_count
and all threads are utilized.If a
BenchmarkDecoder
object is attached tobenchmark
,Process
copies the object for each separate thread. Each instance of the the decoder thus have its own benchmark object. The results of the benchmark are appended to a list and addded to the output.See
run
for examples on running a simulation.- Parameters
code (
PerfectMeasurements
) – A surface code instance (see initialize).decoder (
Sim
) – A decoder instance (see initialize).error_rates (
dict
) – Dictionary for error rates (seeerrors
).iterations (
int
) – Total number of iterations to run.decode_initial (
bool
) – Decode initial code configuration before applying loaded errors.seed (
Optional
[float
]) – Float to use as the seed for the random number generator.processes (
int
) – Number of processes to spawn.benchmark (
Optional
[BenchmarkDecoder
]) – Benchmarks decoder performance and analytics if attached.kwargs – Keyword arguments are passed on to every process of run.
-
class
qsurface.main.
BenchmarkDecoder
(methods_to_benchmark={}, decoder=None, **kwargs)¶ Benchmarks a decoder during simulation.
A benchmark of a decoder can be performed by attaching the current class to a
decode
. A benchmarker will keep track of the number of simulated iterations and the number of successfull operations by the decoder inself.data
.Secondly, a benchmark of the decoder’s class methods can be performed by the decorators supplied in the current class, which have the form def
decorator(self, func):
. The approach in the current benchmark class allows for decorating any of the decoder’s class methods after it has been instanced. The benefit here is that if no benchmark class is attached, no benchmarking will be performed. The class methods to benchmark must be supplied as a dictionary, where the keys are equivalent to the class method names, and the values are the decorator names. Benchmarked values are stored as class attributes to the benchmark object.There are two types of decorators, list decorators, which append some value to a dictionary of lists
self.lists
, and value decorators, that saves or updates some value inself.values
.- Parameters
-
data
¶ Simulation data.
-
lists
¶ Benchmarked data by list decorators.
-
values
¶ Benchmarked data by value decorators.
Examples
To keep track of the duration of each iteration of decoding, the decoder’s decode method can be decorated with the duration decorator.
>>> code, decoder = initialize((6,6), "toric", "mwpm", enabled_errors=["pauli"]) >>> benchmarker = BenchmarkDecoder({"decode": "duration"}, decoder=decoder) >>> code.random_errors(p_bitflip=0.1) >>> decoder.decode() >>> benchmarker.lists {'duration': {'decode': [0.0009881999976641964]}}
The benchmark class can also be attached to run. The mean and standard deviations of the benchmarked values are in that case updated to the output of run after running
lists_mean_var
.>>> benchmarker = BenchmarkDecoder({"decode":"duration"}) >>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1}, benchmark=benchmarker) {'no_error': 8, 'benchmark': {'success_rate': [10, 10], 'seed': 12447.413636559, 'durations': {'decode': {'mean': 0.00244155000000319, 'std': 0.002170364089572033}}}}
Number of calls to class methods can be counted by the count_calls decorator and stored to self.values. Values in self.values can be saved to a list to, for example, log the value per decoding iteration by the value_to_list decorator. Multiple decorators can be attached to a class method by a list of names in methods_to_benchmark. The logged data are still available in the benchmarker class itself.
>>> benchmarker = BenchmarkDecoder({ "decode": ["duration", "value_to_list"], "correct_edge": "count_calls", }) >>> run(code, decoder, iterations=10, error_rates = {"p_bitflip": 0.1}, benchmark=benchmarker) {'no_error': 8, 'benchmark': {'success_rate': [10, 10], 'seed': '12447.413636559', 'duration': {'decode': {'mean': 0.001886229999945499, 'std': 0.0007808582199605158}}, 'count_calls': {'correct_edge': {'mean': 6.7, 'std': 1.4177446878757827}}}} >>> benchmarker.lists {'duration': {'decode': [0.0030814000019745436, 0.0015807000017957762, 0.0010604999988572672, 0.0035383000031288248, 0.0018329999984416645, 0.001753099997586105, 0.001290500000322936, 0.0014110999982221983, 0.0011783000009017996, 0.0021353999982238747]}, 'count_calls': {'correct_edge': [10, 7, 5, 7, 6, 6, 7, 6, 5, 8]}}
Nested class methods can also be benchmarked, e.g. for find of Cluster, which has an alias in unionfind.sim.Toric.
>>> code, decoder = initialize((6,6), "toric", "unionfind", enabled_errors=["pauli"]) >>> benchmarker = BenchmarkDecoder({"Cluster.find", "count_calls"}) >>> code.random_errors(p_bitflip=0.1) >>> decoder.decode() >>> benchmarker.values {'count_calls': {'find': 30}}
-
lists_mean_var
(reset=True)¶ Get mean and stand deviation of values in
self.lists
.- Parameters
reset (
bool
) – Resets all inself.lists
to empty lists.
-
value_to_list
(func)¶ Appends all values in
self.values
to lists inself.lists
.
-
duration
(func)¶ Logs the duration of
func
inself.lists
.
-
count_calls
(func)¶ Logs the number of calls to
func
inself.values
.
Running a threshold simulation¶
-
qsurface.threshold.
run_many
(Code, Decoder, iterations=1, sizes=[], enabled_errors=[], error_rates=[], faulty_measurements=False, methods_to_benchmark={}, output='', mp_processes=1, recursion_limit=100000, **kwargs)¶ Runs a series of simulations of varying sizes and error rates.
A series of simulations are run without plotting for all combinations of
sizes
anderror_rates
. The results are returned as a Pandas DataFrame and saved to the working directory as a csv file. If an existing csv file with the same file name is found, the existing file is loaded and new results are appended to the existing data. Amain.BenchmarkDecoder
object is attached to each simulation to log the seed and other information.- Parameters
Code (
Union
[module
,str
]) – Any surface code module or module name from codes.Decoder (
Union
[module
,str
]) – Any decoder module or module name from decodersiterations (
int
) – Number of iterations to run per configuration.sizes (
List
[Union
[int
,Tuple
[int
,int
]]]) – The sizes of the surface configurations.enabled_errors (
List
[Union
[str
,Sim
]]) – List of error modules fromerrors
.error_rates (
List
[Dict
]) – List of dictionaries for error rates per configuration (seeerrors
).faulty_measurements (
bool
) – Enable faulty measurements (decode in a 3D lattice).methods_to_benchmark (
dict
) – Decoder class methods to benchmark.output (
str
) – File name of outputted csv data. If set to “none”, no file will be saved.mp_processses – Number of processes to spawn. For a single process,
run
is used. For multiple processes,run_multiprocess
is utilized.
Examples
A series of simulations using the
toric
surface code andmwpm
decoder can be easily setup. Benchmarking can be performed by supplying themethods_to_benchmark
argument of theBenchmarkDecoder
class. The function will initialize a benchmark object of each configuration and append all results as columns to the returned dataframe.>>> data = run_many( ... "toric", ... "mwpm", ... iterations = 1000, ... sizes = [8,12,16], ... enabled_errors = ["pauli"], ... error_rates = [{"p_bitflip: p} for p in [0.09, 0.1, 0.11]], ... ) >>> print(data) datetime decoded iterations no_error p_bitflip seed size 0 04/11/2020 14:45:36 1000.0 1000.0 820.0 0.09 13163.013981 8.0 1 04/11/2020 14:45:45 1000.0 1000.0 743.0 0.10 13172.277886 8.0 2 04/11/2020 14:45:54 1000.0 1000.0 673.0 0.11 13181.090130 8.0 3 04/11/2020 14:46:36 1000.0 1000.0 812.0 0.09 13190.191461 12.0 4 04/11/2020 14:47:18 1000.0 1000.0 768.0 0.10 13232.408302 12.0 5 04/11/2020 14:48:16 1000.0 1000.0 629.0 0.11 13274.044268 12.0 6 04/11/2020 14:51:47 1000.0 1000.0 855.0 0.09 13332.153639 16.0 7 04/11/2020 14:55:15 1000.0 1000.0 754.0 0.10 13542.533067 16.0 8 04/11/2020 14:59:14 1000.0 1000.0 621.0 0.11 13751.082511 16.0
- Return type
Optional
[DataFrame
]
-
qsurface.threshold.
read_csv
(file)¶ Reads a CSV file parses it as a Pandas DataFrame.
- Return type
DataFrame
-
class
qsurface.threshold.
ThresholdFit
(modified_ansatz=False, p=0.09, 0.1, 0.11, A=- inf, 0, inf, B=- inf, 0, inf, C=- inf, 0, inf, D=- 2, 1.6, 2, nu=0.8, 0.95, 1.2, mu=0, 0.7, 3)¶ Fitter for code threshold with data obtained by
~.threshold.run
.Threshold fitting is performed using the equations described in [wang2003confinement]. The threshold is computing the ground state of the Hamiltonian that described the phase transition or the Nishimori line in the Random Bond Ising Model. The source provides two functions which are included in this fitting class, where the
modified_ansatz
includes a nonuniversion additive correction to correct for finite size effects.- wang2003confinement
Chenyang Wang, Jim Harrington and John Preskill, Confinement-Higgs transition in a disordered gauge theory and the accuracy threshold for quantum memory, Annals of Physics, 1:31-58, 2003.
-
fit_data
(data, column, **kwargs)¶ Fits for the code threshold.
- Parameters
data (
DataFrame
) – Data obtained viarun
.column (
str
) – The column of the DataFrame to fit for.kwargs – Keyword arguments are passed on the
scipy.curve_fit
.
-
plot_data
(data, column, figure=None, rescaled=False, scatter_kwargs={'s': 10}, line_kwargs={'alpha': 0.5, 'ls': 'dashed', 'lw': 1.5}, axis_attributes={'title': 'Threshold', 'xlabel': 'Physical error rate', 'ylabel': 'Logical error rate'}, num_x_fit=1000, **kwargs)¶ Plots the inputted data and the fit for the code threshold.
- Parameters
data (
DataFrame
) – Data obtained viarun
.column (
str
) – The column of the DataFrame to fit for.figure (
Optional
[Figure
]) – If a figure is attached,show
is not called. Instead, the figure is returned for futher manipulation.rescaled (
bool
) – Plots the data on a rescaled x axis where the fit is a single line.scatter_kwargs (
dict
) – Keyword arguments to pass on to thescatter
for the markers.line_kwargs (
dict
) – Keyword arguments to pass on to the ~matplotlib.pyplot.plot for the line plot.axis_attributes (
dict
) – Attributes to set of the axis viaaxis.set_{attribute}(value)
.num_x_fit (
int
) – Numpy of points to plot for the fit.
Code elements¶
-
class
qsurface.codes.elements.
Qubit
(loc, z=0, *args, **kwargs)¶ General type qubit object.
# This class mainly serves as a superclass or template to other more useful qubit types, which have the apprioate subclass attributes and subclass methods. For other types to to the ‘See Also’ section.
-
class
qsurface.codes.elements.
DataQubit
(*args, **kwargs)¶ Data type qubit object.
The state of a data-qubit is determined by two
Edge
objects stored in theself.edges
dictionary. Each of the edges are part of a separate graph on the surface lattice.-
edges
¶ Dictionary of edges with the error type as key (e.g.
"x"
or"z"
).self.edges = {“x”: Edge_x, “z”, Edge_z}
- Type
dict of
Edge
-
state
¶ A class property that calls to each of the edges stored at the
self.edges
attribute and returns all edge states as a dictionary.- Type
dict of bool
-
-
class
qsurface.codes.elements.
AncillaQubit
(*args, state_type='default', **kwargs)¶ General type qubit object.
An ancilla-qubit is entangled to one or more
DataQubit
objects. Theself.state_type
attribute determines the state on which the measurement is applied. A single measurement is applied when the class propertyself.state
is called. The state of the last measurement is stored inself.measured_state
for state access without prompting a new measurement.- Parameters
state_type (str, {"x", "z"}) – Type of ‘codes.elements.Edge’ objects belonging to the
DataQubit
objects entangled to the current ancilla-qubit for stabilizer measurements.
-
parity_qubits
¶ All qubits in this dictionary are entangled to the current ancilla for stabilizer measurements.
- Type
dict of
DataQubit
-
z_neighbors
¶ Neighbor ancilla in the z direction that is an instance of the same qubit at a different time, required for faulty measurements.
Examples
The state of the entangled
DataQubit
is located at:>>> AncillaQubit.parity_qubits[key].edges[AncillaQubit.state_type] True
-
measure
(p_bitflip_plaq=0, p_bitflip_star=0, **kwargs)¶ Applies a parity measurement on the ancilla.
The functions loops over all the data qubits in
self.parity_qubits
. For every edge associated with the entangled state on the data qubit, the value of aparity
boolean is flipped.
-
class
qsurface.codes.elements.
Edge
(qubit, state_type='', initial_state=None, **kwargs)¶ A state object belonging to a
DataQubit
object.An edge cannot have open vertices and must be spanned by two nodes. In this case, the two nodes must be
AncillaQubit
objects, and are stored inself.nodes
.- Parameters
-
nodes
¶ The vertices that spans the edge.
- Type
list of two ~.codes.elements.AncillaQubit` objects
-
add_node
(node, **kwargs)¶ Adds a node to the edge’s
self.nodes
attribute.
-
class
qsurface.codes.elements.
PseudoQubit
(*args, state_type='default', **kwargs)¶ Boundary element, imitates
codes.elements.AncillaQubit
.Edges needs to be spanned by two nodes. For data qubits on the boundary, one of its edges additionally requires an ancilla qubit like node, which is the pseudo-qubit.
-
measure
(p_bitflip_plaq=0, p_bitflip_star=0, **kwargs)¶ Applies a parity measurement on the ancilla.
The functions loops over all the data qubits in
self.parity_qubits
. For every edge associated with the entangled state on the data qubit, the value of aparity
boolean is flipped.
-
-
class
qsurface.codes.elements.
PseudoEdge
(qubit, state_type='', initial_state=None, **kwargs)¶ Vertical edge connecting time instances of ancilla-qubits, imitates
codes.elements.Edge
.-
add_node
(node, **kwargs)¶ Adds a node to the edge’s
self.nodes
attribute.
-
Template code¶
Simulation¶
-
class
qsurface.codes._template.sim.
PerfectMeasurements
(size, **kwargs)¶ Simulation code class for perfect measurements.
The qubits of the code class are stored in a double dictionary, with the keys in the outer dictionary corresponding to the qubit layer. For perfect measurements, there is a single layer. For faulty measurements, there are multiple layers (and defaults to
self.size
). In the nested dictionaries each qubit is stored byqubit.loc
as key. A qubit can thus be accessed byself.qubits[layer][(x,y)]
.The qubit and edge classes from Code elements can be replaced with inherited classes to store decoder dependent attributes.
- Parameters
size (int or tuple) – Size of the surface code in single dimension or two dimensions
(x,y)
.
-
ancilla_qubits
¶ Nested dictionary of
AncillaQubit
objects.- Type
dict of dict
-
pseudo_qubits
¶ Nested dictionary of
PseudoQubit
objects.- Type
dict of dict
-
errors
¶ Dictionary of error modules with the module name as key. All error modules from Error types loaded in
self.errors
will be applied during a simulation byrandom_errors()
.- Type
-
logical_operators
¶ Dictionary with lists of
Edge
objects that from a trivial loop over the surface and correspond to a logical operator. The logical state of each operator can be obtained by the state of each Edge in the list.- Type
dict of list
-
logical_state
¶ Dictionary with the states corresponding to the logical operators in
self.logical_operators
.- Type
dict of bool
-
no_error
¶ Property for whether there is a logical error in the last iteration. The value for
self.no_error
is updated after a call toself.logical_state
.- Type
-
trivial_ancillas
¶ Property for whether all ancillas are trivial. Usefull for checking if decoding has been successfull.
- Type
-
instance
¶ Time stamp that is renewed every time
random_errors
is called. Helps with identifying a ‘round’ of simulation when using class attributes.- Type
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
abstract
init_surface
()¶ Initiates the surface code.
-
abstract
init_logical_operator
()¶ Initiates the logical operators.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
random_errors
(apply_order=None, measure=True, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.
-
class
qsurface.codes._template.sim.
FaultyMeasurements
(size, *args, layers=None, p_bitflip_plaq=0, p_bitflip_star=0, **kwargs)¶ Simulation code class for faulty measurements.
A 3D graph is initiated with
layers
amount of 2D surfaces fromPerfectMeasurement
stacked on top of each other. The structure of theself.data_qubits
,self.ancilla_qubits
andself.pseudo_qubits
dictionary attributes allows for the storage for various time instances of the same qubits in the first nested layer. E.g.self.data_qubits[0][(0,0)]
andself.data_qubits[1][(0,0)]
store the data-qubit at (0,0) at time instances 0 and 1, respectively. Consecutive instances ofAncillaQubit
objects andPseudoQubit
objects are connected in the 3D graph byPseudoEdge
objects.- Parameters
-
simulate
(**kwargs)¶ Simulate an iteration or errors and measurement.
On all but the final layer, the default or overriding error rates (via keyworded arguments) are applied. On the final layer, perfect measurements are applied by setting
p_bitflip_plaq=0
andp_bitflip_star=0
.
-
init_surface
(**kwargs)¶ Initiates the surface code.
The 3D lattice is initialized by first building the ground layer. After that each consecutive layer is built and pseudo-edges are added to connect the ancilla qubits of each layer.
-
add_vertical_edge
(lower_ancilla, upper_ancilla, **kwargs)¶ Adds a
PseudoEdge
to connect two instances of an ancilla-qubit in time.A surface code with faulty measurements must be decoded in 3D. Instances of the same ancilla qubits in time must be connected with an edge. Here,
lower_ancilla
is an older instance of layer ‘z’, andupper_ancilla
is a newer instance of layer ‘z+1’.- Parameters
lower_ancilla (
AncillaQubit
) – Older instance of ancilla-qubit.upper_ancilla (
AncillaQubit
) – Newer instance of ancilla-qubit.
-
random_errors
(p_bitflip_plaq=None, p_bitflip_star=None, **kwargs)¶ Performs a round of parity measurements on layer
z
with faulty measurements.
-
random_errors_layer
(**kwargs)¶ Applies a layer of random errors loaded in
self.errors
.- Parameters
kwargs – Keyword arguments are passed on to
random_errors
.
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
abstract
init_logical_operator
()¶ Initiates the logical operators.
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
random_measure_layer
(**kwargs)¶ Measures a layer of ancillas.
If the measured state of the current ancilla is not equal to the measured state of the previous instance, the current ancilla is a syndrome.
- Parameters
kwargs – Keyword arguments are passed on to
get_state
.
Plotting¶
-
class
qsurface.codes._template.plot.
PerfectMeasurements
(*args, **kwargs)¶ Plotting template code class for perfect measurements.
-
initialize
(*args, **kwargs)¶ Initializes the code with a figure. Also takes keyword arguments for
init_plot
.Since each error object delivers extra plot properties to the figure, which are dependent on the
self.params
values in the figure itself, we must initialize in the following sequence.First load figure to load
self.params
instance of thePlotParams
dataclass.Initialize lattice, error initialization must have figure properties
Draw figure with plot elements from errors
-
random_errors
(*args, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.- Parameters
apply_order – The order in which the error modules are applied. Items in the list must equal keys in
self.errors
or the names of the loaded error modules.measure – Measure ancilla qubits after errors have been simulated.
-
show_corrected
(**kwargs)¶ Redraws the qubits and ancillas to show their states after decoding.
-
plot_data
(iter_name=None, **kwargs)¶ Update plots of all data-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
plot_ancilla
(iter_name=None, **kwargs)¶ Update plots of all ancilla-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
class
Figure
(code, *args, **kwargs)¶ Surface code plot for perfect measurements.
The inner figure class that plots the surface code based on the
Qubit.loc
andQubit.z
values on the set ofcode.data_qubits
,code.ancilla_qubits
andcode.pseudo_qubits
. This allows for a high amount of code inheritance.An additional
matplotlib.widgets.RadioButtons
object is added to the figure which allows for the user to choose one of the loaded errors and apply the error directly to a qubit via_pick_handler
.- Parameters
code (
PerfectMeasurements
) – Surface code instance.kwargs – Keyword arguments are passed on to
plot.Template2D
.
-
code_params
¶ Additional plotting parameters loaded to the
plot.PlotParams
instance atself.params
.
-
init_plot
(**kwargs)¶ Plots all elements of the surface code onto the figure. Also takes keyword arguments for
init_legend
.An additional
matplotlib.widgets.RadioButtons
object is added to the figure which allows for the user to choose one of the loaded errors and apply the error directly to a qubit via_pick_handler
. This object is added via theinit_plot
method to make sure that the errors are already loaded inself.code.errors
. The method for each loaded error is saved toself.error_methods
. Seeerrors._template.Plot
for more information.
-
init_legend
(legend_items=[], **kwargs)¶ Initializes the legend of the main axis of the figure. Also takes keyword arguments for
legend
.The legend of the main axis
self.main_ax
consists of a series ofLine2D
objects. The qubit, vertex and stars are always in the legend for a surface code plot. Any error from Error types loaded in the code atcode.errors
in de outer class will add an extra element to the legend for differentiation if an error occurs. TheLine2D
attributes are stored aterror.Plot.legend_params
of the error module (seeerrors._template.Plot
).- Parameters
legend_items (list of
Line2D
, optional) – Additional elements to the legend.
-
static
change_properties
(artist, prop_dict)¶ Changes the plot properties and draw the plot object or artist.
-
close
()¶ Closes the figure.
-
draw_figure
(new_iter_name=None, output=True, carriage_return=False, **kwargs)¶ Draws the canvas and blocks code execution.
Draws the queued plot changes onto the canvas and calls for
focus()
which blocks the code execution and catches user input for history navigation.If a new iteration is called by supplying a
new_iter_name
, we additionally check for future property changes in theself.future_dict
, and add these changes to the queue. Finally, all queued property changes for the next iteration are applied bychange_properties
.- Parameters
See also
-
focus
()¶ Enables the blocking object, catches input for history navigation.
The BlockingKeyInput object is called which blocks the execution of the code. During this block, the user input is received by the blocking object and return to the current method. From here, we can manipulate the plot or move through the plot history and call
focus()
again when all changes in the history have been drawn and blit.key
function
h
show help
i
show all iterations
d
redraw current iteration
enter or right
go to next iteration, enter iteration number
backspace or left
go to previous iteration
n
go to newest iteration
0-9
input iteration number
When the method is active, the focus is on the figure. This will be indicated by a green circle in the bottom right of the figure. When the focus is lost, the code execution is continued and the icon is red. The change is icon color is performed by
_set_figure_state()
, which also hides the interactive elements when the focus is lost.
-
property
history_at_newest
¶
-
load_interactive_backend
()¶ Configures the plotting backend.
If the Tkinter backend is enabled or can be enabled, the function returns True. For other backends False is returned.
- Return type
-
new_artist
(artist, axis=None)¶ Adds a new artist to the
axis
.Newly added artists must be hidden in the previous iteration. To make sure the history is properly logged, the visibility of the
artist
is set toFalse
, and a new property of shown visibility is added to the queue of the next iteration.
-
new_properties
(artist, properties, saved_properties={}, **kwargs)¶ Parses a dictionary of property changes of a matplotlib artist.
New properties are supplied via
properties
. If any of the new properties is different from its current value, this is seen as a property change. The old property value is stored inself.history_dict[self.history_iteration]
, and the new property value is stored atself.history_dict[self.history_iteration+1]
. These new properties are queued for the next interation. The queue is emptied by applying all changes whendraw_figure
is called. If the same property changes 2+ times within the same iteration, the previous property change is removed withnext_prop.pop(key, None)
.The
saved_properties
parameter is used when temporary property changes have been applied bytemporary_changes
, in which the original properties are saved toself.temporary_saved
as the saved properties. Before a new iteration is drawn, the temporary changes, which can be overwritten, are compared with the saved changes and the differences in properties are saved to[self.history_dict[self.history_iter-1]]
andself.history_dict[self.history_iteration]
.Some color values from different matplotlib objects are nested, some are list or tuple, and others may be a
numpy.ndarray
. The nested methodsget_nested()
andget_nested_property()
make sure that the return type is always a list.
-
temporary_properties
(artist, properties, **kwargs)¶ Applies temporary property changes to a matplotlib artist.
Only available on the newest iteration, as we cannot change what is already in the past. All values in
properties
are immediately applied toartist
. Since temporary changes can be overwritten within the same iteration, the first time a temporary property change is requested, the previous value is saved toself.temporary_saved
. When the iteration changes, the property differences of the previous and current iteration are recomputed and saved toself.history_dict
in_draw_from_history()
.
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
abstract
init_logical_operator
()¶ Initiates the logical operators.
-
abstract
init_surface
()¶ Initiates the surface code.
-
-
class
qsurface.codes._template.plot.
FaultyMeasurements
(*args, figure3d=True, **kwargs)¶ Plotting template code class for faulty measurements.
Inherits from
codes._template.sim.FaultyMeasurements
andcodes._template.plot.PerfectMeasurements
. See documentation for these classes for more.Dependent on the
figure3d
argument, either a 3D figure object is created that inherits fromTemplate3D
andcodes._template.plot.PerfectMeasurements.Figure
, or the 2Dcodes._template.plot.PerfectMeasurements.Figure
is used.- Parameters
args – Positional arguments are passed on to
codes._template.sim.FaultyMeasurements
.figure3d (
bool
) – Enables plotting on a 3D lattice. Disable to plot layer-by-layer on a 2D lattice, which increases responsiveness.kwargs – Keyword arguments are passed on to
codes._template.sim.FaultyMeasurements
and the figure object.
Code types¶
All surface code modules in this section inherit from the template surface code module, see Template code.
Toric code¶
Simulation¶
-
class
qsurface.codes.toric.sim.
PerfectMeasurements
(size, **kwargs)¶ -
init_surface
(z=0, **kwargs)¶ Initializes the toric surface code on layer
z
.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements. They are stored via the wind-directional keys.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla-qubit to initialize.
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x1, x2, z1, z2] of the toric code.
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
random_errors
(apply_order=None, measure=True, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.
-
-
class
qsurface.codes.toric.sim.
FaultyMeasurements
(size, *args, layers=None, p_bitflip_plaq=0, p_bitflip_star=0, **kwargs)¶ -
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
add_vertical_edge
(lower_ancilla, upper_ancilla, **kwargs)¶ Adds a
PseudoEdge
to connect two instances of an ancilla-qubit in time.A surface code with faulty measurements must be decoded in 3D. Instances of the same ancilla qubits in time must be connected with an edge. Here,
lower_ancilla
is an older instance of layer ‘z’, andupper_ancilla
is a newer instance of layer ‘z+1’.- Parameters
lower_ancilla (
AncillaQubit
) – Older instance of ancilla-qubit.upper_ancilla (
AncillaQubit
) – Newer instance of ancilla-qubit.
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x1, x2, z1, z2] of the toric code.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements. They are stored via the wind-directional keys.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla-qubit to initialize.
-
init_surface
(**kwargs)¶ Initiates the surface code.
The 3D lattice is initialized by first building the ground layer. After that each consecutive layer is built and pseudo-edges are added to connect the ancilla qubits of each layer.
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
random_errors
(p_bitflip_plaq=None, p_bitflip_star=None, **kwargs)¶ Performs a round of parity measurements on layer
z
with faulty measurements.
-
random_errors_layer
(**kwargs)¶ Applies a layer of random errors loaded in
self.errors
.- Parameters
kwargs – Keyword arguments are passed on to
random_errors
.
-
random_measure_layer
(**kwargs)¶ Measures a layer of ancillas.
If the measured state of the current ancilla is not equal to the measured state of the previous instance, the current ancilla is a syndrome.
- Parameters
kwargs – Keyword arguments are passed on to
get_state
.
-
simulate
(**kwargs)¶ Simulate an iteration or errors and measurement.
On all but the final layer, the default or overriding error rates (via keyworded arguments) are applied. On the final layer, perfect measurements are applied by setting
p_bitflip_plaq=0
andp_bitflip_star=0
.
-
Plotting¶
-
class
qsurface.codes.toric.plot.
PerfectMeasurements
(*args, **kwargs)¶ -
class
Figure
(code, *args, **kwargs)¶ -
static
change_properties
(artist, prop_dict)¶ Changes the plot properties and draw the plot object or artist.
-
close
()¶ Closes the figure.
-
draw_figure
(new_iter_name=None, output=True, carriage_return=False, **kwargs)¶ Draws the canvas and blocks code execution.
Draws the queued plot changes onto the canvas and calls for
focus()
which blocks the code execution and catches user input for history navigation.If a new iteration is called by supplying a
new_iter_name
, we additionally check for future property changes in theself.future_dict
, and add these changes to the queue. Finally, all queued property changes for the next iteration are applied bychange_properties
.- Parameters
See also
-
focus
()¶ Enables the blocking object, catches input for history navigation.
The BlockingKeyInput object is called which blocks the execution of the code. During this block, the user input is received by the blocking object and return to the current method. From here, we can manipulate the plot or move through the plot history and call
focus()
again when all changes in the history have been drawn and blit.key
function
h
show help
i
show all iterations
d
redraw current iteration
enter or right
go to next iteration, enter iteration number
backspace or left
go to previous iteration
n
go to newest iteration
0-9
input iteration number
When the method is active, the focus is on the figure. This will be indicated by a green circle in the bottom right of the figure. When the focus is lost, the code execution is continued and the icon is red. The change is icon color is performed by
_set_figure_state()
, which also hides the interactive elements when the focus is lost.
-
property
history_at_newest
¶
-
init_legend
(legend_items=[], **kwargs)¶ Initializes the legend of the main axis of the figure. Also takes keyword arguments for
legend
.The legend of the main axis
self.main_ax
consists of a series ofLine2D
objects. The qubit, vertex and stars are always in the legend for a surface code plot. Any error from Error types loaded in the code atcode.errors
in de outer class will add an extra element to the legend for differentiation if an error occurs. TheLine2D
attributes are stored aterror.Plot.legend_params
of the error module (seeerrors._template.Plot
).- Parameters
legend_items (list of
Line2D
, optional) – Additional elements to the legend.
-
init_plot
(**kwargs)¶ Plots all elements of the surface code onto the figure. Also takes keyword arguments for
init_legend
.An additional
matplotlib.widgets.RadioButtons
object is added to the figure which allows for the user to choose one of the loaded errors and apply the error directly to a qubit via_pick_handler
. This object is added via theinit_plot
method to make sure that the errors are already loaded inself.code.errors
. The method for each loaded error is saved toself.error_methods
. Seeerrors._template.Plot
for more information.
-
load_interactive_backend
()¶ Configures the plotting backend.
If the Tkinter backend is enabled or can be enabled, the function returns True. For other backends False is returned.
- Return type
-
new_artist
(artist, axis=None)¶ Adds a new artist to the
axis
.Newly added artists must be hidden in the previous iteration. To make sure the history is properly logged, the visibility of the
artist
is set toFalse
, and a new property of shown visibility is added to the queue of the next iteration.
-
new_properties
(artist, properties, saved_properties={}, **kwargs)¶ Parses a dictionary of property changes of a matplotlib artist.
New properties are supplied via
properties
. If any of the new properties is different from its current value, this is seen as a property change. The old property value is stored inself.history_dict[self.history_iteration]
, and the new property value is stored atself.history_dict[self.history_iteration+1]
. These new properties are queued for the next interation. The queue is emptied by applying all changes whendraw_figure
is called. If the same property changes 2+ times within the same iteration, the previous property change is removed withnext_prop.pop(key, None)
.The
saved_properties
parameter is used when temporary property changes have been applied bytemporary_changes
, in which the original properties are saved toself.temporary_saved
as the saved properties. Before a new iteration is drawn, the temporary changes, which can be overwritten, are compared with the saved changes and the differences in properties are saved to[self.history_dict[self.history_iter-1]]
andself.history_dict[self.history_iteration]
.Some color values from different matplotlib objects are nested, some are list or tuple, and others may be a
numpy.ndarray
. The nested methodsget_nested()
andget_nested_property()
make sure that the return type is always a list.
-
temporary_properties
(artist, properties, **kwargs)¶ Applies temporary property changes to a matplotlib artist.
Only available on the newest iteration, as we cannot change what is already in the past. All values in
properties
are immediately applied toartist
. Since temporary changes can be overwritten within the same iteration, the first time a temporary property change is requested, the previous value is saved toself.temporary_saved
. When the iteration changes, the property differences of the previous and current iteration are recomputed and saved toself.history_dict
in_draw_from_history()
.
-
static
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x1, x2, z1, z2] of the toric code.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements. They are stored via the wind-directional keys.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla-qubit to initialize.
-
init_surface
(z=0, **kwargs)¶ Initializes the toric surface code on layer
z
.
-
initialize
(*args, **kwargs)¶ Initializes the code with a figure. Also takes keyword arguments for
init_plot
.Since each error object delivers extra plot properties to the figure, which are dependent on the
self.params
values in the figure itself, we must initialize in the following sequence.First load figure to load
self.params
instance of thePlotParams
dataclass.Initialize lattice, error initialization must have figure properties
Draw figure with plot elements from errors
-
plot_ancilla
(iter_name=None, **kwargs)¶ Update plots of all ancilla-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
plot_data
(iter_name=None, **kwargs)¶ Update plots of all data-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
random_errors
(*args, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.- Parameters
apply_order – The order in which the error modules are applied. Items in the list must equal keys in
self.errors
or the names of the loaded error modules.measure – Measure ancilla qubits after errors have been simulated.
-
show_corrected
(**kwargs)¶ Redraws the qubits and ancillas to show their states after decoding.
-
class
-
class
qsurface.codes.toric.plot.
FaultyMeasurements
(*args, figure3d=True, **kwargs)¶ Plotting code class for faulty measurements.
Inherits from
codes.toric.sim.FaultyMeasurements
andcodes.toric.plot.PerfectMeasurements
. See documentation for these classes for more.Dependent on the
figure3d
argument, either a 3D figure object is created that inherits fromTemplate3D
andcodes.toric.plot.PerfectMeasurements.Figure
, or the 2Dcodes.toric.plot.PerfectMeasurements.Figure
is used.- Parameters
args – Positional arguments are passed on to
codes.toric.sim.FaultyMeasurements
.figure3d (
bool
) – Enables plotting on a 3D lattice. Disable to plot layer-by-layer on a 2D lattice, which increases responsiveness.kwargs – Keyword arguments are passed on to
codes.toric.sim.FaultyMeasurements
and the figure object.
Planar code¶
Simulation¶
-
class
qsurface.codes.planar.sim.
PerfectMeasurements
(size, **kwargs)¶ -
init_surface
(z=0, **kwargs)¶ Initializes the planar surface code on layer
z
.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla qubit to initialize.
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x,z] of the planar code.
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
random_errors
(apply_order=None, measure=True, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.
-
-
class
qsurface.codes.planar.sim.
FaultyMeasurements
(size, *args, layers=None, p_bitflip_plaq=0, p_bitflip_star=0, **kwargs)¶ -
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
add_vertical_edge
(lower_ancilla, upper_ancilla, **kwargs)¶ Adds a
PseudoEdge
to connect two instances of an ancilla-qubit in time.A surface code with faulty measurements must be decoded in 3D. Instances of the same ancilla qubits in time must be connected with an edge. Here,
lower_ancilla
is an older instance of layer ‘z’, andupper_ancilla
is a newer instance of layer ‘z+1’.- Parameters
lower_ancilla (
AncillaQubit
) – Older instance of ancilla-qubit.upper_ancilla (
AncillaQubit
) – Newer instance of ancilla-qubit.
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x,z] of the planar code.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla qubit to initialize.
-
init_surface
(**kwargs)¶ Initiates the surface code.
The 3D lattice is initialized by first building the ground layer. After that each consecutive layer is built and pseudo-edges are added to connect the ancilla qubits of each layer.
-
initialize
(*args, **kwargs)¶ Initializes all data objects of the code.
Builds the surface with
init_surface
, adds the logical operators withinit_logical_operator
, and loads error modules withinit_errors
. All keyword arguments from these methods can be used forinitialize
.
-
random_errors
(p_bitflip_plaq=None, p_bitflip_star=None, **kwargs)¶ Performs a round of parity measurements on layer
z
with faulty measurements.
-
random_errors_layer
(**kwargs)¶ Applies a layer of random errors loaded in
self.errors
.- Parameters
kwargs – Keyword arguments are passed on to
random_errors
.
-
random_measure_layer
(**kwargs)¶ Measures a layer of ancillas.
If the measured state of the current ancilla is not equal to the measured state of the previous instance, the current ancilla is a syndrome.
- Parameters
kwargs – Keyword arguments are passed on to
get_state
.
-
simulate
(**kwargs)¶ Simulate an iteration or errors and measurement.
On all but the final layer, the default or overriding error rates (via keyworded arguments) are applied. On the final layer, perfect measurements are applied by setting
p_bitflip_plaq=0
andp_bitflip_star=0
.
-
Plotting¶
-
class
qsurface.codes.planar.plot.
PerfectMeasurements
(*args, **kwargs)¶ -
class
Figure
(code, *args, **kwargs)¶ -
static
change_properties
(artist, prop_dict)¶ Changes the plot properties and draw the plot object or artist.
-
close
()¶ Closes the figure.
-
draw_figure
(new_iter_name=None, output=True, carriage_return=False, **kwargs)¶ Draws the canvas and blocks code execution.
Draws the queued plot changes onto the canvas and calls for
focus()
which blocks the code execution and catches user input for history navigation.If a new iteration is called by supplying a
new_iter_name
, we additionally check for future property changes in theself.future_dict
, and add these changes to the queue. Finally, all queued property changes for the next iteration are applied bychange_properties
.- Parameters
See also
-
focus
()¶ Enables the blocking object, catches input for history navigation.
The BlockingKeyInput object is called which blocks the execution of the code. During this block, the user input is received by the blocking object and return to the current method. From here, we can manipulate the plot or move through the plot history and call
focus()
again when all changes in the history have been drawn and blit.key
function
h
show help
i
show all iterations
d
redraw current iteration
enter or right
go to next iteration, enter iteration number
backspace or left
go to previous iteration
n
go to newest iteration
0-9
input iteration number
When the method is active, the focus is on the figure. This will be indicated by a green circle in the bottom right of the figure. When the focus is lost, the code execution is continued and the icon is red. The change is icon color is performed by
_set_figure_state()
, which also hides the interactive elements when the focus is lost.
-
property
history_at_newest
¶
-
init_legend
(legend_items=[], **kwargs)¶ Initializes the legend of the main axis of the figure. Also takes keyword arguments for
legend
.The legend of the main axis
self.main_ax
consists of a series ofLine2D
objects. The qubit, vertex and stars are always in the legend for a surface code plot. Any error from Error types loaded in the code atcode.errors
in de outer class will add an extra element to the legend for differentiation if an error occurs. TheLine2D
attributes are stored aterror.Plot.legend_params
of the error module (seeerrors._template.Plot
).- Parameters
legend_items (list of
Line2D
, optional) – Additional elements to the legend.
-
init_plot
(**kwargs)¶ Plots all elements of the surface code onto the figure. Also takes keyword arguments for
init_legend
.An additional
matplotlib.widgets.RadioButtons
object is added to the figure which allows for the user to choose one of the loaded errors and apply the error directly to a qubit via_pick_handler
. This object is added via theinit_plot
method to make sure that the errors are already loaded inself.code.errors
. The method for each loaded error is saved toself.error_methods
. Seeerrors._template.Plot
for more information.
-
load_interactive_backend
()¶ Configures the plotting backend.
If the Tkinter backend is enabled or can be enabled, the function returns True. For other backends False is returned.
- Return type
-
new_artist
(artist, axis=None)¶ Adds a new artist to the
axis
.Newly added artists must be hidden in the previous iteration. To make sure the history is properly logged, the visibility of the
artist
is set toFalse
, and a new property of shown visibility is added to the queue of the next iteration.
-
new_properties
(artist, properties, saved_properties={}, **kwargs)¶ Parses a dictionary of property changes of a matplotlib artist.
New properties are supplied via
properties
. If any of the new properties is different from its current value, this is seen as a property change. The old property value is stored inself.history_dict[self.history_iteration]
, and the new property value is stored atself.history_dict[self.history_iteration+1]
. These new properties are queued for the next interation. The queue is emptied by applying all changes whendraw_figure
is called. If the same property changes 2+ times within the same iteration, the previous property change is removed withnext_prop.pop(key, None)
.The
saved_properties
parameter is used when temporary property changes have been applied bytemporary_changes
, in which the original properties are saved toself.temporary_saved
as the saved properties. Before a new iteration is drawn, the temporary changes, which can be overwritten, are compared with the saved changes and the differences in properties are saved to[self.history_dict[self.history_iter-1]]
andself.history_dict[self.history_iteration]
.Some color values from different matplotlib objects are nested, some are list or tuple, and others may be a
numpy.ndarray
. The nested methodsget_nested()
andget_nested_property()
make sure that the return type is always a list.
-
temporary_properties
(artist, properties, **kwargs)¶ Applies temporary property changes to a matplotlib artist.
Only available on the newest iteration, as we cannot change what is already in the past. All values in
properties
are immediately applied toartist
. Since temporary changes can be overwritten within the same iteration, the first time a temporary property change is requested, the previous value is saved toself.temporary_saved
. When the iteration changes, the property differences of the previous and current iteration are recomputed and saved toself.history_dict
in_draw_from_history()
.
-
static
-
add_ancilla_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
AncillaQubit
and saved toself.ancilla_qubits[z][loc]
.- Return type
-
add_data_qubit
(loc, z=0, initial_states=None, None, **kwargs)¶ Initializes a
DataQubit
and saved toself.data_qubits[z][loc]
.
-
add_pseudo_qubit
(loc, z=0, state_type='x', **kwargs)¶ Initializes a
PseudoQubit
and saved toself.pseudo_qubits[z][loc]
.- Return type
-
static
entangle_pair
(data_qubit, ancilla_qubit, key, edge=None, **kwargs)¶ Entangles one
DataQubit
to aAncillaQubit
for parity measurement.- Parameters
data_qubit (
DataQubit
) – Control qubit.ancilla_qubit (
AncillaQubit
) – Controlled qubit.key (
Any
) – The entanglement is saved by adding theDataQubit
toAncillaQubit
.parity_qubits[key]
edge (
Optional
[Edge
]) – The edge of the data-qubit to entangle to.
-
init_errors
(*error_modules, error_rates={}, **kwargs)¶ Initializes error modules.
Any error module from Error types can loaded as either a string equivalent to the module file name or as the module itself. The default error rates for all loaded error modules can be supplied as a dictionary with keywords corresponding to the default error rates of the associated error modules.
- Parameters
error_modules (
Union
[str
,Sim
]) – The error modules to load. May be a string or an error module from Error types.error_rates (
dict
) – The default error rates for the loaded modules. Must be a dictionary with probabilities with keywords corresponding to the default or overriding error rates of the associated error modules.
Examples
Load Pauli error and Erasure error modules via string names. Set default bitflip rate to
0.1
and erasure to0.03
.>>> code.init_errors( ... "pauli", ... "erasure", ... error_rates={"p_bitflip": 0.1, "p_erasure": 0.03} ... )
Load Pauli error module via module. Set default phaseflip rate to
0.05
.>>> import .errors.pauli as pauli >>> code.init_errors(pauli, error_rates={"p_phaseflip": 0.05})
-
init_logical_operator
(**kwargs)¶ Initiates the logical operators [x,z] of the planar code.
-
init_parity_check
(ancilla_qubit, **kwargs)¶ Initiates a parity check measurement.
For every ancilla qubit on
(x,y)
, four neighboring data qubits are entangled for parity check measurements.- Parameters
ancilla_qubit (
AncillaQubit
) – Ancilla qubit to initialize.
-
init_surface
(z=0, **kwargs)¶ Initializes the planar surface code on layer
z
.
-
initialize
(*args, **kwargs)¶ Initializes the code with a figure. Also takes keyword arguments for
init_plot
.Since each error object delivers extra plot properties to the figure, which are dependent on the
self.params
values in the figure itself, we must initialize in the following sequence.First load figure to load
self.params
instance of thePlotParams
dataclass.Initialize lattice, error initialization must have figure properties
Draw figure with plot elements from errors
-
plot_ancilla
(iter_name=None, **kwargs)¶ Update plots of all ancilla-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
plot_data
(iter_name=None, **kwargs)¶ Update plots of all data-qubits. A plot iteration is added if a
iter_name
is supplied. Seedraw_figure
.
-
random_errors
(*args, **kwargs)¶ Applies all errors loaded in
self.errors
attribute to layerz
.The random error is applied for each loaded error module by calling
random_error
. Ifapply_order
is specified, the error modules are applied in order of the error names in the list. If no order is specified, the errors are applied in a random order. Addionally, any error rate can set by supplying the rate as a keyword argument e.g.p_bitflip = 0.1
.- Parameters
apply_order – The order in which the error modules are applied. Items in the list must equal keys in
self.errors
or the names of the loaded error modules.measure – Measure ancilla qubits after errors have been simulated.
-
show_corrected
(**kwargs)¶ Redraws the qubits and ancillas to show their states after decoding.
-
class
-
class
qsurface.codes.planar.plot.
FaultyMeasurements
(*args, figure3d=True, **kwargs)¶ Plotting code class for faulty measurements.
Inherits from
codes.planar.sim.FaultyMeasurements
andcodes.planar.plot.PerfectMeasurements
. See documentation for these classes for more.Dependent on the
figure3d
argument, either a 3D figure object is created that inherits fromTemplate3D
andcodes.planar.plot.PerfectMeasurements.Figure
, or the 2Dcodes.planar.plot.PerfectMeasurements.Figure
is used.- Parameters
args – Positional arguments are passed on to
codes.planar.sim.FaultyMeasurements
.figure3d (
bool
) – Enables plotting on a 3D lattice. Disable to plot layer-by-layer on a 2D lattice, which increases responsiveness.kwargs – Keyword arguments are passed on to
codes.planar.sim.FaultyMeasurements
and the figure object.
Template error¶
-
class
qsurface.errors._template.
Sim
(code=None, **kwargs)¶ Template simulation class for errors.
The template simulation error class can be used as a parent class for error modules for surface code classes that inherit from
codes._template.sim.PerfectMeasurements
orcodes._template.sim.FaultyMeasurements
. The error of the module must be applied to each qubit separately using the abstract methodrandom_error
.- Parameters
code (
codes._template.sim.PerfectMeasurements
) – Simulation surface code class.
-
default_error_rates
¶ The error rates that are applied at default.
- Type
dict of float
-
class
qsurface.errors._template.
Plot
(*args, **kwargs)¶ Template plot class for errors.
The template plotting error class can be used as a parent class for error modules for surface code classes that inherit from
codes._template.plot.PerfectMeasurements
orcodes._template.plot.FaultyMeasurements
, which have a figure object attribute atcode.figure
. The error of the module must be applied to each qubit separately using the abstract methodrandom_error
.To change properties of the qubit (a
matplotlib.patches.Circle
object) if an error has been appied to visualize the error. The template plot error class features an easy way to define the plot properties of an error. First of all, each error must be defined in an error method that applies the error to the qubit. The template can contain multiple error methods, all of which must be called byrandom_error
. For all errors that we wish to plot, we must add the names of the methods toself.error_methods
. The plot properties are stored under the same name inself.plot_params
.class CustomPlotError(Plot): error_methods = ["example_method"] plot_params = { "example_method": {"edgecolor": "color_edge", "facecolor": (0,0,0,0)} } def random_error(self, qubit): if random.random < 0.5: self.error_method(qubit) def example_method(self, qubit): # apply error pass
Note that the properties can either be literal or refer to some attribute of the
PlotParams
object stored atself.code.figure.params
(seeload_params
). Thus the name for the error methods must be unique to any attribute inPlotParams
.Similarly, additional legend items can be added to the surface code plot
self.code.figure
. Each legend item is amatplotlib.lines.line2D
. The properties for each additional item in the legend is stored atself.legend_params
, and must also be unique to anyPlotParams
attribute. The legend titles for each item is stored inself.legend_titles
at the same keys. The additional legend items are added ininit_legend
.class CustomPlotError(Plot): error_methods = ["example_method"] plot_params = { "example_method": {"edgecolor": "color_edge", "facecolor": (0,0,0,0)} } legend_params = { "example_item": { "marker": "o", "color": "color_edge", "mfc": (1, 0, 0), "mec": "g", }, } legend_titles = { "example_item": "Example error" } def random_error(self, qubit): if random.random < 0.5: self.error_method(qubit) def example_method(self, qubit): # apply error pass
Finally, error methods can be also be added to the GUI of the surface code plot. For this, each error method must a static method that is not dependant on the error class. Each error method to be added in the GUI must be included in
self.gui_methods
. The GUI elements are included ininit_plot
.class CustomPlotError(Plot): error_methods = ["example_method"] gui_methods = ["example_method"] plot_params = { "example_method": {"edgecolor": "color_edge", "facecolor": (0,0,0,0)} } legend_params = { "example_item": { "marker": "o", "color": "color_edge", "mfc": (1, 0, 0), "mec": "g", }, } legend_titles = { "example_item": "Example error" } def random_error(self, qubit): if random.random < 0.5: self.error_method(qubit) @staticmethod def example_method(qubit): # apply error pass
- Parameters
code (
PerfectMeasurements
) – Plotting surface code class.
-
error_methods
¶ List of names of the error methods that changes the qubit surface code plot according to properties defined in
self.plot_params
.- Type
-
plot_params
¶ Qubit plot properties to apply for each of the error methods in
self.error_methods
. Properties are loaded to thePlotParams
object stored at theself.code.figure.params
attribute of the surface code plot (seeload_params
).- Type
{method_name: properties}
-
legend_params {method_name
Legend items to add to the surface code plot. Properties are loaded to the
PlotParams
object stored at theself.code.figure.params
attribute of the surface code plot (seeload_params
), and used to initialize aLine2D
legend item.- Type
Line2D properties}
-
legend_titles
¶ Titles to display for the legend items in
self.legend_params
.- Type
{method_name: legend_title}
-
gui_permanent
¶ If enabled, the application of an error method on a qubit cannot be reversed within the same simulation instance.
- Type
-
plot_error
(error_name)¶ Decorates the error method with plotting features.
The method
error_name
is decorated with plot property changes defined inself.plot_params
. For each of the properties to change, the original property value of the artist is stored and requested as a change at the end of the simulation instance.See also
None()
,None()
Error types¶
All error modules in this section inherit from the template error module, see Template error.
Pauli error¶
-
class
qsurface.errors.pauli.
Plot
(*args, **kwargs)¶ Plot Pauli error class.
-
class
qsurface.errors.pauli.
Sim
(*args, p_bitflip=0, p_phaseflip=0, **kwargs)¶ Simulation Pauli error class.
- Parameters
-
static
bitflip
(qubit, **kwargs)¶ Applies a bitflip or Pauli X on
qubit
.
-
static
bitphaseflip
(qubit, **kwargs)¶ Applies a bitflip and phaseflip or ZX on
qubit
.
-
static
phaseflip
(qubit, **kwargs)¶ Applies a phaseflip or Pauli Z on
qubit
.
-
random_error
(qubit, p_bitflip=0, p_phaseflip=0, **kwargs)¶ Applies a Pauli error, bitflip and/or phaseflip.
Erasure error¶
-
class
qsurface.errors.erasure.
Plot
(*args, **kwargs)¶ Plot erasure error class.
-
class
qsurface.errors.erasure.
Sim
(*args, p_erasure=0, initial_states=0, 0, **kwargs)¶ Simulation erasure error class.
- Parameters
-
static
erasure
(qubit, instance=0, initial_states=0, 0, **kwargs)¶ Erases the
qubit
by resetting its attributes.
-
random_error
(qubit, p_erasure=0, initial_states=None, **kwargs)¶ Applies an erasure error.
Template decoder¶
-
qsurface.decoders._template.
write_config
(config_dict, path)¶ Writes a configuration file to the path.
-
qsurface.decoders._template.
read_config
(path, config_dict=None)¶ Reads an INI formatted configuration file and parses it to a nested dict
Each category in the INI file will be parsed as a separate nested dictionary. A default
config_dict
can be provided with default values for the parameters. Parameters under the “main” section will be parsed in the main dictionary. All data types will be converted byast.literal_eval()
.- Parameters
- Returns
Parsed dictionary.
- Return type
Examples
Let us look at the following example INI file.
[main] param1 = hello [section] param2 = world param3 = 0.1
This file will be parsed as follows
>>> read_config("config.ini") { "param1": "hello", "section": { "param2": "world", "param3": 0.1 } }
-
qsurface.decoders._template.
init_config
(ini_file, write=False, **kwargs)¶ Reads the default and the user defined INI file.
First, the INI file stored in file directory is read and parsed. If there exists another INI file in the working directory, the attributes defined there are read, parsed and overwrites and default values.
- Parameters
write (bool) – Writes the default configuration to the working direction of the user.
See also
-
class
qsurface.decoders._template.
Sim
(code, check_compatibility=False, **kwargs)¶ Decoder simulation class template.
- Parameters
code (
PerfectMeasurements
) – APerfectMeasurements
orFaultyMeasurements
class from thesim
module of Code types.check_compatibility (
bool
) – Checks compatibility of the decoder with the code class and loaded errors bycheck_compatibility
.
-
compatibility_errors
¶ Compatibility with the various error modules in Error types.
- Type
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
correct_edge
(ancilla_qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.- Return type
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
-
abstract
decode
(*args, **kwargs)¶ Decodes the surface loaded at
self.code
after all ancilla-qubits have been measured.
-
class
qsurface.decoders._template.
Plot
(*args, **kwargs)¶ Decoder plotting class template.
The plotting decoder class requires a surface code object that inherits from
codes._template.plot.PerfectMeasurements
. The template decoder provides theplot_matching_edge
method that is called bycorrect_edge
to visualize the matched edges on the lattice.- Parameters
-
decode
(*args, **kwargs)¶ Decodes the surface loaded at
self.code
after all ancilla-qubits have been measured.
-
correct_edge
(qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.
-
plot_matching_edge
(line=None)¶ Plots the matching edge.
Based on the colors defined in
self.line_color_match
, if aLine2D
object is supplied, the color of the edge is changed. A future change back to its original color is immediately saved infigure.future_dict
.
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
Decoders¶
All decoder modules in this section inherit from the template decoder module, see Template decoder.
mwpm¶
The Minimum-Weight Perfect Matching decoder.
Information¶
The most popular decoder for surface codes is the Minimum-Weight Perfect Matching (MWPM) decoder. It performs near-optimal for a pauli noise model [dennis2002] on a standard toric code with a threshold of \(p_{\text{th}} = 10.3\%\), and for a phenomenological noise model (including faulty measurements) [wang2003], which includes faulty measurements, with \(p_{\text{th}} = 2.9\%\). The main idea is to approximate the error with the minimum-weight error configuration compatible with the syndrome. The minimum-weight configuration is found by constructing a fully connected graph between the nodes of the syndrome, which leads to a cubic worst-case time complexity [kolmogorov2009].
The decoder defaults to using a Python implementation of MWPM by networkx.algorithms.matching.max_weight_matching
. This implementation is however quite slow. Optionally, Blossom V [kolmogorov2009], a C++ algorithm, can be used to increase the speed of the decoder. Since this software has its own license, it is not bundeled with qsurface. A script is provided to download and compile the latest release of BlossomV in get_blossomv
. The interface of the C++ code and Python is taken from Fault Tolerant Simulations.
-
qsurface.decoders.mwpm.
get_blossomv
(accept=False)¶ Downloads and compiles the BlossomV algorithm, which is distributed under the following license:
License:
Copyright 2008-2009 UCL Business PLC, Author Vladimir Kolmogorov (vnk@ist.ac.at) This software can be used for evaluation and non-commercial research purposes only. Commercial use is prohibited. Public redistribution of the code or its derivatives is prohibited. If you use this software for research purposes, you should cite the following paper in any resulting publication: Vladimir Kolmogorov. "Blossom V: A new implementation of a minimum cost perfect matching algorithm." In Mathematical Programming Computation (MPC), July 2009, 1(1):43-67. For commercial use of the software not covered by this agreement, you may obtain a licence from the copyright holders UCL Business via their licensing site: www.e-lucid.com/i/software/optimisation_software/BlossomV.html. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Simulation¶
-
class
qsurface.decoders.mwpm.sim.
Toric
(code, check_compatibility=False, **kwargs)¶ Minimum-Weight Perfect Matching decoder for the toric lattice.
- Parameters
args – Positional and keyword arguments are passed on to
decoders._template.Sim
.kwargs – Positional and keyword arguments are passed on to
decoders._template.Sim
.
-
decode
(**kwargs)¶ Decodes the surface loaded at
self.code
after all ancilla-qubits have been measured.
-
match_syndromes
(syndromes, use_blossomv=False, **kwargs)¶ Decodes a list of syndromes of the same type.
A graph is constructed with the syndromes in
syndromes
as nodes and the distances between each of the syndromes as the edges. The distances are dependent on the boundary conditions of the code and is calculated byget_qubit_distances
. A minimum-weight matching is then found by eithermatch_networkx
ormatch_blossomv
.- Parameters
syndromes (
List
[AncillaQubit
]) – Syndromes of the code.use_blossomv (
bool
) – Use external C++ Blossom V library for minimum-weight matching. Needs to be downloaded and compiled by callingget_blossomv
.
- Returns
Minimum-weight matched ancilla-qubits.
- Return type
list of
AncillaQubit
-
correct_matching
(syndromes, matching, **kwargs)¶ Applies the matchings as a correction to the code.
-
static
match_networkx
(edges, maxcardinality, **kwargs)¶ Finds the minimum-weight matching of a list of
edges
usingnetworkx.algorithms.matching.max_weight_matching
.- Parameters
edges ([[nodeA, nodeB, distance(nodeA,nodeB)],..]) – A graph defined by a list of edges.
maxcardinality (
float
) – Seenetworkx.algorithms.matching.max_weight_matching
.
- Returns
Minimum weight matching in the form of [[nodeA, nodeB],..].
- Return type
-
static
match_blossomv
(edges, num_nodes=0, **kwargs)¶ Finds the minimum-weight matching of a list of
edges
using Blossom V.- Parameters
edges ([[nodeA, nodeB, distance(nodeA,nodeB)],..]) – A graph defined by a list of edges.
- Returns
Minimum weight matching in the form of [[nodeA, nodeB],..].
- Return type
-
static
get_qubit_distances
(qubits, size)¶ Computes the distance between a list of qubits.
On a toric lattice, the shortest distance between two qubits may be one in four directions due to the periodic boundary conditions. The
size
parameters indicates the length in both x and y directions to find the shortest distance in all directions.
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
correct_edge
(ancilla_qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.- Return type
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
-
class
qsurface.decoders.mwpm.sim.
Planar
(code, check_compatibility=False, **kwargs)¶ Minimum-Weight Perfect Matching decoder for the planar lattice.
Additionally to all edges, virtual qubits are added to the boundary, which connect to their main qubits.Edges between all virtual qubits are added with weight zero.
-
decode
(**kwargs)¶ Decodes the surface loaded at
self.code
after all ancilla-qubits have been measured.
-
correct_matching
(syndromes, matching)¶ Applies the matchings as a correction to the code.
-
static
get_qubit_distances
(qubits, *args)¶ Computes the distance between a list of qubits.
On a planar lattice, any qubit can be paired with the boundary, which is inhabited by
PseudoQubit
objects. The graph of syndromes that supports minimum-weight matching algorithms must be fully connected, with each syndrome connecting additionally to its boundary pseudo-qubit, and a fully connected graph between all pseudo-qubits with weight 0.
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
correct_edge
(ancilla_qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.- Return type
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
-
static
match_blossomv
(edges, num_nodes=0, **kwargs)¶ Finds the minimum-weight matching of a list of
edges
using Blossom V.- Parameters
edges ([[nodeA, nodeB, distance(nodeA,nodeB)],..]) – A graph defined by a list of edges.
- Returns
Minimum weight matching in the form of [[nodeA, nodeB],..].
- Return type
-
static
match_networkx
(edges, maxcardinality, **kwargs)¶ Finds the minimum-weight matching of a list of
edges
usingnetworkx.algorithms.matching.max_weight_matching
.- Parameters
edges ([[nodeA, nodeB, distance(nodeA,nodeB)],..]) – A graph defined by a list of edges.
maxcardinality (
float
) – Seenetworkx.algorithms.matching.max_weight_matching
.
- Returns
Minimum weight matching in the form of [[nodeA, nodeB],..].
- Return type
-
match_syndromes
(syndromes, use_blossomv=False, **kwargs)¶ Decodes a list of syndromes of the same type.
A graph is constructed with the syndromes in
syndromes
as nodes and the distances between each of the syndromes as the edges. The distances are dependent on the boundary conditions of the code and is calculated byget_qubit_distances
. A minimum-weight matching is then found by eithermatch_networkx
ormatch_blossomv
.- Parameters
syndromes (
List
[AncillaQubit
]) – Syndromes of the code.use_blossomv (
bool
) – Use external C++ Blossom V library for minimum-weight matching. Needs to be downloaded and compiled by callingget_blossomv
.
- Returns
Minimum-weight matched ancilla-qubits.
- Return type
list of
AncillaQubit
-
Plotting¶
-
class
qsurface.decoders.mwpm.plot.
Toric
(*args, **kwargs)¶ Plot MWPM decoder for the toric code.
- Parameters
args – Positional and keyword arguments are passed on to
decoders._template.Plot
anddecoders.mwpm.sim.Toric
.kwargs – Positional and keyword arguments are passed on to
decoders._template.Plot
anddecoders.mwpm.sim.Toric
.
-
class
qsurface.decoders.mwpm.plot.
Planar
(*args, **kwargs)¶ Plot MWPM decoder for the planar code.
- Parameters
args – Positional and keyword arguments are passed on to
Toric
anddecoders.mwpm.sim.Planar
.kwargs – Positional and keyword arguments are passed on to
Toric
anddecoders.mwpm.sim.Planar
.
- dennis2002
Dennis, Eric and Kitaev, Alexei and Landahl, Andrew and Preskill, John, Topological quantum memory, in Journal of Mathematical Physics, 2002, 43(9)4452-4505.
- wang2003
Wang, Chenyang and Harrington, Jim and Preskill, John, Confinement-Higgs transition in a disordered gauge theory and the accuracy threshold for quantum memory, in Annals of Physics, 2003, 303(1)31-58.
- kolmogorov2009(1,2)
Kolmogorov, Vladimir, Blossom V: A new implementation of a minimum cost perfect matching algorithm in Mathematical Programming Computation (MPC), July 2009, 1(1):43-67.
unionfind¶
The Union-Find decoder.
Information¶
The Union-Find decoder [delfosse2017almost] maps each element of the syndrome \(\sigma\) to an ancilla \(v\) in a non-connected graph defined on the code lattice. From this starting point, it grows clusters around these ancillas by repeatedly adding a layer of edges and ancillas to existing clusters, until all clusters have an even number of non-trivial syndrome ancillas. Then, it selects a spanning tree \(F\) for each cluster.
The leaves of each spanning tree are conditionally peeled in a tail-recursive breadth-first search until all non-trivial syndrome ancillas are paired and linked by a path within \(F\), which is the correcting operator \(\mathcal{C}\) [delfosse2017linear]. The strategy for constructing the clusters turns out to have a strong effect on performance. For instance, the threshold for bitflip noise of a decoder that grows the clusters following a random order is 9.2% [delfosse2017almost], while if the clusters are grown in order of cluster size, which we call Weighted Growth, the threshold increases to 9.9% [delfosse2017almost].
The complexity of the Union-Find decoder is driven by the merging of the clusters. For this, the algorithm uses the Union-Find or disjoint-set data structure [tarjan1975efficiency]. This data structure contains a set of elements, in this case ancillas on the lattice. The set of elements is represented by a two-level tree. At the root of the tree sits one element chosen arbitrarily; the rest of the elements are linked to the root element. The structure admits two functions: \(Find\) and \(Union\). Given \(v\) an element from the structure, the function \(Find(v)\) returns the root element of the tree. This is is used to identify the cluster to which \(v\) belongs. The second function is \(Union(u, v)\), this function merges the sets associated with elements \(u\) and \(v\). This requires pointing all the elements of one of the sets to the root of the other. In order to minimize the number of operations the root of the set with the larger number of elements is chosen as root for the merged set, this is called Weighted Union. In this context, \(Union\) is used when the growth of a cluster requires adding a vertex that belongs to another.
-
class
qsurface.decoders.unionfind.elements.
Cluster
(index, instance, **kwargs)¶ CLuster of
AncillaQubit
objects.A disjoint set, or cluster, of ancilla-qubits. The size of the cluster is equal to the number of qubits in the cluster. The parity of the cluster is equal to the number of non-trivial ancilla-qubits in the cluster.
A cluster can be joined with another by
union
. Joined clusters are stored in the union-find data structure [tarjan1975efficiency]. The representative element or root cluster is returned byfind
.- Parameters
-
bound, new_bound
The current and next boundary of the current cluster.
- Type
list,
[[inner_ancilla, edge, outer_ancilla],...]
-
add_ancilla
(ancilla)¶ Adds an ancilla to a cluster.
-
find
(**kwargs)¶ Finds the representative root cluster.
The function is applied recursively until the root element of the union-find tree is encountered. The representative root element is returned. Path compression is applied to reduce the depth of the tree.
Examples
For joined clusters in the union-find data structure:
cl0 / \ cl1 cl2 / cl2
the representative element can be found by
>>> cl2.find() cl0
- Return type
-
union
(cluster, **kwargs)¶ Merges two clusters.
The
cluster
is made a child of the current cluster. The joined size and parity attributes are updated.- Parameters
cluster (
Cluster
) – The cluster to merge withself
.
Examples
For two clusters
cl0
andcl1
,cl0.union(cl1)
results in the following tree:cl0 / cl1
Simulation¶
The following description also applies to unionfind.sim.Planar
.
-
class
qsurface.decoders.unionfind.sim.
Toric
(*args, **kwargs)¶ Union-Find decoder for the toric lattice.
In this implementation, cluster properties are not stored at the root of the tree. Instead, ancillas are collected within
Cluster
objects, which contain theunion
andfind
methods.Default values for the following parameters can be supplied via a decoders.ini file under the section of
[unionfind]
.The
cluster
andpeeled
attributes are monkey patched to theAncillaQubit
object to assist the identification of its parent cluster and to assist peeling. Theforest
attribute is monkey-patched toAncillaQubit
andEdge
if a dynamic forest is not maintained to assist with the construction of the acyclic forest after cluster growth.- Parameters
weighted_growth (bool, optional) – Enables weighted growth via bucket growth. Default is true. See
grow_clusters
.weighted_union (bool, optional) – Enables weighted union, Default is true. See
union_bucket
.dynamic_forest (bool, optional) – Enables dynamically mainted forests. Default is true.
print_steps (bool, optional) – Prints additional decoding information. Default is false.
kwargs – Keyword arguments are forwarded to
Sim
.
-
support
¶ Dictionary of growth states of all edges in the code.
value
state
2
fully grown
1
half grown
0
none
-1
removed by cycle or peel
-2
added to matching
- Type
-
buckets
¶ Ordered dictionary (by index) for bucket growth (implementation of weighted growth). See
grow_clusters
.- Type
-
decode
(**kwargs)¶ Decodes the code using the Union-Find algorithm.
Decoding process can be subdivided into 3 sections:
Finding the initial clusters.
Growing and merging these clusters.
Peeling the clusters using the Peeling algorithm.
- Parameters
kwargs – Keyword arguments are passed on to
find_clusters
,grow_clusters
andpeel_clusters
.
-
get_cluster
(ancilla)¶ Returns the cluster to which
ancilla
belongs to.If
ancilla
has no cluster or the cluster is not from the current simulation, none is returned. Otherwise, the root element of the cluster-tree is found, updated toancilla.cluster
and returned.- Parameters
ancilla (
AncillaQubit
) – The ancilla for which the cluster is to be found.- Return type
-
cluster_add_ancilla
(cluster, ancilla, parent=None, **kwargs)¶ Recursively adds erased edges to
cluster
and finds the new boundary.For a given
ancilla
, this function finds the neighboring edges and ancillas that are in the the currunt cluster. If the newly found edge is erased, the edge and the corresponding ancilla will be added to the cluster, and the function applied recursively on the new ancilla. Otherwise, the neighbor is added to the new boundaryself.new_bound
.- Parameters
cluster (
Cluster
) – Current active clusterancilla (
AncillaQubit
) – Ancilla from which the connected erased edges or boundary are searched.
-
find_clusters
(**kwargs)¶ Initializes the clusters on the lattice.
For every non-trivial ancilla on the lattice, a
Cluster
is initiated. If any set of ancillas are connected by some set of erased qubits, all connected ancillas are found bycluster_add_ancilla
and a single cluster is initiated for the set.The cluster is then placed into a bucket based on its size and parity by
place_bucket
. Seegrow_clusters
for more information on buckets.
-
grow_clusters
(**kwargs)¶ Grows odd-parity clusters outward for union with others until all clusters are even.
Lists of odd-parity clusters are maintained at
self.buckets
. Starting from bucket 0, odd-parity clusters are popped from the bucket by ‘grow_bucket and grown at the boundary bygrow_boundary
by adding 1 for every boundary edge incluster.bound
inself.support
. Grown clusters are then placed in a new bucket byplace_bucket
based on its size if it has odd parity.Edges are fully added to the cluster per two growth iterations. Since a cluster with half-grown edges at the boundary has the same size (number of ancillas) as before growth, but is non-arguably bigger, the degeneracy in cluster size is differentiated by
cluster.support
. When an union occurs between two clusters during growth, if the merged cluster is odd, it is placed in a new bucket. Thus the real bucket number is saved at the cluster locally ascluster.bucket
. These two checks are performed before a cluster is grown ingrow_bucket
.The chronology of events per bucket must be the following:
Grow all clusters in the bucket if checks passed.
Add all odd-parity clusters after growth to
place_list
.Add all merging clusters to
union_list
.
Merge all clusters in
union_list
Add odd-parity clusters after union to
place_list
.
Place all clusters in
place_list
in new bucket if parity is odd.
For clusters with
cluster.support==1
or with half-grown edges at the boundary, the new boundary atclusters.new_bound
consists of the same half-grown edges. For clusters withcluster.support==0
, the new boundary is found bycluster_add_ancilla
.If weighted_growth is disabled, odd-parity clusters are always placed in
self.buckets[0]
. The same checks forcluster.bucket
andcluster.support
are applied to ensure clusters growth is valid.
-
grow_bucket
(bucket, bucket_i, **kwargs)¶ Grows the clusters which are contained in the current bucket.
See
grow_clusters
for more information.
-
grow_boundary
(cluster, union_list, **kwargs)¶ Grows the boundary of the
cluster
.See
grow_clusters
for more information.- Parameters
cluster (
Cluster
) – The cluster to be grown.union_list (
List
[Tuple
[AncillaQubit
,Edge
,AncillaQubit
]]) – List of potential mergers between two cluster-distinct ancillas.
-
union_bucket
(union_list, **kwargs)¶ Merges clusters in
union_list
if checks are passed.Items in
union_list
consists of[ancillaA, edge, ancillaB]
of two ancillas that, at the time added to the list, were not part of the same cluster. The cluster of an ancilla is stored atancilla.cluster
, but due to cluster mergers the cluster atancilla_cluster
may not be the root element in the cluster-tree, and thus the cluster must be requested byancilla.cluster.
find
. Since the clusters ofancillaA
andancillaB
may have already merged, checks are performed inunion_check
after which the clusters are conditionally merged onedge
byunion_edge
.If
weighted_union
is enabled, the smaller cluster is always made a child of the bigger cluster in the cluster-tree. This ensures the that the depth of the tree is minimized and the future calls tofind
is reduced.If
dynamic_forest
is disabled, cycles within clusters are not immediately removed. The acyclic forest is then later constructed before peeling inpeel_leaf
.- Parameters
union_list (
List
[Tuple
[AncillaQubit
,Edge
,AncillaQubit
]]) – List of potential mergers between two cluster-distinct ancillas.
-
union_check
(edge, ancilla, new_ancilla, cluster, new_cluster)¶ Checks whether
cluster
andnew_cluster
can be joined onedge
.See
union_bucket
for more information.- Return type
-
place_bucket
(clusters, bucket_i)¶ Places all clusters in
clusters
in a bucket if parity is odd.If
weighted_growth
is enabled. the cluster is placed in a new bucket based on its size, otherwise it is placed inself.buckets[0]
-
peel_clusters
(**kwargs)¶ Loops over all clusters to find pendant ancillas to peel.
To make sure that all cluster-trees are fully peeled, all ancillas are considered in the loop. If the ancilla has not been peeled before and belongs to a cluster of the current simulation, the ancilla is considered for peeling by
peel_leaf
.
-
peel_leaf
(cluster, ancilla)¶ Recursive function which peels a branch of the tree if the input ancilla is a pendant ancilla
If there is only one neighbor of the input ancilla that is in the same cluster, this ancilla is a pendant ancilla and can be peeled. The function calls itself on the other ancilla of the edge leaf.
If [“dynamic_forest”] is disabled, once a pendant leaf is found, the acyclic forest is constructed by
static_forest
.- Parameters
cluster – Current cluster being peeled.
ancilla – Pendant ancilla of the edge to be peeled.
-
flip_edge
(ancilla, edge, new_ancilla, **kwargs)¶ Flips the values of the ancillas connected to
edge
.
-
static_forest
(ancilla)¶ Constructs an acyclic forest in the cluster of
ancilla
.Applies recursively to all neighbors of
ancilla
. If a cycle is detected, edges are removed from the cluster.- Parameters
ancilla (
AncillaQubit
) –
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
correct_edge
(ancilla_qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.- Return type
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
-
class
qsurface.decoders.unionfind.sim.
Planar
(*args, **kwargs)¶ Union-Find decoder for the planar lattice.
See the description of
unionfind.sim.Toric
.
Plotting¶
-
class
qsurface.decoders.unionfind.plot.
Toric
(*args, **kwargs)¶ Union-Find decoder for the toric lattice with union-find plot.
Has all class attributes and methods from
unionfind.sim.Toric
, with additional parameters below. Default values for these parameters can be supplied via a decoders.ini file under the section of[unionfind]
(seedecoders._template.read_config
).The plotting class initiates a
qsurface.plot
object. For its usage, see Usage.- Parameters
step_bucket (bool, optional) – Waits for user after every occupied bucket. Default is false.
step_cluster (bool, optional) – Waits for user after growth of every cluster. Default is false.
step_cycle (bool, optional) – Waits for user after every edge removed due to cycle detection. Default is false.
step_peel (bool, optional) – Waits for user after every edge removed during peeling. Default is false.
-
class
Figure2D
(decoder, name, *args, **kwargs)¶ Visualizer for the Union-Find decoder and Union-Find based decoders with perfect measurements.
- Parameters
args – Positional and keyword arguments are forwarded to
plot.Template2D
.kwargs – Positional and keyword arguments are forwarded to
plot.Template2D
.
-
class
Figure3D
(*args, **kwargs)¶ Visualizer for the Union-Find decoder and Union-Find based decoders with faulty measurements.
- Parameters
args – Positional and keyword arguments are forwarded to
Figure2D
andplot.Template3D
.kwargs – Positional and keyword arguments are forwarded to
Figure2D
andplot.Template3D
.
-
class
qsurface.decoders.unionfind.plot.
Planar
(*args, **kwargs)¶ Union-Find decoder for the planar lattice with union-find plot.
Has all class attributes and methods from
unionfind.sim.Planar
, with additional parameters below. Default values for these parameters can be supplied via a decoders.ini file under the section of[unionfind]
(seedecoders._template.read_config
).The plotting class initiates a
qsurface.plot
object. For its usage, see Usage.- Parameters
step_bucket (bool, optional) – Waits for user after every occupied bucket. Default is false.
step_cluster (bool, optional) – Waits for user after growth of every cluster. Default is false.
step_cycle (bool, optional) – Waits for user after every edge removed due to cycle detection. Default is false.
step_peel (bool, optional) – Waits for user after every edge removed during peeling. Default is false.
kwargs – Keyword arguments are passed on to
unionfind.sim.Planar
.
-
class
Figure2D
(decoder, name, *args, **kwargs)¶ Visualizer for the Union-Find decoder and Union-Find based decoders with perfect measurements.
- Parameters
args – Positional and keyword arguments are forwarded to
unionfind.plot.Toric.Figure2D
.kwargs – Positional and keyword arguments are forwarded to
unionfind.plot.Toric.Figure2D
.
-
class
Figure3D
(*args, **kwargs)¶ Visualizer for the Union-Find decoder and Union-Find based decoders with faulty measurements.
- Parameters
args – Positional and keyword arguments are forwarded to
Figure2D
andplot.Template3D
.kwargs – Positional and keyword arguments are forwarded to
Figure2D
andplot.Template3D
.
- delfosse2017almost(1,2,3)
Delfosse, Nicolas and Nickerson, Naomi H., Almost-linear time decoding algorithm for topological codes, arXiv preprint arXiv:1709.06218, 2017.
- delfosse2017linear
Delfosse, Nicolas and Zemor, Gilles, Linear-time maximum likelihood decoding of surface codes over the quantum erasure channel, arXiv preprint arXiv:1703.01517, 2017.
- tarjan1975efficiency(1,2)
Tarjan, Robert, Efficiency of a good but not linear set union algorithm, Journal of the ACM, 22(2)215-225, 1975.
ufns¶
The Union-Find Node-Suspension decoder.
Information¶
The Union-Find Node-Suspension decoder [hu2020thesis] uses the potential matching weight as a heuristic to prioritize growth in specific partitions – the nodes – of the Union-Find cluster (see Information). The potential matching weight is approximated by levering a node-tree in the Node-Suspension Data-structure. The elements of the node-tree are descendent objects of Node
.
The complexity of the algorithm is determined by the calculation of the node parity in ns_parity
, the node delay in ns_delay
, and the growth of the cluster, which is now applied as a recursive function that inspects all nodes in the node tree (ufns.sim.Toric.grow_node
). During cluster mergers, additional to union
, node-trees are joined by join_node_trees
.
Todo
Proper calculation of delay for erasures/empty nodes in the graph
-
class
qsurface.decoders.ufns.elements.
Node
(primer)¶ Element in the node-tree.
A subgraph \(\mathcal{V}\subseteq C\) is a spanning-tree of a cluster \(C\) if it is a connected acyclic subgraph that includes all vertices of \(C\) and a minimum number of edges. We call the spanning-tree of a cluster its ancilla-tree. An acyclic connected spanning-forest is required for the Union-Find Decoder.
A node-tree \(\mathcal{N}\) is a partition of a ancilla-tree \(\mathcal{V}\), such that each element of the partition – which we call a node \(n\) – represents a set of adjacent vertices that lie at the same distance – the node radius :math:`r` – from the *primer ancilla, which initializes the node and lies at its center. The node-tree is a directed acyclic graph, and its edges \(\mathcal{E}_i\) have lengths equal to the distance between the primer vertices of neighboring nodes.
- Parameters
primer (
AncillaQubit
) – Primer ancilla-qubit.
-
parity
¶ Node parity.
- Type
{0,1}
-
abstract
ns_parity
()¶ Calculates and returns the parity of the current node.
-
ns_delay
(parent=None, min_delay=None)¶ Calculates the node delay.
Head recursive function that calculates the delays of the current node and all its descendent nodes.
\[n_d = m_d + \lfloor n_r-m_r \rfloor - (-1)^{n_p} |(n,m)|\]The minimal delay
min_delay
in the tree is maintained as the actual delay is relative to the minimal delay value within the entire node-tree.
-
class
qsurface.decoders.ufns.elements.
Syndrome
(primer)¶ -
ns_parity
(parent_node=None)¶ Calculates the node parity.
Tail recursive function that calculates the parities of the current node and all its descendent nodes.
\[s_p = \big( \sum_{n \in \text{ children of } s} (1+s_p) \big) \bmod 2\]
-
-
class
qsurface.decoders.ufns.elements.
Junction
(primer)¶ -
ns_parity
(parent_node=None)¶ Calculates the node parity.
Tail recursive function that calculates the parities of the current node and all its children.
\[j_p = 1 - \big(\sum_{n \in \text{ children of } j} (1+n_p) \big) \bmod 2.\]
-
-
class
qsurface.decoders.ufns.elements.
OddNode
(*args, **kwargs)¶
-
qsurface.decoders.ufns.elements.
print_tree
(current_node, parent_node=None)¶ Prints the node-tree of
current_node
and its descendents.Utilizes pptree to print a tree of nodes, which requires a list of children elements per node. Since the node-tree is semi-directional (the root can be any element in the tree), we need to traverse the node-tree from
current_node
in all directions except for theparent_node
to find the children attributes for the current direction.
Simulation¶
The following description also applies to ufns.sim.Planar
.
-
class
qsurface.decoders.ufns.sim.
Toric
(*args, **kwargs)¶ Union-Find Node-Suspension decoder for the toric lattice.
Within the combined Union-Find and Node-Suspension data structure, every
Cluster
is partitioned into one or moreNode
objectss. Thenode
attribute is monkey-patched to theAncillaQubit
object to assist the identification of its parentNode
.The boundary of every cluster is not stored at the cluster object, but divided under its partitioned nodes. Cluster growth is initiated from the root of the node-tree. The attributes
root_node
andmin_delay
are monkey-patched to theCluster
object to assist with cluster growth in the Node-Suspension data structure. Seegrow_node
for more.The current class inherits from
unionfind.sim.Toric
for its application the Union-Find data structure for cluster growth and mergers. To maintain low operating complexity in UFNS, the following parameters are set of the Union-Find parent class.parameter
value
weighted_growth
True
weighted_union
True
dynamic_forest
True
-
cluster_add_ancilla
(cluster, ancilla, parent=None, **kwargs)¶ Recursively adds erased edges to
cluster
and finds the new boundary.For a given
ancilla
, this function finds the neighboring edges and ancillas that are in the the currunt cluster. If the newly found edge is erased, the edge and the corresponding ancilla will be added to the cluster, and the function applied recursively on the new ancilla. Otherwise, the neighbor is added to the new boundaryself.new_boundary
.- Parameters
cluster (
Cluster
) – Current active clusterancilla (
AncillaQubit
) – Ancilla from which the connected erased edges or boundary are searched.
-
bound_ancilla_to_node
()¶ Saves the new boundary to their respective nodes.
Saves all the new boundaries found by
cluster_add_ancilla
, which are of the form[inner_ancilla, edge, outer_ancilla]
, to the node atinner_ancilla.node
. This method is called after cluster union inunion_bucket
, which also joins the node-trees, such that the new boundary is saved to the updated nodes.
-
find_clusters
(**kwargs)¶ Initializes the clusters on the lattice.
For every non-trivial ancilla on the lattice, a
Cluster
is initiated. If any set of ancillas are connected by some set of erased qubits, all connected ancillas are found bycluster_add_ancilla
and a single cluster is initiated for the set.Additionally, a syndrome-node is initiated on the non-trivial ancilla – a syndrome – with the ancilla as primer. New boundaries are saved to the nodes by
bound_ancilla_to_node
.The cluster is then placed into a bucket based on its size and parity by
place_bucket
. Seegrow_clusters
for more information on buckets.
-
grow_clusters
(**kwargs)¶ Grows odd-parity clusters outward for union with others until all clusters are even.
Lists of odd-parity clusters are maintained at
self.buckets
. Starting from bucket 0, odd-parity clusters are popped from the bucket by ‘grow_bucket and grown at the boundary bygrow_boundary
by adding 1 for every boundary edge incluster.bound
inself.support
. Grown clusters are then placed in a new bucket byplace_bucket
based on its size if it has odd parity.Edges are fully added to the cluster per two growth iterations. Since a cluster with half-grown edges at the boundary has the same size (number of ancillas) as before growth, but is non-arguably bigger, the degeneracy in cluster size is differentiated by
cluster.support
. When an union occurs between two clusters during growth, if the merged cluster is odd, it is placed in a new bucket. Thus the real bucket number is saved at the cluster locally ascluster.bucket
. These two checks are performed before a cluster is grown ingrow_bucket
.The chronology of events per bucket must be the following:
Grow all clusters in the bucket if checks passed.
Add all odd-parity clusters after growth to
place_list
.Add all merging clusters to
union_list
.
Merge all clusters in
union_list
Add odd-parity clusters after union to
place_list
.
Place all clusters in
place_list
in new bucket if parity is odd.
For clusters with
cluster.support==1
or with half-grown edges at the boundary, the new boundary atclusters.new_bound
consists of the same half-grown edges. For clusters withcluster.support==0
, the new boundary is found bycluster_add_ancilla
.The current implementation of
grow_clusters
for theufns
decoder currently includes a work-around for a non-frequently occuring bug. Since the grown of a cluster is separated into nodes, and nodes may be buried by surrounding cluster trees such that it is an interior element and has no boundaries, it may be possible that when an odd cluster is grown no edges are actually added to the cluster. In this case, due to cluster parity duality the odd cluster will be placed in the same bucket after two rounds of growth. The work-around is to always check if the previous bucket is empty before moving on to the next one.
-
grow_boundary
(cluster, union_list, **kwargs)¶ Grows the boundary of the
cluster
.See
grow_clusters
for more information. Each element in theroot_list
of the root node of thecluster
is a subroot of an even subtree in the node-tree. From each of these subroots, the node parity and delays are calculated byns_parity
andns_delay
. The node-tree is then recursively grown bygrow_node
.- Parameters
cluster (
Cluster
) – The cluster to be grown.union_list (
List
[Tuple
[AncillaQubit
,Edge
,AncillaQubit
]]) – List of odd-parity clusters to be placed in new buckets.
-
grow_node
(cluster, node, union_list, parent_node=None)¶ Recursive function that grows a
node
and its descendents.Grows the boundary list that is stored at the current node if there the current node is not suspended. The condition required is the following:
where \(\mathcal{N}\) is the node-tree. The minimal delay value in the node-tree here stored as
cluster.min_delay
. Fully grown edges are added tounion_list
to be later considered byunion_bucket
.- Parameters
cluster (
Cluster
) – Parent cluster object ofnode
.node (
Node
) – Node to consider for growth.union_list (
List
[Tuple
[AncillaQubit
,Edge
,AncillaQubit
]]) – List of potential mergers between two cluster-distinct ancillas.parent_node (
Optional
[Node
]) – Parent node in the node-tree to indicate recursive direction.
-
grow_node_boundary
(node, union_list)¶ Grows the boundary of a
node
.
-
union_bucket
(union_list, **kwargs)¶ Potentially merges two neighboring ancillas.
If the check by
union_check
is passed, the clusters ofancilla
andnew_ancilla
are merged. additionally, the node-trees either directly joined, or by the creation of a new junction-node which asnew_ancilla
as its primer. Weighted union is applied to ensure low operating complexity.
-
check_compatibility
()¶ Checks compatibility of the decoder with the code class and loaded errors.
-
correct_edge
(ancilla_qubit, key, **kwargs)¶ Applies a correction.
The correction is applied to the data-qubit located at
ancilla_qubit.parity_qubits[key]
. More specifically, the correction is applied to theEdge
object corresponding to thestate_type
ofancilla_qubit
.- Return type
-
decode
(**kwargs)¶ Decodes the code using the Union-Find algorithm.
Decoding process can be subdivided into 3 sections:
Finding the initial clusters.
Growing and merging these clusters.
Peeling the clusters using the Peeling algorithm.
- Parameters
kwargs – Keyword arguments are passed on to
find_clusters
,grow_clusters
andpeel_clusters
.
-
flip_edge
(ancilla, edge, new_ancilla, **kwargs)¶ Flips the values of the ancillas connected to
edge
.
-
get_cluster
(ancilla)¶ Returns the cluster to which
ancilla
belongs to.If
ancilla
has no cluster or the cluster is not from the current simulation, none is returned. Otherwise, the root element of the cluster-tree is found, updated toancilla.cluster
and returned.- Parameters
ancilla (
AncillaQubit
) – The ancilla for which the cluster is to be found.- Return type
-
static
get_neighbor
(ancilla_qubit, key)¶ Returns the neighboring ancilla-qubit of
ancilla_qubit
in the direction ofkey
.- Return type
-
get_neighbors
(ancilla_qubit, loop=False, **kwargs)¶ Returns all neighboring ancillas, including other time instances.
- Parameters
loop (
bool
) – Include neighbors in time that are not chronologically next to each other during decoding within the same instance.
-
get_syndrome
(find_pseudo=False)¶ Finds the syndrome of the code.
- Parameters
find_pseudo (bool, optional) – If enabled, the lists of syndromes returned are not only
AncillaQubit
objects, but tuples of(ancilla, pseudo)
, wherepseudo
is the closestPseudoQubit
in the boundary of the code.- Return type
Union
[Tuple
[List
[AncillaQubit
],List
[AncillaQubit
]],Tuple
[List
[Tuple
[AncillaQubit
,PseudoQubit
]],List
[Tuple
[AncillaQubit
,PseudoQubit
]]]]- Returns
list – Plaquette operator syndromes.
list – Star operator syndromes.
-
grow_bucket
(bucket, bucket_i, **kwargs)¶ Grows the clusters which are contained in the current bucket.
See
grow_clusters
for more information.
-
peel_clusters
(**kwargs)¶ Loops over all clusters to find pendant ancillas to peel.
To make sure that all cluster-trees are fully peeled, all ancillas are considered in the loop. If the ancilla has not been peeled before and belongs to a cluster of the current simulation, the ancilla is considered for peeling by
peel_leaf
.
-
peel_leaf
(cluster, ancilla)¶ Recursive function which peels a branch of the tree if the input ancilla is a pendant ancilla
If there is only one neighbor of the input ancilla that is in the same cluster, this ancilla is a pendant ancilla and can be peeled. The function calls itself on the other ancilla of the edge leaf.
If [“dynamic_forest”] is disabled, once a pendant leaf is found, the acyclic forest is constructed by
static_forest
.- Parameters
cluster – Current cluster being peeled.
ancilla – Pendant ancilla of the edge to be peeled.
-
place_bucket
(clusters, bucket_i)¶ Places all clusters in
clusters
in a bucket if parity is odd.If
weighted_growth
is enabled. the cluster is placed in a new bucket based on its size, otherwise it is placed inself.buckets[0]
-
static_forest
(ancilla)¶ Constructs an acyclic forest in the cluster of
ancilla
.Applies recursively to all neighbors of
ancilla
. If a cycle is detected, edges are removed from the cluster.- Parameters
ancilla (
AncillaQubit
) –
-
union_check
(edge, ancilla, new_ancilla, cluster, new_cluster)¶ Checks whether
cluster
andnew_cluster
can be joined onedge
.See
union_bucket
for more information.- Return type
-
-
class
qsurface.decoders.ufns.sim.
Planar
(*args, **kwargs)¶ Union-Find Node-Suspension decoder for the planar lattice.
See the description of
ufns.sim.Toric
.
Plotting¶
-
class
qsurface.decoders.ufns.plot.
Toric
(*args, **kwargs)¶ Union-Find Node-Suspension decoder for the toric lattice with union-find plot.
Has all class attributes, methods, and nested figure classes from
ufns.sim.Toric
, with additional parameters below. Default values for these parameters can be supplied via a decoders.ini file under the section of[ufns]
(seedecoders._template.read_config
).The plotting class initiates a
qsurface.plot
object. For its usage, see Usage.- Parameters
step_bucket (bool, optional) – Waits for user after every occupied bucket. Default is false.
step_cluster (bool, optional) – Waits for user after growth of every cluster. Default is false.
step_node (bool, optional) – Waits for user after growth of every node. Default is false.
step_cycle (bool, optional) – Waits for user after every edge removed due to cycle detection. Default is false.
step_peel (bool, optional) – Waits for user after every edge removed during peeling. Default is false.
-
class
qsurface.decoders.ufns.plot.
Planar
(*args, **kwargs)¶ Union-Find Node-Suspension decoder for the planar lattice with union-find plot.
Has all class attributes, methods, and nested figure classes from
ufns.sim.Planar
, with additional parameters below. Default values for these parameters can be supplied via a decoders.ini file under the section of[ufns]
(seedecoders._template.read_config
).The plotting class initiates a
qsurface.plot
object. For its usage, see Usage.- Parameters
step_bucket (bool, optional) – Waits for user after every occupied bucket. Default is false.
step_cluster (bool, optional) – Waits for user after growth of every cluster. Default is false.
step_node (bool, optional) – Waits for user after growth of every node. Default is false.
step_cycle (bool, optional) – Waits for user after every edge removed due to cycle detection. Default is false.
step_peel (bool, optional) – Waits for user after every edge removed during peeling. Default is false.
- hu2020thesis
Hu, Mark Shui, Quasilinear Time Decoding Algorithm for Topological Codes with High Error Threshold, DOI: 10.13140/RG.2.2.13495.96162, 2020.
Plotting template¶
Usage¶
Plot objects that inherit from the template plot classes have the following properties.
Fast plotting by use of
matplotlib.canvas.blit
.Redrawing past iterations of the figure by storing all changes in history.
Keyboard navigation for iteration selection.
Plot object information by picking.
When the focus is on the figure, indicated by a green circle in the bottom right corner, the user can navigate through the history of the figure by the commands below.
key |
function |
---|---|
h |
show help |
i |
show all iterations |
enter or right |
go to next iteration, enter iteration number |
backspace or left |
go to previous iteration |
n |
go to newest iteration |
0-9 |
input iteration number |
If the focus is lost, it can be regained by calling template.focus
on the plot object.
Default values for plot properties such as colors and linewidths are saved in a plot.ini file. Any plot property can be overwritten by supplying the override value as a keyword argument during object initialization or a custom plot.ini file in the working directory.
Development¶
-
class
qsurface.plot.
PlotParams
(blocking_wait=- 1, blocking_pick_radius=10, scale_figure_length=10, scale_figure_height=10, scale_font_primary=12, scale_font_secondary=10, scale_3d_layer=8, color_background=1, 1, 1, 0, color_edge=0.8, 0.8, 0.8, 1, color_qubit_edge=0.7, 0.7, 0.7, 1, color_qubit_face=0.95, 0.95, 0.95, 1, color_x_primary=0.9, 0.3, 0.3, 1, color_z_primary=0.5, 0.5, 0.9, 1, color_y_primary=0.9, 0.9, 0.5, 1, color_x_secondary=0.9, 0.7, 0.3, 1, color_z_secondary=0.3, 0.9, 0.3, 1, color_y_secondary=0.9, 0.9, 0.5, 1, color_x_tertiary=0.5, 0.1, 0.1, 1, color_z_tertiary=0.1, 0.1, 0.5, 1, color_y_tertiary=0.9, 0.9, 0.5, 1, alpha_primary=0.35, alpha_secondary=0.5, line_width_primary=1.5, line_width_secondary=3, line_style_primary='solid', line_style_secondary='dashed', line_style_tertiary='dotted', patch_circle_2d=0.1, patch_rectangle_2d=0.1, patch_circle_3d=30, patch_rectangle_3d=30, axis_main=0.075, 0.1, 0.7, 0.85, axis_main_non_interact=0.0, 0.05, 0.8, 0.9, axis_block=0.96, 0.01, 0.03, 0.03, axis_nextbutton=0.85, 0.05, 0.125, 0.05, axis_prevbutton=0.85, 0.12, 0.125, 0.05, axis_legend=0.85, 0.5, 0.125, 0.3, axis_text=0.05, 0.025, 0.7, 0.05, axis_radio=0.85, 0.19, 0.125, 0.125, font_default_size=12, font_title_size=16, font_button_size=12, axis3d_pane_color=1, 1, 1, 0, axis3d_line_color=0, 0, 0, 0.1, axis3d_grid_line_style='dotted', axis3d_grid_line_alpha=0.2)¶ Parameters for the plotting template classes.
Contains all parameters used in inherited objects of
Template2D
andTemplate3D
. The dataclass is initialized with many default values for an optimal plotting experience. But if any parameters should be changed, the user can call the class to create its own instance of plotting paramters, where the altered paramters are supplied as keyword arguments. The instance can be supplied to the plotting class via theplot_params
keyword argument.Examples
See the below example where the background color of the figure is changed to black. Note that we have to inherit from the
Template2D
class.>>> class Plotting(Template2D): ... pass >>> custom_params = PlotParams(color_background = (0,0,0,1)) >>> plot_with_custom_params = Plotting(plot_params=custom_params)
-
load_params
(param_dict)¶ Loads extra plotting parameters.
Additional parameters can be loaded to the dataclass via this method. The additional parameters must be a dictionary where values are stored to the dataclass with the key as attribute name. If the value is a string that equals to any already defined dataclass attribute, the value at the existing attribute is used for the new parameter. See examples.
- Parameters
params_dict – Dictionary or dictionary of dictionaries of additional parameters.
Examples
New parameters can be added to the dataclass. Values of dataclass attributes are used if present.
>>> params = PlotParams() >>> params.alpha_primary 0.35 >>> params.load_params({ ... "new_attr" : "some_value", ... "use_existing" : "alpha_primary", ... }) >>> params.new_attr some_value >>> params.use_existing 0.35
Nested dictionaries will also load existing attribute values.
>>> params.load_params({ ... "category": { ... "new_attr" : "some_value", ... "use_existing" : "alpha_primary", ... } ... }) >>> params.category {"new_attr" : "some_value", "use_existing" : 0.35}
-
-
class
qsurface.plot.
BlockingKeyInput
(*args, **kwargs)¶ Blocking class to receive key presses.
See also
None
Inherited blocking class.
-
class
qsurface.plot.
Template2D
(plot_params=None, projection=None, **kwargs)¶ Template 2D plot object with history navigation.
This template plot object which can either be an interactive figure using the Tkinter backend, or shows each plotting iteration as a separate figure for the IPython
inline
backend. The interactive figure has the following features.Fast plotting by use of “blitting”.
Redrawing past iterations of the figure by storing all changes in history.
Keyboard navigation for iteration selection.
Plot object information by picking.
To instance this class, one must inherit the current class. The existing objects can then be altered by updating their plot properties by
new_properties()
, where the changed properties must be a dictionary with keywords and values corresponding tho the respective matplotlib object. Every change in plot property is stored inself.history_dict
. This allows to undo or redo changes by simply applying the saved changed properties in the dictionary. Fast plotting is enabled by not drawing the figure after every queued change. Instead, each object is draw in the canvas individually after a property change and a series of changes is drawn to the figure when a new plot iteration is requested vianew_iter()
. This is performed by blitting the canvas.Keyboard navigation and picking is enabled by blocking the code via a custom
BlockingKeyInput
class. While the code is blocked, inputs are caught by the blocking class and processed for history navigation or picking navigation. Moving the iteration past the available history allows for the code to continue. The keyboard input is parsed byfocus()
.Default values for plot properties such as colors and linewidths loaded from
PlotParams
. A custom parameter dataclass can be supplied via theplot_params
keyword argument.- Parameters
plot_params (
Optional
[PlotParams
]) – Plotting parameters dataclass containing colors, styles and others.
-
figure
¶ Main figure.
-
main_ax
¶ Main axis of the figure.
- Type
-
history_dict
¶ For each iteration, for every plot object with changed properties, the properties are stored as a nested dictionary. See the example below.
>>> history_dict = { 0: { "<Line2D object>": { "color": "k", }, "<Circle object>": { "linestyle": "-", } } 1: { "<Line2D object>": { "color": "r", }, "<Circle object>": { "linestyle": ":", } } }
-
history_iter_names
¶ List of length
history_iters
containing a title for each iteration.- Type
list of str
-
future_dict
¶ Same as
history_dict
but for changes for future iterations.
-
temporary_changes
¶ Temporary changes for plot properties, requested by
temporary_properties()
, which are immediately drawn to the figure. These properties can be overwritten or undone before a new iteration is requested vianew_iter()
. When a new iteration is requested, we need to find the difference in properties of the queued changes with the current iteration and save all differences toself.history_dict
.
-
temporary_saved
¶ Temporary changes are saved to the current iteration
iter
. Thus when a new iterationiter + 1
is requested, we need to recalculate the differences of the properties initer-1
and the current iteration with the temporary changes. The previous property values when temporary changes are requested bytemporary_properties()
are saved toself.temporary_saved
and used as the property changes foriter-1
.
-
interact_axes
¶ All iteractive elements should have their own axis saved in
self.interact_axes
. Theaxis.active
attribute must be added to define when the axis is shown. If the focus on the figure is lost, all axes inself.interact_axes
are hidden by settingaxis.active=False
.- Type
dict of
matplotlib.axes.Axes
-
interact_bodies
¶ All interactive elements such as buttons, radiobuttons, sliders, should be saved to this dictionary with the same key as their axes in
self.interact_axes
.- Type
Notes
Note all backends support blitting. It does not work with the OSX backend (but does work with other GUI backends on mac).
Examples
A
matplotlib.lines.Line2D
object is initiated withcolor="k"
andls="-"
. We request that the color of the object is red in a new plot iteration.>>> import matplotlib.pyplot as plt ... class Example(Template2D): ... def __init__(self, *args, **kwargs): ... super().__init__(*args, **kwargs) ... self.line = plt.plot(0, 0, color="k", ls="-")[0] # Line located at [0] after plot >>> fig = Example() >>> fig.new_properties(fig.line, {"color": "r}) >>> fig.new_iter() >>> fig.history_dict { 0: {"<Line2D>": {"color": "k"}}, 1: {"<Line2D>": {"color": "r"}}, }
The attribute
self.history_dict
thus only contain changes to plot properties. If we request another iteration but change the linestyle to “:”, the initial linestyle will be saved to iteration 1.>>> fig.new_properties(fig.line, {"ls": ":"}) >>> fig.new_iter() >>> fig.history_dict { 0: {"<Line2D>": {"color": "k"}}, 1: {"<Line2D>": {"color": "r", "ls: "-"}}, 2: {"<Line2D>": {ls: ":"}}, }
We temporarily alter the linewidth to 2, and then to 1.5. After we are satisfied with the temporary changes. we request a new iteration with the final change of color to green.
>>> fig.temporary_properties(fig.line, {"lw": 2}) >>> fig.temporary_properties(fig.line, {"lw": 1.5}) >>> fig.temporary_changes {"<Line2D>": {"lw": 1.5}} >>> fig.temporary_saved {"<Line2D>": {"lw": 1}} # default value >>> fig.new_properties(fig.line, {"color": "g"}) >>> fig.new_iter() >>> fig.history_dict { 0: {"<Line2D>": {"color": "k"}}, 1: {"<Line2D>": {"color": "r", "ls: "-", "lw": 1}}, 2: {"<Line2D>": {"lw": 1.5, color": "r"}, 3: {"<Line2D>": {"color": "g"}}, }
Properties in
self.temporary_saved
are saved toself.history_dict
in the previous iteration, properties inself.temporary_changes
are saved to the current iteration, and new properties are saved to the new iteration.The
history_dict
for a plot with a Line2D object and a Circle object. In the second iteration, the color of the Line2D object is updated from black to red, and the linestyle of the Circle object is changed from “-” to “:”.-
load_interactive_backend
()¶ Configures the plotting backend.
If the Tkinter backend is enabled or can be enabled, the function returns True. For other backends False is returned.
- Return type
-
close
()¶ Closes the figure.
-
focus
()¶ Enables the blocking object, catches input for history navigation.
The BlockingKeyInput object is called which blocks the execution of the code. During this block, the user input is received by the blocking object and return to the current method. From here, we can manipulate the plot or move through the plot history and call
focus()
again when all changes in the history have been drawn and blit.key
function
h
show help
i
show all iterations
d
redraw current iteration
enter or right
go to next iteration, enter iteration number
backspace or left
go to previous iteration
n
go to newest iteration
0-9
input iteration number
When the method is active, the focus is on the figure. This will be indicated by a green circle in the bottom right of the figure. When the focus is lost, the code execution is continued and the icon is red. The change is icon color is performed by
_set_figure_state()
, which also hides the interactive elements when the focus is lost.
-
draw_figure
(new_iter_name=None, output=True, carriage_return=False, **kwargs)¶ Draws the canvas and blocks code execution.
Draws the queued plot changes onto the canvas and calls for
focus()
which blocks the code execution and catches user input for history navigation.If a new iteration is called by supplying a
new_iter_name
, we additionally check for future property changes in theself.future_dict
, and add these changes to the queue. Finally, all queued property changes for the next iteration are applied bychange_properties
.- Parameters
See also
-
new_artist
(artist, axis=None)¶ Adds a new artist to the
axis
.Newly added artists must be hidden in the previous iteration. To make sure the history is properly logged, the visibility of the
artist
is set toFalse
, and a new property of shown visibility is added to the queue of the next iteration.
-
static
change_properties
(artist, prop_dict)¶ Changes the plot properties and draw the plot object or artist.
-
new_properties
(artist, properties, saved_properties={}, **kwargs)¶ Parses a dictionary of property changes of a matplotlib artist.
New properties are supplied via
properties
. If any of the new properties is different from its current value, this is seen as a property change. The old property value is stored inself.history_dict[self.history_iteration]
, and the new property value is stored atself.history_dict[self.history_iteration+1]
. These new properties are queued for the next interation. The queue is emptied by applying all changes whendraw_figure
is called. If the same property changes 2+ times within the same iteration, the previous property change is removed withnext_prop.pop(key, None)
.The
saved_properties
parameter is used when temporary property changes have been applied bytemporary_changes
, in which the original properties are saved toself.temporary_saved
as the saved properties. Before a new iteration is drawn, the temporary changes, which can be overwritten, are compared with the saved changes and the differences in properties are saved to[self.history_dict[self.history_iter-1]]
andself.history_dict[self.history_iteration]
.Some color values from different matplotlib objects are nested, some are list or tuple, and others may be a
numpy.ndarray
. The nested methodsget_nested()
andget_nested_property()
make sure that the return type is always a list.
-
temporary_properties
(artist, properties, **kwargs)¶ Applies temporary property changes to a matplotlib artist.
Only available on the newest iteration, as we cannot change what is already in the past. All values in
properties
are immediately applied toartist
. Since temporary changes can be overwritten within the same iteration, the first time a temporary property change is requested, the previous value is saved toself.temporary_saved
. When the iteration changes, the property differences of the previous and current iteration are recomputed and saved toself.history_dict
in_draw_from_history()
.
-
class
qsurface.plot.
Template3D
(*args, **kwargs)¶ Template 3D plot object with history navigation.
License¶
BSD 3-Clause License
Copyright (c) 2020, Shui Hu All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.