Beispiel #1
0
def _rec_classical(packet):
    """
    Receives a classical message packet , parses it into sequence number and message and sends an
    ACK message to receiver.

    Args:
        packet (Packet): The packet in which to receive.

    Returns:
        dict : A dictionary consisting of 'message' and 'sequence number'
    """
    message = packet.payload
    if packet.payload.content == Constants.ACK:
        message = Message(sender=packet.sender,
                          content=Constants.ACK,
                          seq_num=packet.seq_num)
        Logger.get_instance().log(packet.receiver + " received ACK from " +
                                  packet.sender + " with sequence number " +
                                  str(packet.seq_num))
    else:
        # Send an ACK msg if seq_num is not -1, as long as not an ACK msg!
        if packet.seq_num != -1:
            _send_ack(packet.sender, packet.receiver, packet.seq_num)

    return message
Beispiel #2
0
def _send_superdense(packet):
    """
    Encodes and sends a qubit to send a superdense message.

    Args:
        packet (Packet): The packet in which to transmit.
    """
    sender = packet.sender
    receiver = packet.receiver
    host_sender = network.get_host(sender)

    if not network.shares_epr(sender, receiver):
        Logger.get_instance().log('No shared EPRs - Generating one between ' + sender + " and " + receiver)
        q_id, _ = host_sender.send_epr(receiver, await_ack=True, block=True)
        assert q_id is not None
        q_superdense = host_sender.get_epr(receiver, q_id=q_id, wait=Constants.WAIT_TIME)

    else:
        q_superdense = host_sender.get_epr(receiver)

    if q_superdense is None:
        Logger.get_instance().log('Failed to get EPR with ' + sender + " and " + receiver)
        raise Exception("couldn't encode superdense")

    _encode_superdense(packet.payload, q_superdense)

    # change ID, so that at receiving they are not the same
    q_superdense.id = "E" + q_superdense.id
    packet.payload = q_superdense
    packet.protocol = Constants.REC_SUPERDENSE
    packet.payload_type = Constants.QUANTUM
    network.send(packet)
Beispiel #3
0
def _send_teleport(packet):
    """
    Does the measurements for teleportation of a qubit and sends the measurement results to another host.

    Args:
        packet (Packet): The packet in which to transmit.
    """

    if 'node' in packet.payload:
        node = packet.payload['node']
    else:
        node = packet.sender

    if 'type' in packet.payload:
        q_type = packet.payload['type']
    else:
        q_type = Constants.DATA

    q = packet.payload['q']
    host_sender = network.get_host(packet.sender)

    if Constants.GENERATE_EPR_IF_NONE in packet.payload and packet.payload[Constants.GENERATE_EPR_IF_NONE]:
        if not network.shares_epr(packet.sender, packet.receiver):
            Logger.get_instance().log(
                'No shared EPRs - Generating one between ' + packet.sender + " and " + packet.receiver)
            host_sender.send_epr(packet.receiver, q_id=q.id, await_ack=True, block=True)

    if 'eq_id' in packet.payload:
        epr_teleport = host_sender.get_epr(packet.receiver, packet.payload['eq_id'], wait=Constants.WAIT_TIME)
    else:
        epr_teleport = host_sender.get_epr(packet.receiver, wait=Constants.WAIT_TIME)

    assert epr_teleport is not None
    q.cnot(epr_teleport)
    q.H()

    m1 = q.measure()
    m2 = epr_teleport.measure()

    data = {
        'measurements': [m1, m2],
        'type': q_type,
        'node': node
    }

    if q_type == Constants.EPR:
        data['q_id'] = packet.payload['eq_id']
        data['eq_id'] = packet.payload['eq_id']
    else:
        data['q_id'] = q.id
        data['eq_id'] = epr_teleport.id

    if 'o_seq_num' in packet.payload:
        data['o_seq_num'] = packet.payload['o_seq_num']
    if 'ack' in packet.payload:
        data['ack'] = packet.payload['ack']

    packet.payload = data
    packet.protocol = Constants.REC_TELEPORT
    network.send(packet)
