netqasm.sdk.epr_socket
EPR Socket interface.
- class netqasm.sdk.epr_socket.EPRSocket(remote_app_name, epr_socket_id=0, remote_epr_socket_id=0, min_fidelity=100)
Bases:
ABCEPR socket class. Used to generate entanglement with a remote node.
An EPR socket represents a connection with a single remote node through which EPR pairs can be generated. Its main interfaces are the create and recv methods. A typical use case for two nodes is that they both create an EPR socket to the other node, and during the protocol, one of the nodes does create operations on its socket while the other node does recv operations.
A create operation asks the network stack to initiate generation of EPR pairs with the remote node. Depending on the type of generation, the result of this operation can be qubit objects or measurement outcomes. A recv operation asks the network stack to wait for the remote node to initiate generation of EPR pairs. Again, the result can be qubit objects or measurement outcomes.
Each create operation on one node must be matched by a recv operation on the other node. Since “creating” and “receiving” must happen at the same time, a node that is doing a create operation on its socket cannot advance until the other node does the corresponding recv. This is different from classical network sockets where a “send” operation (roughly anologous to create in an EPR socket) does not block on the remote node receiving it.
An EPR socket is identified by a triple consisting of (1) the remote node ID, (2) the local socket ID and (3) the remote socket ID. Two nodes that want to generate EPR pairs with each other should make sure that the IDs in their local sockets match.
- Parameters:
remote_app_name (
str)epr_socket_id (
int)remote_epr_socket_id (
int)min_fidelity (
int)
- __init__(remote_app_name, epr_socket_id=0, remote_epr_socket_id=0, min_fidelity=100)
Create an EPR socket. It still needs to be registered with the network stack separately.
Registering and opening the EPR socket is currently done automatically by the connection that uses this EPR socket, specifically when a context is opened with that connection.
- Parameters:
remote_app_name (
str) – name of the remote party (i.e. the role, like “client”, not necessarily the node name like “delft”)epr_socket_id (
int) – local socket ID, defaults to 0remote_epr_socket_id (
int) – remote socket ID, defaults to 0. Note that this must match with the local socket ID of the remote node’s EPR socket.min_fidelity (
int) – minimum desired fidelity for EPR pairs generated over this socket, in percentages (i.e. range 0-100). Defaults to 100.
- property conn: BaseNetQASMConnection
Get the underlying
NetQASMConnection
- property remote_app_name: str
Get the remote application name
- property remote_node_id: int
Get the remote node ID
- property epr_socket_id: int
Get the EPR socket ID
- property remote_epr_socket_id: int
Get the remote EPR socket ID
- property min_fidelity: int
Get the desired minimum fidelity
- create_keep(number=1, post_routine=None, sequential=False, time_unit=TimeUnit.MICRO_SECONDS, max_time=0, min_fidelity_all_at_end=None, max_tries=None)
Ask the network stack to generate EPR pairs with the remote node and keep them in memory.
A create_keep operation must always be matched by a recv_keep operation on the remote node.
If sequential is False (default), this operation returns a list of Qubit objects representing the local qubits that are each one half of the generated pairs. These qubits can then be manipulated locally just like locally initialized qubits, by e.g. applying gates or measuring them. Each qubit also contains information about the entanglement generation that lead to its creation, and can be accessed by its entanglement_info property.
A typical example for just generating one pair with another node would be:
q = epr_socket.create_keep()[0] # `q` can now be used as a normal qubit
If sequential is False (default), the all requested EPR pairs are generated at once, before returning the results (qubits or entanglement info objects).
If sequential is True, a callback function (post_routine) should be specified. After generating one EPR pair, this callback will be called, before generating the next pair. This method can e.g. be used to generate many EPR pairs (more than the number of physical qubits available), by measuring (and freeing up) each qubit before the next pair is generated.
For example:
outcomes = alice.new_array(num) def post_create(conn, q, pair): q.H() outcome = outcomes.get_future_index(pair) q.measure(outcome) epr_socket.create_keep(number=num, post_routine=post_create, sequential=True)
- Parameters:
number (
int) – number of EPR pairs to generate, defaults to 1post_routine (
Optional[Callable]) – callback function for each genated pair. Only used if sequential is True. The callback should take three arguments (conn, q, pair) where * conn is the connection (e.g. self) * q is the entangled qubit (of type FutureQubit) * pair is a register holding which pair is handled (0, 1, …)sequential (
bool) – whether to use callbacks after each pair, defaults to Falsetime_unit (
TimeUnit) – which time unit to use for the max_time parametermax_time (
int) – maximum number of time units (see time_unit) the Host is willing to wait for entanglement generation of a single pair. If generation does not succeed within this time, the whole subroutine that this request is part of is reset and run again by the quantum node controller.min_fidelity_all_at_end (
Optional[int]) – the minimum fidelity that all entangled qubits should ideally still have at the moment the last qubit has been generated. For example, when specifying number=2 and min_fidelity_all_at_end=80, the the program will automatically try to make sure that both qubits have a fidelity of at least 80% when the second qubit has been generated. It will attempt to do this by automatically re-trying the entanglement generation if the fidelity constraint is not satisfied. This is however an attempt, and not a guarantee!.max_tries (
Optional[int]) – maximum number of re-tries should be made to try and achieve the min_fidelity_all_at_end constraint.
- Return type:
list[Qubit]- Returns:
list of qubits created
- create_keep_with_info(number=1, post_routine=None, sequential=False, time_unit=TimeUnit.MICRO_SECONDS, max_time=0, min_fidelity_all_at_end=None)
Same as create_keep but also return the EPR generation information coming from the network stack.
For more information see the documentation of create_keep.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1post_routine (
Optional[Callable])sequential (
bool)time_unit (
TimeUnit)max_time (
int)min_fidelity_all_at_end (
Optional[int])
- Return type:
tuple[list[Qubit],list[EprKeepResult]]- Returns:
tuple with (1) list of qubits created, (2) list of EprKeepResult objects
- create_measure(number=1, time_unit=TimeUnit.MICRO_SECONDS, max_time=0, basis_local=None, basis_remote=None, rotations_local=(0, 0, 0), rotations_remote=(0, 0, 0), random_basis_local=None, random_basis_remote=None, rotation_axes_local=QubitMeasureAxes.XYX, rotation_axes_remote=QubitMeasureAxes.XYX)
Ask the network stack to generate EPR pairs with the remote node and measure them immediately (on both nodes).
A create_measure operation must always be matched by a recv_measure operation on the remote node.
This operation returns a list of Linklayer response objects. These objects contain information about the entanglement generation and includes the measurement outcome and basis used. Note that all values are Future objects. This means that the current subroutine must be flushed before the values become defined.
An example for generating 10 pairs with another node that are immediately measured:
# list of Futures that become defined when subroutine is flushed outcomes = [] with NetQASMConnection("alice", epr_sockets=[epr_socket]): ent_infos = epr_socket.create(number=10, tp=EPRType.M) for ent_info in ent_infos: outcomes.append(ent_info.measurement_outcome)
The basis to measure in can also be specified. There are 3 ways to specify a basis:
using one of the EprMeasBasis variants
by specifying 3 rotation angles, interpreted as three sequential rotations around the axes specified through rotation_axes_local and rotation_axes_remote. For example, setting rotations_local to (8, 0, 0) with rotation_axes_local set to XYX means that before measuring, an X-rotation of 8*pi/16 = pi/2 radians is applied to the qubit.
using one of the RandomBasis variants, in which case one of the bases of that variant is chosen at random just before measuring
NOTE: the node that initiates the entanglement generation, i.e. the one that calls create on its EPR socket, also controls the measurement bases of the receiving node (by setting e.g. rotations_remote). The receiving node cannot change this.
- Parameters:
number (
int) – number of EPR pairs to generate, defaults to 1time_unit (
TimeUnit) – which time unit to use for the max_time parametermax_time (
int) – maximum number of time units (see time_unit) the Host is willing to wait for entanglement generation of a single pair. If generation does not succeed within this time, the whole subroutine that this request is part of is reset and run again by the quantum node controller.basis_local (
Optional[EprMeasBasis]) – basis to measure in on this node for M-type requestsbasis_remote (
Optional[EprMeasBasis]) – basis to measure in on the remote node for M-type requestsrotations_local (
tuple[int,int,int]) – rotations to apply before measuring on this noderotations_remote (
tuple[int,int,int]) – rotations to apply before measuring on remote noderandom_basis_local (
Optional[RandomBasis]) – random bases to choose from when measuring on this noderandom_basis_remote (
Optional[RandomBasis]) – random bases to choose from when measuring on the remote noderotation_axes_local (
QubitMeasureAxes) – Sequence of axes to rotate around before measuring on the local noderotation_axes_remote (
QubitMeasureAxes) – Sequence of axes to rotate around before measuring on the remote node
- Return type:
list[EprMeasureResult]- Returns:
list of entanglement info objects per created pair.
- create_rsp(number=1, time_unit=TimeUnit.MICRO_SECONDS, max_time=0, basis_local=None, rotations_local=(0, 0, 0), random_basis_local=None, min_fidelity_all_at_end=None, max_tries=None, rotation_axes_local=QubitMeasureAxes.XYX)
Ask the network stack to do remote preparation with the remote node.
A create_rsp operation must always be matched by a recv_epr operation on the remote node.
This operation returns a list of Linklayer response objects. These objects contain information about the entanglement generation and includes the measurement outcome and basis used. Note that all values are Future objects. This means that the current subroutine must be flushed before the values become defined.
An example for generating 10 pairs with another node that are immediately measured:
m: LinkLayerOKTypeM = epr_socket.create_rsp(tp=EPRType.R)[0] print(m.measurement_outcome) # remote node now has a prepared qubit
The basis to measure in can also be specified. There are 3 ways to specify a basis:
using one of the EprMeasBasis variants
by specifying 3 rotation angles, interpreted as three sequential rotations around the axes specified through rotation_axes_local. For example, setting rotations_local to (8, 0, 0) with rotation_axes_local set to XYX means that before measuring, an X-rotation of 8*pi/16 = pi/2 radians is applied to the qubit.
using one of the RandomBasis variants, in which case one of the bases of that variant is chosen at random just before measuring
- Parameters:
number (
int) – number of EPR pairs to generate, defaults to 1time_unit (
TimeUnit) – which time unit to use for the max_time parametermax_time (
int) – maximum number of time units (see time_unit) the Host is willing to wait for entanglement generation of a single pair. If generation does not succeed within this time, the whole subroutine that this request is part of is reset and run again by the quantum node controller.basis_local (
Optional[EprMeasBasis]) – basis to measure in on this node for M-type requestsrotations_local (
tuple[int,int,int]) – rotations to apply before measuring on this noderandom_basis_local (
Optional[RandomBasis]) – random bases to choose from when measuring on this nodemin_fidelity_all_at_end (
Optional[int]) – the minimum fidelity that all entangled qubits should ideally still have at the moment the last qubit has been generated. For example, when specifying number=2 and min_fidelity_all_at_end=80, the the program will automatically try to make sure that both qubits have a fidelity of at least 80% when the second qubit has been generated. It will attempt to do this by automatically re-trying the entanglement generation if the fidelity constraint is not satisfied. This is however an attempt, and not a guarantee!.max_tries (
Optional[int]) – maximum number of re-tries should be made to try and achieve the min_fidelity_all_at_end constraint.rotation_axes_local (
QubitMeasureAxes) – Sequence of axes to rotate around before measuring on the local node
- Return type:
list[EprMeasureResult]- Returns:
list of entanglement info objects per created pair.
- create(number=1, post_routine=None, sequential=False, tp=EPRType.K, time_unit=TimeUnit.MICRO_SECONDS, max_time=0, basis_local=None, basis_remote=None, rotations_local=(0, 0, 0), rotations_remote=(0, 0, 0), random_basis_local=None, random_basis_remote=None, rotation_axes_local=QubitMeasureAxes.XYX, rotation_axes_remote=QubitMeasureAxes.XYX)
Ask the network stack to generate EPR pairs with the remote node.
A create operation must always be matched by a recv operation on the remote node.
If the type of request is Create and Keep (CK, or just K) and if sequential is False (default), this operation returns a list of Qubit objects representing the local qubits that are each one half of the generated pairs. These qubits can then be manipulated locally just like locally initialized qubits, by e.g. applying gates or measuring them. Each qubit also contains information about the entanglement generation that lead to its creation, and can be accessed by its entanglement_info property.
A typical example for just generating one pair with another node would be:
q = epr_socket.create()[0] # `q` can now be used as a normal qubit
If the type of request is Measure Directly (MD, or just M), this operation returns a list of Linklayer response objects. These objects contain information about the entanglement generation and includes the measurement outcome and basis used. Note that all values are Future objects. This means that the current subroutine must be flushed before the values become defined.
An example for generating 10 pairs with another node that are immediately measured:
# list of Futures that become defined when subroutine is flushed outcomes = [] with NetQASMConnection("alice", epr_sockets=[epr_socket]): ent_infos = epr_socket.create(number=10, tp=EPRType.M) for ent_info in ent_infos: outcomes.append(ent_info.measurement_outcome)
For “Measure Directly”-type requests, the basis to measure in can also be specified. There are 3 ways to specify a basis:
using one of the EprMeasBasis variants
by specifying 3 rotation angles, interpreted as three sequential rotations around the axes specified through rotation_axes_local and rotation_axes_remote. For example, setting rotations_local to (8, 0, 0) with rotation_axes_local set to XYX means that before measuring, an X-rotation of 8*pi/16 = pi/2 radians is applied to the qubit.
using one of the RandomBasis variants, in which case one of the bases of that variant is chosen at random just before measuring
NOTE: the node that initiates the entanglement generation, i.e. the one that calls create on its EPR socket, also controls the measurement bases of the receiving node (by setting e.g. rotations_remote). The receiving node cannot change this.
If sequential is False (default), the all requested EPR pairs are generated at once, before returning the results (qubits or entanglement info objects).
If sequential is True, a callback function (post_routine) should be specified. After generating one EPR pair, this callback will be called, before generating the next pair. This method can e.g. be used to generate many EPR pairs (more than the number of physical qubits available), by measuring (and freeing up) each qubit before the next pair is generated.
For example:
outcomes = alice.new_array(num) def post_create(conn, q, pair): q.H() outcome = outcomes.get_future_index(pair) q.measure(outcome) epr_socket.create(number=num, post_routine=post_create, sequential=True)
- Parameters:
number (
int) – number of EPR pairs to generate, defaults to 1post_routine (
Optional[Callable]) – callback function for each genated pair. Only used if sequential is True. The callback should take three arguments (conn, q, pair) where * conn is the connection (e.g. self) * q is the entangled qubit (of type FutureQubit) * pair is a register holding which pair is handled (0, 1, …)sequential (
bool) – whether to use callbacks after each pair, defaults to Falsetp (
EPRType) – type of entanglement generation, defaults to EPRType.K. Note that corresponding recv of the remote node’s EPR socket must specify the same type.time_unit (
TimeUnit) – which time unit to use for the max_time parametermax_time (
int) – maximum number of time units (see time_unit) the Host is willing to wait for entanglement generation of a single pair. If generation does not succeed within this time, the whole subroutine that this request is part of is reset and run again by the quantum node controller.basis_local (
Optional[EprMeasBasis]) – basis to measure in on this node for M-type requestsbasis_remote (
Optional[EprMeasBasis]) – basis to measure in on the remote node for M-type requestsrotations_local (
tuple[int,int,int]) – rotations to apply before measuring on this node (for M- or R-type requests)rotations_remote (
tuple[int,int,int]) – rotations to apply before measuring on remote node (for M-type requests)random_basis_local (
Optional[RandomBasis]) – random bases to choose from when measuring on this node (for M- or R-type requests)random_basis_remote (
Optional[RandomBasis]) – random bases to choose from when measuring on the remote node (for M-type requests)rotation_axes_local (
QubitMeasureAxes) – Sequence of axes to rotate around before measuring on the local node (for M- or R-type requests)rotation_axes_remote (
QubitMeasureAxes) – Sequence of axes to rotate around before measuring on the remote node (for M-type requests)
- Return type:
list[Qubit] |list[EprMeasureResult] |list[LinkLayerOKTypeM]- Returns:
For K-type requests: list of qubits created. For M-type requests: list of entanglement info objects per created pair.
- create_context(number=1, sequential=False, time_unit=TimeUnit.MICRO_SECONDS, max_time=0)
Create a context that is executed for each generated EPR pair consecutively.
Creates EPR pairs with a remote node and handles each pair by the operations defined in a subsequent context. See the example below.
with epr_socket.create_context(number=10) as (q, pair): q.H() m = q.measure()
NOTE: even though all pairs are handled consecutively, they are still generated concurrently by the network stack. By setting sequential to True, the network stack only generates the next pair after the context for the previous pair has been executed, similar to using a callback (post_routine) in the create method.
- Parameters:
number (
int) – number of EPR pairs to generate, defaults to 1sequential (
bool) – whether to generate pairs sequentially, defaults to Falsetime_unit (
TimeUnit)max_time (
int)
- Return type:
ContextManager[tuple[FutureQubit,RegFuture]]
- recv_keep(number=1, post_routine=None, sequential=False, expect_phi_plus=True, expect_psi_plus=False, min_fidelity_all_at_end=None, max_tries=None)
Ask the network stack to wait for the remote node to generate EPR pairs, which are kept in memory.
A recv_keep operation must always be matched by a create_keep operation on the remote node. The number of generated pairs must also match.
For more information see the documentation of create_keep.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1post_routine (
Optional[Callable]) – callback function used when sequential is Truesequential (
bool) – whether to call the callback after each pair generation, defaults to Falseexpect_phi_plus (
bool) – whether to assume that the EPR pairs that are created are in the Phi+ (or Phi_00) state. Defaults to True. If True, the compiler will make sure that if the physical link actually produced another Bell state, the behavior seen by the application is still as if a Phi+ state was actually produced.min_fidelity_all_at_end (
Optional[int]) – the minimum fidelity that all entangled qubits should ideally still have at the moment the last qubit has been generated. For example, when specifying number=2 and min_fidelity_all_at_end=80, the the program will automatically try to make sure that both qubits have a fidelity of at least 80% when the second qubit has been generated. It will attempt to do this by automatically re-trying the entanglement generation if the fidelity constraint is not satisfied. This is however an attempt, and not a guarantee!.max_tries (
Optional[int]) – maximum number of re-tries should be made to try and achieve the min_fidelity_all_at_end constraint.expect_psi_plus (
bool)
- Return type:
list[Qubit]- Returns:
list of qubits created
- recv_keep_with_info(number=1, post_routine=None, sequential=False, expect_phi_plus=True, min_fidelity_all_at_end=None, max_tries=None)
Same as recv_keep but also return the EPR generation information coming from the network stack.
For more information see the documentation of recv_keep.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1post_routine (
Optional[Callable])sequential (
bool)expect_phi_plus (
bool)min_fidelity_all_at_end (
Optional[int])max_tries (
Optional[int])
- Return type:
tuple[list[Qubit],list[EprKeepResult]]- Returns:
tuple with (1) list of qubits created, (2) list of EprKeepResult objects
- recv_measure(number=1, expect_phi_plus=True)
Ask the network stack to wait for the remote node to generate EPR pairs, which are immediately measured (on both nodes).
A recv_measure operation must always be matched by a create_measure operation on the remote node. The number and type of generation must also match.
For more information see the documentation of create_measure.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1expect_phi_plus (
bool) – whether to assume that the EPR pairs that are created are in the Phi+ (or Phi_00) state. Defaults to True. If True, the compiler will make sure that if the physical link actually produced another Bell state, the behavior seen by the application is still as if a Phi+ state was actually produced.
- Return type:
list[EprMeasureResult]- Returns:
list of entanglement info objects per created pair.
- recv_rsp(number=1, expect_phi_plus=True, min_fidelity_all_at_end=None, max_tries=None)
Ask the network stack to wait for remote state preparation from another node.
A recv_rsp operation must always be matched by a create_rsp operation on the remote node. The number and type of generation must also match.
For more information see the documentation of create_rsp.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1expect_phi_plus (
bool) – whether to assume that the EPR pairs that are created are in the Phi+ (or Phi_00) state. Defaults to True. If True, the compiler will make sure that if the physical link actually produced another Bell state, the behavior seen by the application is still as if a Phi+ state was actually produced.min_fidelity_all_at_end (
Optional[int]) – the minimum fidelity that all entangled qubits should ideally still have at the moment the last qubit has been generated. For example, when specifying number=2 and min_fidelity_all_at_end=80, the the program will automatically try to make sure that both qubits have a fidelity of at least 80% when the second qubit has been generated. It will attempt to do this by automatically re-trying the entanglement generation if the fidelity constraint is not satisfied. This is however an attempt, and not a guarantee!.max_tries (
Optional[int]) – maximum number of re-tries should be made to try and achieve the min_fidelity_all_at_end constraint.
- Return type:
list[Qubit]- Returns:
list of qubits created
- recv_rsp_with_info(number=1, expect_phi_plus=True, min_fidelity_all_at_end=None, max_tries=None)
Same as recv_rsp but also return the EPR generation information coming from the network stack.
For more information see the documentation of recv_rsp.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1expect_phi_plus (
bool)min_fidelity_all_at_end (
Optional[int])max_tries (
Optional[int])
- Return type:
tuple[list[Qubit],list[EprKeepResult]]- Returns:
tuple with (1) list of qubits created, (2) list of EprKeepResult objects
- recv(number=1, post_routine=None, sequential=False, tp=EPRType.K)
Ask the network stack to wait for the remote node to generate EPR pairs.
A recv operation must always be matched by a create operation on the remote node. See also the documentation of create. The number and type of generation must also match.
In case of Measure Directly requests, it is the initiating node (that calls create) which specifies the measurement bases. This should not and cannot be done in recv.
For more information see the documentation of create.
- Parameters:
number (
int) – number of pairs to generate, defaults to 1post_routine (
Optional[Callable]) – callback function used when sequential is Truesequential (
bool) – whether to call the callback after each pair generation, defaults to Falsetp (
EPRType) – type of entanglement generation, defaults to EPRType.K
- Return type:
list[Qubit] |list[EprMeasureResult] |list[LinkLayerOKTypeR]- Returns:
For K-type requests: list of qubits created. For M-type requests: list of entanglement info objects per created pair.
- recv_context(number=1, sequential=False)
Receives EPR pair with a remote node (see doc of
create_context())- Parameters:
number (
int)sequential (
bool)