Gate-wise Error Models#
The GatewiseModel
is an error_model
that allows users to design error models where gates can be applied according
to classical probability distributions that are specified for individual ideal gates or groups of ideal gates. To being
we write the following:
>>> import pecos as pc
>>> myerrors = pc.error_models.GatewiseModel()
To randomly add an to classical probability distributions that are specified for individual ideal gates or groups of ideal gates. To being we write the following:
>>> import pecos as pc
>>> myerrors = pc.error_models.GatewiseModel()
To randomly add an to classical probability distributions that are specified for individual ideal gates or groups of ideal gates. To being we write the following:
>>> import pecos as pc
>>> myerrors = pc.error_models.GatewiseModel()
To randomly add an to classical probability distributions that are specified for individual ideal gates or groups of ideal gates. To being we write the following:
>>> import pecos as pc
>>> myerrors = pc.error_models.GatewiseModel()
To randomly add an to classical probability distributions that are specified for individual ideal gates or groups of ideal gates. To being we write the following:
>>> import pecos as pc
>>> myerrors = pc.error_models.GatewiseModel()
To randomly add an \(X\) error after every Hadamard we write:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("H", "X")
Here, the probability of a \(X\) error occurring will, by default, equal to the value of the key 'p'
in an
error_params
dictionary that is passed to the run_logic
method of a circuit_runner
.
To test the error model we are creating, we can use the get_gate_error
method to generate errors. The first argument
of the method is the ideal gate-symbol. The second, is a set of qudit locations the errors may occur on. The third, is a
error_params
dictionary used to specify the probability of errors. An example of using this method is seen here:
>>> # Continuing from last example.
>>> myerrors.get_gate_error("H", {0, 1, 2, 3, 4}, error_params={"p": 0.5})
(QuantumCircuit([{'X': {0, 1, 3}}]), QuantumCircuit([]), set())
Here, the method returns a tuple. The first element is the error circuit that is applied after the ideal gates. The second, before the ideal gates. The third element is the set of qudit locations corresponding to gate locations of ideal gates to be removed from the ideal quantum-circuit.
Note, by default errors specified by the set_gate_error
method will be generated after the ideal quantum-gates. To
generate errors before the gates, one can set the keyword after
to False
when using the add_gate_error
method.
The probability-parameter used (default being 'p'
) can be changed by using the keyword error_param
:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("H", "X", error_param="q", after=False)
>>> myerrors.get_gate_error("H", {0, 1, 2, 3, 4}, error_params={"q": 0.5})
(QuantumCircuit([]), QuantumCircuit([{'X': {0, 3}}]), set())
Here we used the keyword``error_param`` to declare that 'q'
will be used to set the probability of an \(X\)
error occurring. We also see an example of the keyword after
being used to indicate that errors should be applied
before the ideal gates rather than after.
Besides specifying errors of a single gate-type, we can declare a set of errors to be uniformly drawn from:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("X", {"X", "Y", "S"}, error_param="r")
>>> myerrors.get_gate_error("X", {0, 1, 2, 3, 4}, error_params={"r": 0.5})
(QuantumCircuit([{'S': {3, 4}}]), QuantumCircuit([]), set())
Such uniform error-distributions can be made for two-qubit gates as well:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("CNOT", {("I", "X"), ("X", "X"), "CNOT"}, error_param="r")
>>> myerrors.get_gate_error("CNOT", {(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)}, error_params={"r": 0.8})
(QuantumCircuit([{'CNOT': {(0, 1), (4, 5), (8, 9)}, 'X': {3, 6, 7}, 'I': {2}}]), QuantumCircuit([]),
set())
Here we see that two-qubit gates or tuples of single-qubit gates can be supplied as errors.
Other distributions besides the uniform distribution can be specified by passing a callable, such as a function or a method. An example is seen in the following:
>>> # Continuing from last example.
>>> import random
>>> def error_func(after, before, replace, location, error_params):
... s = error_params["s"]
... rand = random.triangular(0, 1, 0.6)
... if rand < 0.6:
... err = "Q"
... elif rand < 0.7:
... err = "S"
... else:
... err = "R"
... before.update(err, {location}, emptyappend=True)
...
Here, callables that are used to create unique error distributions must take the arguments after
, before
,
replace
, location
, and error_params
. The variables after
and before
are QuantumCircuits
representing the errors that are applied after and before the ideals gates of a single tick, respectively. The variable
replace
is the set of qubit gate-locations of the ideals gates to be removed from the ideal quantum-circuit. These
callables are called only if error occurs according to the probability of an associated error parameter, which we will
see later how to set. The location
variable is the qudit index or tuple of qudit indices where the error has
occurred. The variable error_params
is the dictionary of error parameters that are being used to determine the
probability distribution of errors. In the above callable, we see a triangular distribution being used to apply quantum
errors. Note that the callable is responsible for updating QuantumCircuits
after
, before
, replace
as
appropriate.
To use callables to generate errors, we can call the set_gate_error
method in the following manner:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("Y", error_func, error_param="s")
>>> myerrors.get_gate_error("Y", {0, 1, 2, 3, 4}, error_params={"s": 0.5})
(QuantumCircuit([]), QuantumCircuit([{'R': {0, 4}, 'Q': {1, 2}}]), set())
Here we set the probability of error_func
being called to generate errors using the error_params
keyword
argument.
There are two special gate-symbols for which error distributions can be assigned to. These special symbols are
'data'
and 'idle'
. The error distribution associated with 'data'
is used to generate errors at the beginning
of each LogicalInstruction
for each data qudit. An error distribution associated with the 'idle'
symbol is used
to generate errors whenever a qubit is not acted on by a quantum operation during a LogicalCircuit
.
An example of setting the errors of a 'data'
and 'idle'
can see here:
>>> # Continuing from last example.
>>> myerrors.set_gate_error("data", "X", error_param="q")
>>> myerrors.set_gate_error("idle", "Y", error_param="s")
Besides specifying errors for individual gate-types, one can specify errors for a group of gates. To do this one may define a gate group and set the error distribution for this group:
>>> # Continuing from last example.
>>> myerrors.set_gate_group("measurements", {"measure X", "measure Y", "measure Z"})
>>> myerrors.set_group_error("measurements", {"X", "Y", "Z"}, error_param="m")
Note, set_group_error
will override the error distribution of any gate belonging to the gate group.
The gate groups that are defined by default can be found by running:
>>> newerrors = pc.error_models.GatewiseModel()
>>> newerrors.gate_groups
{'measurements': {'measure X', 'measure Y', 'measure Z'},
'inits': {'init |+>', 'init |+i>', 'init |->', 'init |-i>', 'init |0>', 'init |1>'},
'two_qubits': {'CNOT', 'CZ', 'G', 'SWAP'},
'one_qubits': {'F1', 'F1d', 'F2', 'F2d', 'F3', 'F3d', 'F4', 'F4d', 'H', 'H+y-z', 'H+z+x', 'H-x+y', 'H-x-y', 'H-y-z',
'H-z-x', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I', 'Q', 'Qd', 'R', 'Rd', 'S', 'Sd', 'X', 'Y', 'Z'}}
Here the keys are symbols representing the gate groups and the values are the set of gate symbols belong to the corresponding gate group. These gate groups (
The gate groups that are defined by default can be found by running:
>>> newerrors = pc.error_models.GatewiseModel()
>>> newerrors.gate_groups
{'measurements': {'measure X', 'measure Y', 'measure Z'},
'inits': {'init |+>', 'init |+i>', 'init |->', 'init |-i>', 'init |0>', 'init |1>'},
'two_qubits': {'CNOT', 'CZ', 'G', 'SWAP'},
'one_qubits': {'F1', 'F1d', 'F2', 'F2d', 'F3', 'F3d', 'F4', 'F4d', 'H', 'H+y-z', 'H+z+x', 'H-x+y', 'H-x-y', 'H-y-z',
'H-z-x', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I', 'Q', 'Qd', 'R', 'Rd', 'S', 'Sd', 'X', 'Y', 'Z'}}
Here the keys are symbols representing the gate groups and the values are the set of gate symbols belong to the corresponding gate group. These gate groups (
The gate groups that are defined by default can be found by running:
>>> newerrors = pc.error_models.GatewiseModel()
>>> newerrors.gate_groups
{'measurements': {'measure X', 'measure Y', 'measure Z'},
'inits': {'init |+>', 'init |+i>', 'init |->', 'init |-i>', 'init |0>', 'init |1>'},
'two_qubits': {'CNOT', 'CZ', 'G', 'SWAP'},
'one_qubits': {'F1', 'F1d', 'F2', 'F2d', 'F3', 'F3d', 'F4', 'F4d', 'H', 'H+y-z', 'H+z+x', 'H-x+y', 'H-x-y', 'H-y-z',
'H-z-x', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I', 'Q', 'Qd', 'R', 'Rd', 'S', 'Sd', 'X', 'Y', 'Z'}}
Here the keys are symbols representing the gate groups and the values are the set of gate symbols belong to the corresponding gate group. These gate groups (
The gate groups that are defined by default can be found by running:
>>> newerrors = pc.error_models.GatewiseModel()
>>> newerrors.gate_groups
{'measurements': {'measure X', 'measure Y', 'measure Z'},
'inits': {'init |+>', 'init |+i>', 'init |->', 'init |-i>', 'init |0>', 'init |1>'},
'two_qubits': {'CNOT', 'CZ', 'G', 'SWAP'},
'one_qubits': {'F1', 'F1d', 'F2', 'F2d', 'F3', 'F3d', 'F4', 'F4d', 'H', 'H+y-z', 'H+z+x', 'H-x+y', 'H-x-y', 'H-y-z',
'H-z-x', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I', 'Q', 'Qd', 'R', 'Rd', 'S', 'Sd', 'X', 'Y', 'Z'}}
Here the keys are symbols representing the gate groups and the values are the set of gate symbols belong to the corresponding gate group. These gate groups (
The gate groups that are defined by default can be found by running:
>>> newerrors = pc.error_models.GatewiseModel()
>>> newerrors.gate_groups
{'measurements': {'measure X', 'measure Y', 'measure Z'},
'inits': {'init |+>', 'init |+i>', 'init |->', 'init |-i>', 'init |0>', 'init |1>'},
'two_qubits': {'CNOT', 'CZ', 'G', 'SWAP'},
'one_qubits': {'F1', 'F1d', 'F2', 'F2d', 'F3', 'F3d', 'F4', 'F4d', 'H', 'H+y-z', 'H+z+x', 'H-x+y', 'H-x-y', 'H-y-z',
'H-z-x', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I', 'Q', 'Qd', 'R', 'Rd', 'S', 'Sd', 'X', 'Y', 'Z'}}
Here the keys are symbols representing the gate groups and the values are the set of gate symbols belong to the
corresponding gate group. These gate groups ('measurements'
, 'inits'
, 'two_qubits'
, and 'one_qubits'
)
can be redefined by the user.
Example: The Symmetric Depolarizing-channel#
As an example, the circuit-level symmetric depolarizing-channel is modeled by DepolarGen
as discussed in
this page, can be represented by the GatewiseModel
class as follows:
depolar_circuit = pc.error_models.GatewiseModel()
set_gate_group("Xinit", {"init |+>", "init |->"})
set_gate_group("Yinit", {"init |+i>", "init |-i>"})
set_gate_group("Zinit", {"init |0>", "init |1>"})
depolar_circuit.set_group_error("Xinit", "Z")
depolar_circuit.set_group_error("Yinit", "Z")
depolar_circuit.set_group_error("Zinit", "X")
depolar_circuit.set_gate_error("measure X", "Z", after=False)
depolar_circuit.set_gate_error("measure Y", "Z", after=False)
depolar_circuit.set_gate_error("measure Z", "X", after=False)
depolar_circuit.set_group_error("one_qubits", {"X", "Y", "Z"})
depolar_circuit.set_group_error(
"two_qubits",
{
("I", "X"),
("I", "Y"),
("I", "Z"),
("X", "I"),
("X", "X"),
("X", "Y"),
("X", "Z"),
("Y", "I"),
("Y", "X"),
("Y", "Y"),
("Y", "Z"),
("Z", "I"),
("Z", "X"),
("I", "Y"),
("Z", "Z"),
},
)
Example: The Amplitude-dampening Channel#
The stochastic circuit-level amplitude-dampening channel can be described as:
amp_damp = pc.error_models.GatewiseModel()
amp_damp.set_group_error("inits", "init |0>")
amp_damp.set_gate_error("measurements", "init |0>", after=False)
amp_damp.set_group_error("one_qubits", "init |0>")
amp_damp.set_group_error("two_qubits", {("I", "init |0>"), ("init |0>", "I"), ("init |0>", "init |0>")})