Beispiel #4
0
def _send_ack(sender, receiver, seq_number):
    """
    Send an acknowledge message from the sender to the receiver.
    Args:
        sender (str): The sender ID
        receiver (str): The receiver ID
        seq_number (int): The sequence number which to ACK
    """
    Logger.get_instance().log('sending ACK:' + str(seq_number + 1) + ' from ' + receiver + " to " + sender)
    host_receiver = network.get_host(receiver)
    host_receiver.send_ack(sender, seq_number)
Beispiel #5
0
    def add_host(self, host):
        """
        Adds the *host* to ARP table and updates the network graph.

        Args:
            host (Host): The host to be added to the network.
        """

        Logger.get_instance().debug('host added: ' + host.host_id)
        self.ARP[host.host_id] = host
        self._update_network_graph(host)
Beispiel #6
0
    def _remove_network_node(self, host):
        """
        Removes the host from the ARP table.

        Args:
            host (Host): The host to be removed from the network.
        """

        try:
            self.classical_network.remove_node(host.host_id)
        except nx.NetworkXError:
            Logger.get_instance().error(
                'attempted to remove a non-exiting node from network')
Beispiel #7
0
def process(packet):
    """
    Decodes the packet and processes the packet according to the protocol in the packet header.

    Args:
        packet (Packet): Packet to be processed.

    Returns:
        Returns what protocol function returns.

    """

    protocol = packet.protocol
    if protocol == Constants.SEND_TELEPORT:
        return _send_teleport(packet)
    elif protocol == Constants.REC_TELEPORT:
        return _rec_teleport(packet)
    elif protocol == Constants.SEND_CLASSICAL:
        return _send_classical(packet)
    elif protocol == Constants.REC_CLASSICAL:
        return _rec_classical(packet)
    elif protocol == Constants.REC_EPR:
        return _rec_epr(packet)
    elif protocol == Constants.SEND_EPR:
        return _send_epr(packet)
    elif protocol == Constants.SEND_SUPERDENSE:
        return _send_superdense(packet)
    elif protocol == Constants.REC_SUPERDENSE:
        return _rec_superdense(packet)
    elif protocol == Constants.SEND_QUBIT:
        return _send_qubit(packet)
    elif protocol == Constants.REC_QUBIT:
        return _rec_qubit(packet)
    elif protocol == Constants.RELAY:
        return _relay_message(packet)
    elif protocol == Constants.SEND_KEY:
        return _send_key(packet)
    elif protocol == Constants.REC_KEY:
        return _rec_key(packet)
    elif protocol == Constants.SEND_GHZ:
        return _send_ghz(packet)
    elif protocol == Constants.REC_GHZ:
        return _rec_ghz(packet)
    elif protocol == Constants.SEND_W:
        return _send_w(packet)
    elif protocol == Constants.REC_W:
        return _rec_w(packet)
    elif protocol == Constants.SEND_BROADCAST:
        return _send_broadcast(packet)
    else:
        Logger.get_instance().error('protocol not defined: ' + str(protocol))
Beispiel #8
0
def _relay_message(packet):
    """
    Reduce TTL of network packet and if TTL > 0, sends the message to be relayed to the next
    node in the network and modifies the header.

    Args:
        packet (RoutingPacket): Packet to be relayed

    """
    packet.ttl -= 1
    if packet.ttl != 0:
        network.send(packet)
    else:
        Logger.get_instance().log('TTL Expired on packet')
