Source code for mqt.ionshuttler.multi_shuttler.outside.graph_utils

# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

from __future__ import annotations

from typing import TYPE_CHECKING

import networkx as nx

if TYPE_CHECKING:
    from .graph import Graph
    from .ion_types import Edge, Node


# create dictionary to swap from idx to idc and vice versa
# reversed in comparison with previous versions -> edge_idc key, edge_idx value now -> can also have an entry for the reversed edge_idc
[docs] def create_idc_dictionary(graph: Graph) -> dict[Edge, int]: edge_dict = {} for edge_idx, edge_idc in enumerate(graph.edges()): node1, node2 = tuple(sorted(edge_idc, key=lambda e: sum(list(e)))) edge_dict[node1, node2] = edge_idx edge_dict[node2, node1] = edge_idx return edge_dict
[docs] def get_idx_from_idc(edge_dictionary: dict[Edge, int], idc: Edge) -> int: node1, node2 = tuple(sorted(idc, key=lambda e: sum(list(e)))) return edge_dictionary[node1, node2]
[docs] def get_idc_from_idx(edge_dictionary: dict[Edge, int], idx: int) -> Edge: return next((k for k, v in edge_dictionary.items() if v == idx)) # list(edge_dictionary.values()).index(idx)
[docs] def create_dist_dict(graph: Graph) -> dict[str, dict[Edge, list[Node]]]: # create dictionary of dictionary with all distances to entry of each edge for each pz from .cycles import find_path_edge_to_edge dist_dict = {} for pz in graph.pzs: pz_dict = {} for edge_idc in graph.edges(): # keep node ordering consistent: edge_idx = get_idx_from_idc(graph.idc_dict, edge_idc) # for pz_path_idx in pz.path_to_pz_idxs: # if edge_idx == pz.path_to_pz: path = find_path_edge_to_edge(graph, edge_idc, pz.parking_edge, find_any_path=True) # assert path is not None, f"No path from edge {edge_idc} to parking edge {pz.parking_edge} for pz {pz.name}" if path is None: print(f"Warning: No path from edge {edge_idc} to parking edge {pz.parking_edge} for pz {pz.name}") continue pz_dict[get_idc_from_idx(graph.idc_dict, edge_idx)] = path dist_dict[pz.name] = pz_dict return dist_dict
# calc distance to parking edge for all ions
[docs] def update_distance_map(graph: Graph, state: dict[int, int]) -> dict[int, dict[str, int]]: """Update a distance map that tracks the distances to each pz for each ion of current state. Dict: {ion: {'pz_name': distance}}, e.g., {0: {'pz1': 2, 'pz2': 2, 'pz3': 1}, 1: {'pz1': 4, 'pz2': 1, 'pz3': 2}, 2: {'pz1': 3, 'pz2': 1, 'pz3': 3}}""" distance_map = {} for ion, edge_idx in state.items(): pz_dict = {} for pz in graph.pzs: pz_dict[pz.name] = len(graph.dist_dict[pz.name][get_idc_from_idx(graph.idc_dict, edge_idx)]) distance_map[ion] = pz_dict return distance_map
# Function to convert all nodes to float
[docs] def convert_nodes_to_float(graph: Graph) -> Graph: mapping = {node: (float(node[0]), float(node[1])) for node in graph.nodes} return nx.relabel_nodes(graph, mapping, copy=False)