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: abc.ABC

EPR 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 0

  • remote_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

Get the underlying NetQASMConnection

Return type

connection.BaseNetQASMConnection

property remote_app_name

Get the remote application name

Return type

str

property remote_node_id

Get the remote node ID

Return type

int

property epr_socket_id

Get the EPR socket ID

Return type

int

property remote_epr_socket_id

Get the remote EPR socket ID

Return type

int

property min_fidelity

Get the desired minimum fidelity

Return type

int

create_keep(number=1, post_routine=None, sequential=False, time_unit=<TimeUnit.MICRO_SECONDS: 0>, 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 1

  • post_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 False

  • time_unit (TimeUnit) – which time unit to use for the max_time parameter

  • max_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: 0>, 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 1

  • post_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: 0>, 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)

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 an X-rotation, a Y-rotation and another X-rotation. For example, setting rotations_local to (8, 0, 0) 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 1

  • time_unit (TimeUnit) – which time unit to use for the max_time parameter

  • max_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 requests

  • basis_remote (Optional[EprMeasBasis]) – basis to measure in on the remote node for M-type requests

  • rotations_local (Tuple[int, int, int]) – rotations to apply before measuring on this node

  • rotations_remote (Tuple[int, int, int]) – rotations to apply before measuring on remote node

  • random_basis_local (Optional[RandomBasis]) – random bases to choose from when measuring on this node

  • random_basis_remote (Optional[RandomBasis]) – random bases to choose from when 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: 0>, max_time=0, basis_local=None, rotations_local=(0, 0, 0), random_basis_local=None, min_fidelity_all_at_end=None, max_tries=None)

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 an X-rotation, a Y-rotation and another X-rotation. For example, setting rotations_local to (8, 0, 0) 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 1

  • time_unit (TimeUnit) – which time unit to use for the max_time parameter

  • max_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 requests

  • rotations_local (Tuple[int, int, int]) – rotations to apply before measuring on this node

  • random_basis_local (Optional[RandomBasis]) – random bases to choose from when measuring on this node

  • 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[EprMeasureResult]

Returns

list of entanglement info objects per created pair.

create(number=1, post_routine=None, sequential=False, tp=<EPRType.K: 0>, time_unit=<TimeUnit.MICRO_SECONDS: 0>, 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)

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 an X-rotation, a Y-rotation and another X-rotation. For example, setting rotations_local to (8, 0, 0) 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 1

  • post_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 False

  • tp (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 parameter

  • max_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 requests

  • basis_remote (Optional[EprMeasBasis]) – basis to measure in on the remote node for M-type requests

  • rotations_local (Tuple[int, int, int]) – rotations to apply before measuring on this node (for M-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-type requests)

  • random_basis_remote (Optional[RandomBasis]) – random bases to choose from when measuring on the remote node (for M-type requests)

Return type

Union[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: 0>, 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 1

  • sequential (bool) – whether to generate pairs sequentially, defaults to False

  • time_unit (TimeUnit) –

  • max_time (int) –

Return type

AbstractContextManager[Tuple[FutureQubit, RegFuture]]

recv_keep(number=1, post_routine=None, sequential=False, expect_phi_plus=True, 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 1

  • post_routine (Optional[Callable]) – callback function used when sequential is True

  • sequential (bool) – whether to call the callback after each pair generation, defaults to False

  • expect_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_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 1

  • post_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 1

  • expect_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 1

  • expect_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 1

  • 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(number=1, post_routine=None, sequential=False, tp=<EPRType.K: 0>)

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 1

  • post_routine (Optional[Callable]) – callback function used when sequential is True

  • sequential (bool) – whether to call the callback after each pair generation, defaults to False

  • tp (EPRType) – type of entanglement generation, defaults to EPRType.K

Return type

Union[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) –