Beispiel #9
0
    def _route_quantum_info(self, sender, receiver, qubits):
        """
        Routes qubits from sender to receiver.

        Args:
            sender (Host): Sender of qubits
            receiver (Host): Receiver qubits
            qubits (List of Qubits): The qubits to be sent
        """
        def transfer_qubits(r, s, original_sender=None):
            for q in qubits:
                # Modify the qubit according to error function of the model
                qubit_id = q.id
                q = self.ARP[s].quantum_connections[
                    self.ARP[r].host_id].model.qubit_func(q)

                if q is None:
                    # Log failure of transmission if qubit is lost
                    Logger.get_instance().log(
                        'transfer qubits - transfer of qubit ' + qubit_id +
                        ' failed')
                    return False

                else:
                    Logger.get_instance().log(
                        'transfer qubits - sending qubit ' + q.id)

                    q.send_to(self.ARP[r].host_id)
                    Logger.get_instance().log('transfer qubits - received ' +
                                              q.id)

                    # Unblock qubits in case they were blocked
                    q.blocked = False

                    if self.ARP[r].q_relay_sniffing:
                        self.ARP[r].q_relay_sniffing_fn(
                            original_sender, receiver, q)
            return True

        route = self.get_quantum_route(sender, receiver)
        i = 0
        while i < len(route) - 1:
            Logger.get_instance().log('sending qubits from ' + route[i] +
                                      ' to ' + route[i + 1])
            if not transfer_qubits(
                    route[i + 1], route[i], original_sender=route[0]):
                return False
            i += 1
        return True
Beispiel #10
0
    def __init__(self):
        # _host_dict stores host_id -> array with qubits of the host.
        self._host_dict = {}
        # _qubit_dict stores qubit_id -> dict Host_id -> Qubit objects with this id.
        self._qubit_dict = {}
        # _purpose_dict stores qubit_id -> dict Host_id -> Purpose belonging to
        # the Qubit with the same Host and ID.
        self._purpose_dict = {}
        self._storage_mode = QuantumStorage.STORAGE_LIMIT_INDIVIDUALLY_PER_HOST
        self._storage_limits_per_host = {}
        self._amount_qubits_stored_per_host = {}
        self._default_storage_limit_per_host = -1
        self._storage_limit = -1
        self._amount_qubit_stored = 0
        self._heralding_probability = 1.0
        self._reading_efficiency = 1.0
        self._coherence_time = -1
        # read write lock, for threaded access
        self.lock = RWLock()

        self.logger = Logger.get_instance()

        # for tracking pending requests
        # dictionary tracks the request made by a pending request.
        self._pending_request_dict = {}
        # Determines a unique ID for a pending request.
        self._request_id = 0
        # Amount of pending requests
        self._amount_pending_requests = 0
Beispiel #11
0
    def stop(self, stop_hosts=False):
        """
        Stops the network.
        """

        Logger.get_instance().log("Network stopped")
        try:
            if stop_hosts:
                for host in self.ARP:
                    self.ARP[host].stop(release_qubits=True)

            self.send(None)  # Send None to queue to stop the queue
            if self._backend is not None:
                self._backend.stop()
        except Exception as e:
            Logger.get_instance().error(e)
Beispiel #12
0
def _rec_qubit(packet):
    """
    Receive a packet containing qubit information (qubit is transmitted externally)

    Args:
        packet (Packet): The packet in which to receive.
    """
    from_host = packet.sender
    receiver = packet.receiver
    qubit = packet.payload
    receiver = network.get_host(receiver)
    receiver.add_data_qubit(from_host, qubit)

    Logger.get_instance().log(packet.receiver + ' received qubit ' +
                              packet.payload.id + ' from ' + packet.sender)
    # Send ACK if seq_num is not -1

    if packet.seq_num != -1:
        _send_ack(packet.sender, packet.receiver, packet.seq_num)
Beispiel #13
0
        def transfer_qubits(r, original_sender=None):
            for q in qubits:
                Logger.get_instance().log('transfer qubits - sending qubit ' +
                                          q.id)
                x_err_var = random.random()
                z_err_var = random.random()
                if x_err_var > (1 - self.x_error_rate):
                    q.X()
                if z_err_var > (1 - self.z_error_rate):
                    q.Z()

                q.send_to(self.ARP[r].host_id)
                Logger.get_instance().log('transfer qubits - received ' + q.id)

                # Unblock qubits in case they were blocked
                q.blocked = False

                if self.ARP[r].q_relay_sniffing:
                    self.ARP[r].q_relay_sniffing_fn(original_sender, receiver,
                                                    q)
Beispiel #14
0
        def transfer_qubits(r, s, original_sender=None):
            for q in qubits:
                # Modify the qubit according to error function of the model
                qubit_id = q.id
                q = self.ARP[s].quantum_connections[
                    self.ARP[r].host_id].model.qubit_func(q)

                if q is None:
                    # Log failure of transmission if qubit is lost
                    Logger.get_instance().log(
                        'transfer qubits - transfer of qubit ' + qubit_id +
                        ' failed')
                    return False

                else:
                    Logger.get_instance().log(
                        'transfer qubits - sending qubit ' + q.id)

                    q.send_to(self.ARP[r].host_id)
                    Logger.get_instance().log('transfer qubits - received ' +
                                              q.id)

                    # Unblock qubits in case they were blocked
                    q.blocked = False

                    if self.ARP[r].q_relay_sniffing:
                        self.ARP[r].q_relay_sniffing_fn(
                            original_sender, receiver, q)
            return True
Beispiel #15
0
def checksum_sender(host, q_size, receiver_id, checksum_size_per_qubit):
    bit_arr = np.random.randint(2, size=q_size)
    Logger.get_instance().log('Bit array to be sent: ' + str(bit_arr))
    qubits = []
    for i in range(q_size):
        q_tmp = Qubit(host)
        if bit_arr[i] == 1:
            q_tmp.X()
        qubits.append(q_tmp)

    check_qubits = host.add_checksum(qubits, checksum_size_per_qubit)
    checksum_size = int(q_size / checksum_size_per_qubit)
    qubits.append(check_qubits)
    checksum_cnt = 0
    for i in range(q_size + checksum_size):
        if i < q_size:
            q = qubits[i]
        else:
            q = qubits[q_size][checksum_cnt]
            checksum_cnt = checksum_cnt + 1

        host.send_qubit(receiver_id, q, await_ack=True)
Beispiel #16
0
    def _route_quantum_info(self, sender, receiver, qubits):
        """
        Routes qubits from sender to receiver.

        Args:
            sender (Host): Sender of qubits
            receiver (Host): Receiver qubits
            qubits (List of Qubits): The qubits to be sent
        """
        def transfer_qubits(r, original_sender=None):
            for q in qubits:
                Logger.get_instance().log('transfer qubits - sending qubit ' +
                                          q.id)
                x_err_var = random.random()
                z_err_var = random.random()
                if x_err_var > (1 - self.x_error_rate):
                    q.X()
                if z_err_var > (1 - self.z_error_rate):
                    q.Z()

                q.send_to(self.ARP[r].host_id)
                Logger.get_instance().log('transfer qubits - received ' + q.id)

                # Unblock qubits in case they were blocked
                q.blocked = False

                if self.ARP[r].q_relay_sniffing:
                    self.ARP[r].q_relay_sniffing_fn(original_sender, receiver,
                                                    q)

        route = self.get_quantum_route(sender, receiver)
        i = 0
        while i < len(route) - 1:
            Logger.get_instance().log('sending qubits from ' + route[i] +
                                      ' to ' + route[i + 1])
            transfer_qubits(route[i + 1], original_sender=route[0])
            i += 1
Beispiel #17
0
def routing_algorithm(di_graph, source, target):
    """
    Entanglement based routing function. Note: any custom routing function must
    have exactly these three parameters and must return a list ordered by the steps
    in the route.

    Args:
        di_graph (networkx DiGraph): The directed graph representation of the network.
        source (str): The sender ID
        target (str: The receiver ID
    Returns:
        (list): The route ordered by the steps in the route.
    """

    # Generate entanglement network
    entanglement_network = nx.DiGraph()
    nodes = di_graph.nodes()
    for node in nodes:
        host = network.get_host(node)
        host_connections = host.get_connections()
        for connection in host_connections:
            if connection['type'] == 'quantum':
                num_epr_pairs = len(host.get_epr_pairs(connection['connection']))
                # print(host.host_id, connection['connection'], num_epr_pairs)
                if num_epr_pairs == 0:
                    entanglement_network.add_edge(host.host_id, connection['connection'], weight=1000)
                else:
                    entanglement_network.add_edge(host.host_id, connection['connection'], weight=1. / num_epr_pairs)

    try:
        route = nx.shortest_path(entanglement_network, source, target, weight='weight')
        if source == 'A':
            print('-------' + str(route) + '-------')
        return route
    except Exception as e:
        Logger.get_instance().error(e)
Beispiel #18
0
def checksum_receiver(host, q_size, sender_id, checksum_size_per_qubit):
    qubits = []
    checksum_size = int(q_size / checksum_size_per_qubit)
    while len(qubits) < (q_size + checksum_size):
        q = host.get_data_qubit(sender_id, wait=WAIT_TIME)
        qubits.append(q)
        Logger.get_instance().log(str(host.host_id) + ': received qubit')

    checksum_qubits = []
    checksum_cnt = 0

    for i in range(len(qubits)):
        if checksum_cnt < checksum_size:
            checksum_qubits.append(qubits[q_size + i]['q'])
            checksum_cnt = checksum_cnt + 1

    checksum_cnt = 1
    for i in range(len(qubits) - checksum_size):
        qubits[i]['q'].cnot(checksum_qubits[checksum_cnt - 1])
        if i == (checksum_cnt * checksum_size_per_qubit - 1):
            checksum_cnt = checksum_cnt + 1

    errors = 0
    for i in range(len(checksum_qubits)):
        if checksum_qubits[i].measure() != 0:
            errors += 1

    print('---------')
    if errors == 0:
        Logger.get_instance().log('No error exist in UDP packet')
    else:
        Logger.get_instance().log('There were errors in the UDP transmission')
    print('---------')

    rec_bits = []
    for i in range(len(qubits) - checksum_size):
        rec_bits.append(qubits[i]['q'].measure())

    if errors == 0:
        print('---------')
        Logger.get_instance().log('Receiver received the classical bits: ' + str(rec_bits))
        print('---------')
        return True

    return
Beispiel #19
0
    def _process_queue(self):
        """
        Runs a thread for processing the packets in the packet queue.
        """

        while True:

            packet = self._packet_queue.get()

            if not packet:
                # Stop the network
                self._stop_thread = True
                break

            # Artificially delay the network
            if self.delay > 0:
                time.sleep(self.delay)

            # Simulate packet loss
            packet_drop_var = random.random()
            if packet_drop_var > (1 - self.packet_drop_rate):
                Logger.get_instance().log("PACKET DROPPED")
                if packet.payload_type == Constants.QUANTUM:
                    packet.payload.release()
                continue

            sender, receiver = packet.sender, packet.receiver

            if packet.payload_type == Constants.QUANTUM:
                if not self._route_quantum_info(sender, receiver,
                                                [packet.payload]):
                    continue

            try:
                if packet.protocol == Constants.RELAY and not self.use_hop_by_hop:
                    full_route = packet.route
                    route = full_route[full_route.index(sender):]
                else:
                    if packet.protocol == Constants.REC_EPR:
                        route = self.get_classical_route(sender, receiver)
                    else:
                        route = self.get_classical_route(sender, receiver)

                if len(route) < 2:
                    raise Exception('No route exists')

                elif len(route) == 2:
                    if packet.protocol != Constants.RELAY:
                        if packet.protocol == Constants.REC_EPR:
                            host_sender = self.get_host(sender)
                            q = host_sender \
                                .backend \
                                .create_EPR(host_sender.host_id,
                                            receiver,
                                            q_id=packet.payload['q_id'],
                                            block=packet.payload['blocked'])
                            host_sender.add_epr(receiver, q)
                        self.ARP[receiver].rec_packet(packet)
                    else:
                        self.ARP[receiver].rec_packet(packet.payload)
                else:
                    if packet.protocol == Constants.REC_EPR:
                        q_id = packet.payload['q_id']
                        blocked = packet.payload['blocked']
                        q_route = self.get_quantum_route(sender, receiver)

                        if self.use_ent_swap:
                            DaemonThread(self._entanglement_swap,
                                         args=(sender, receiver, q_route, q_id,
                                               packet.seq_num, blocked))
                        else:
                            DaemonThread(self._establish_epr,
                                         args=(sender, receiver, q_id,
                                               packet.seq_num, blocked))

                    else:
                        network_packet = self._encode(route, packet)
                        self.ARP[route[1]].rec_packet(network_packet)

            except nx.NodeNotFound:
                Logger.get_instance().error(
                    "route couldn't be calculated, node doesn't exist")
            except ValueError:
                Logger.get_instance().error(
                    "route couldn't be calculated, value error")
            except Exception as e:
                Logger.get_instance().error('Error in network: ' + str(e))
Beispiel #20
0
    def _entanglement_swap(self, sender, receiver, route, q_id, o_seq_num,
                           blocked):
        """
        Performs a chain of entanglement swaps with the hosts between sender and receiver to create a shared EPR pair
        between sender and receiver.

        Args:
            sender (Host): Sender of the EPR pair
            receiver (Host): Receiver of the EPR pair
            route (list): Route between the sender and receiver
            q_id (str): Qubit ID of the sent EPR pair
            o_seq_num (int): The original sequence number
            blocked (bool): If the pair being distributed is blocked or not
        """
        host_sender = self.get_host(sender)

        def establish_epr(net, s, r):
            if not net.shares_epr(s, r):
                self.get_host(s).send_epr(r, q_id, await_ack=True)
            else:
                old_id = self.get_host(s).change_epr_qubit_id(r, q_id)
                net.get_host(r).change_epr_qubit_id(route[i], q_id, old_id)

        # Create EPR pairs on the route, where all EPR qubits have the id q_id
        threads = []
        for i in range(len(route) - 1):
            threads.append(
                DaemonThread(establish_epr,
                             args=(self, route[i], route[i + 1])))

        for t in threads:
            t.join()

        for i in range(len(route) - 2):
            host = self.get_host(route[i + 1])
            q = host.get_epr(route[0], q_id, wait=10)
            if q is None:
                print("Host is %s" % host.host_id)
                print("Search host is %s" % route[0])
                print("Search id is %s" % q_id)
                print("EPR storage is")
                print(host.EPR_store)
                Logger.get_instance().error('Entanglement swap failed')
                return
            data = {
                'q': q,
                'eq_id': q_id,
                'node': sender,
                'o_seq_num': o_seq_num,
                'type': Constants.EPR
            }

            if route[i + 2] == route[-1]:
                data = {
                    'q': q,
                    'eq_id': q_id,
                    'node': sender,
                    'ack': True,
                    'o_seq_num': o_seq_num,
                    'type': Constants.EPR
                }

            host.send_teleport(route[i + 2],
                               None,
                               await_ack=True,
                               payload=data,
                               generate_epr_if_none=False)

        # Change in the storage that the EPR qubit is shared with the receiver
        q2 = host_sender.get_epr(route[1], q_id=q_id)
        host_sender.add_epr(receiver, q2, q_id, blocked)
        Logger.get_instance().log(
            'Entanglement swap was successful for pair with id ' + q_id +
            ' between ' + sender + ' and ' + receiver)
Beispiel #21
0
    def _process_queue(self):
        """
        Runs a thread for processing the packets in the packet queue.
        """

        while True:
            if self._stop_thread:
                break

            if not self._packet_queue.empty():
                # Artificially delay the network
                if self.delay > 0:
                    time.sleep(self.delay)

                packet = self._packet_queue.get()

                sender, receiver = packet.sender, packet.receiver
                host_sender = self.get_host(sender)

                # Find transmission probability of the quantum connection and update network ticks if the packet is a qubit or an EPR signal
                if packet.payload_type == Constants.QUANTUM or (
                        packet.payload_type == Constants.SIGNAL
                        and isinstance(packet.payload, dict)
                        and 'q_id' in packet.payload.keys()):
                    transmission_probability = 1.0
                    for connection in host_sender.quantum_connections:
                        if connection.receiver_id == receiver:
                            transmission_probability = connection.transmission_p
                            break

                # Simulate packet loss
                packet_drop_var = random.random()
                transmission_var = random.random()

                if packet_drop_var > (1 - self.packet_drop_rate):
                    Logger.get_instance().log("PACKET DROPPED")
                    if packet.payload_type == Constants.QUANTUM:
                        packet.payload.release()
                    continue

                # Simulate packet loss due to absorption of qubits in the quantum channel
                elif packet.payload_type == Constants.QUANTUM or (
                        packet.payload_type == Constants.SIGNAL
                        and isinstance(packet.payload, dict)
                        and 'q_id' in packet.payload.keys()):
                    if transmission_var < 1 - transmission_probability:
                        Logger.get_instance().log("QUBIT TRANSMISSION FAILED")
                        if packet.payload_type == Constants.QUANTUM:
                            packet.payload.release()
                        continue

                if packet.payload_type == Constants.QUANTUM:
                    self._route_quantum_info(sender, receiver,
                                             [packet.payload])

                try:
                    if packet.protocol == Constants.RELAY and not self.use_hop_by_hop:
                        full_route = packet.route
                        route = full_route[full_route.index(sender):]
                    else:
                        if packet.protocol == Constants.REC_EPR:
                            route = self.get_classical_route(sender, receiver)
                        else:
                            route = self.get_classical_route(sender, receiver)

                    if len(route) < 2:
                        raise Exception('No route exists')

                    elif len(route) == 2:

                        # Update network ticks
                        sending_host = self.get_host(route[0])
                        receiving_host = self.get_host(route[1])
                        if packet.payload_type == Constants.QUANTUM or (
                                packet.payload_type == Constants.SIGNAL
                                and isinstance(packet.payload, dict)
                                and 'q_id' in packet.payload.keys()):
                            for connection in sending_host.quantum_connections:
                                if connection.receiver_id == receiving_host.host_id:
                                    self._tick += int(
                                        float(connection.length * 1000 /
                                              (self._tickspan)) / 300000000)
                                    break
                        else:
                            for connection in sending_host.classical_connections:
                                if connection.receiver_id == receiving_host.host_id:
                                    self._tick += int(
                                        float(connection.length * 1000 /
                                              (self._tickspan)) / 300000000)
                                    break

                        if packet.protocol != Constants.RELAY:
                            if packet.protocol == Constants.REC_EPR:
                                host_sender = self.get_host(sender)
                                q = host_sender \
                                    .backend \
                                    .create_EPR(host_sender.host_id,
                                                receiver,
                                                q_id=packet.payload['q_id'],
                                                block=packet.payload['blocked'])
                                host_sender.add_epr(receiver, q)
                            self.ARP[receiver].rec_packet(packet)
                        else:
                            self.ARP[receiver].rec_packet(packet.payload)
                    else:

                        # Update network ticks
                        #for routeidx in range(len(route)-2):
                        sending_host = self.get_host(route[0])
                        receiving_host = self.get_host(route[1])
                        if packet.payload_type == Constants.QUANTUM or (
                                packet.payload_type == Constants.SIGNAL
                                and isinstance(packet.payload, dict)
                                and 'q_id' in packet.payload.keys()):
                            for connection in sending_host.quantum_connections:
                                if connection.receiver_id == receiving_host.host_id:
                                    self._tick += int(
                                        float(connection.length * 1000 /
                                              (self._tickspan)) / 300000000)
                                    break
                        else:
                            for connection in sending_host.classical_connections:
                                if connection.receiver_id == receiving_host.host_id:
                                    self._tick += int(
                                        float(connection.length * 1000 /
                                              (self._tickspan)) / 300000000)
                                    break

                        if packet.protocol == Constants.REC_EPR:
                            q_id = packet.payload['q_id']
                            blocked = packet.payload['blocked']
                            q_route = self.get_quantum_route(sender, receiver)

                            if self.use_ent_swap:
                                DaemonThread(self._entanglement_swap,
                                             args=(sender, receiver, q_route,
                                                   q_id, packet.seq_num,
                                                   blocked))
                            else:
                                DaemonThread(self._establish_epr,
                                             args=(sender, receiver, q_id,
                                                   packet.seq_num, blocked))

                        else:
                            network_packet = self._encode(route, packet)
                            self.ARP[route[1]].rec_packet(network_packet)

                except nx.NodeNotFound:
                    Logger.get_instance().error(
                        "route couldn't be calculated, node doesn't exist")
                except ValueError:
                    Logger.get_instance().error(
                        "route couldn't be calculated, value error")
                except Exception as e:
                    Logger.get_instance().error('Error in network: ' + str(e))