code: def hausdorff_matching(
      G1,
      G2,
      node_substitution_cost,
      edge_substitution_cost,
      G1_node_deletion_cost,
      G1_edge_deletion_cost,
      G2_node_insertion_cost,
      G2_edge_insertion_cost,
  ):
      # Calculates approximate GED using hausdorff_matching
      # cost matrix of node mappings
  
      num_G1_nodes = G1.num_nodes()
      num_G2_nodes = G2.num_nodes()
  
      num_G1_edges = G1.num_edges()
      num_G2_edges = G2.num_edges()
  
      self_edge_list_G1 = [np.array([], dtype=int)] * num_G1_nodes
      self_edge_list_G2 = [np.array([], dtype=int)] * num_G2_nodes
      incoming_edges_G1 = [np.array([], dtype=int)] * num_G1_nodes
      incoming_edges_G2 = [np.array([], dtype=int)] * num_G2_nodes
      outgoing_edges_G1 = [np.array([], dtype=int)] * num_G1_nodes
      outgoing_edges_G2 = [np.array([], dtype=int)] * num_G2_nodes
  
      for i in range(num_G1_nodes):
          if G1.has_edge_between(i, i):
              self_edge_list_G1[i] = sorted(
                  G1.edge_ids(i, i, return_array=True).numpy()
              )
          incoming_edges_G1[i] = G1.in_edges([i], "eid").numpy()
          incoming_edges_G1[i] = np.setdiff1d(
              incoming_edges_G1[i], self_edge_list_G1[i]
          )
          outgoing_edges_G1[i] = G1.out_edges([i], "eid").numpy()
          outgoing_edges_G1[i] = np.setdiff1d(
              outgoing_edges_G1[i], self_edge_list_G1[i]
          )
      for i in range(num_G2_nodes):
          if G2.has_edge_between(i, i):
              self_edge_list_G2[i] = sorted(
                  G2.edge_ids(i, i, return_array=True).numpy()
              )
          incoming_edges_G2[i] = G2.in_edges([i], "eid").numpy()
          incoming_edges_G2[i] = np.setdiff1d(
              incoming_edges_G2[i], self_edge_list_G2[i]
          )
          outgoing_edges_G2[i] = G2.out_edges([i], "eid").numpy()
          outgoing_edges_G2[i] = np.setdiff1d(
              outgoing_edges_G2[i], self_edge_list_G2[i]
          )
  
      selected_deletion_self_G1 = [
          G1_edge_deletion_cost[self_edge_list_G1[i]]
          for i in range(G1.num_nodes())
      ]
      selected_insertion_self_G2 = [
          G2_edge_insertion_cost[self_edge_list_G2[i]]
          for i in range(G2.num_nodes())
      ]
  
      selected_deletion_incoming_G1 = [
          G1_edge_deletion_cost[incoming_edges_G1[i]]
          for i in range(G1.num_nodes())
      ]
      selected_insertion_incoming_G2 = [
          G2_edge_insertion_cost[incoming_edges_G2[i]]
          for i in range(G2.num_nodes())
      ]
  
      selected_deletion_outgoing_G1 = [
          G1_edge_deletion_cost[outgoing_edges_G1[i]]
          for i in range(G1.num_nodes())
      ]
      selected_insertion_outgoing_G2 = [
          G2_edge_insertion_cost[outgoing_edges_G2[i]]
          for i in range(G2.num_nodes())
      ]
  
      selected_deletion_G1 = [
          G1_edge_deletion_cost[
              np.concatenate(
                  (
                      self_edge_list_G1[i],
                      incoming_edges_G1[i],
                      outgoing_edges_G1[i],
                  )
              )
          ]
          for i in range(G1.num_nodes())
      ]
      selected_insertion_G2 = [
          G2_edge_insertion_cost[
              np.concatenate(
                  (
                      self_edge_list_G2[i],
                      incoming_edges_G2[i],
                      outgoing_edges_G2[i],
                  )
              )
          ]
          for i in range(G2.num_nodes())
      ]
  
      cost_G1 = np.array(
          [
              (
                  G1_node_deletion_cost[i]
                  + selected_deletion_G1[i].sum() / 2
              )
              for i in range(num_G1_nodes)
          ]
      )
      cost_G2 = np.array(
          [
              (
                  G2_node_insertion_cost[i]
                  + selected_insertion_G2[i].sum() / 2
              )
              for i in range(num_G2_nodes)
          ]
      )
  
      for i in range(num_G1_nodes):
          for j in range(num_G2_nodes):
              c1_self = deepcopy(selected_deletion_self_G1[i])
              c2_self = deepcopy(selected_insertion_self_G2[j])
              c1_incoming = deepcopy(selected_deletion_incoming_G1[i])
              c2_incoming = deepcopy(selected_insertion_incoming_G2[j])
              c1_outgoing = deepcopy(selected_deletion_outgoing_G1[i])
              c2_outgoing = deepcopy(selected_insertion_outgoing_G2[j])
  
              for k, a in enumerate(self_edge_list_G1[i]):
                  for l, b in enumerate(self_edge_list_G2[j]):
                      c1_self[k] = min(
                          c1_self[k], edge_substitution_cost[a, b] / 2
                      )
                      c2_self[l] = min(
                          c2_self[l], edge_substitution_cost[a, b] / 2
                      )
  
              for k, a in enumerate(incoming_edges_G1[i]):
                  for l, b in enumerate(incoming_edges_G2[j]):
                      c1_incoming[k] = min(
                          c1_incoming[k],
                          edge_substitution_cost[a, b] / 2,
                      )
                      c2_incoming[l] = min(
                          c2_incoming[l],
                          edge_substitution_cost[a, b] / 2,
                      )
  
              for k, a in enumerate(outgoing_edges_G1[i]):
                  for l, b in enumerate(outgoing_edges_G2[j]):
                      c1_outgoing[k] = min(
                          c1_outgoing[k],
                          edge_substitution_cost[a, b] / 2,
                      )
                      c2_outgoing[l] = min(
                          c2_outgoing[l],
                          edge_substitution_cost[a, b] / 2,
                      )
  
              edge_hausdorff_lower_bound = 0.0
  
              if len(selected_deletion_G1[i]) > len(
                  selected_insertion_G2[j]
              ):
                  idx = np.argpartition(
                      selected_deletion_G1[i],
                      (
                          len(selected_deletion_G1[i])
                          - len(selected_insertion_G2[j])
                      ),
                  )
                  edge_hausdorff_lower_bound = selected_deletion_G1[i][
                      idx[
                          : (
                              len(selected_deletion_G1[i])
                              - len(selected_insertion_G2[j])
                          )
                      ]
                  ].sum()
              elif len(selected_deletion_G1[i]) < len(
                  selected_insertion_G2[j]
              ):
                  idx = np.argpartition(
                      selected_insertion_G2[j],
                      (
                          len(selected_insertion_G2[j])
                          - len(selected_deletion_G1[i])
                      ),
                  )
                  edge_hausdorff_lower_bound = selected_insertion_G2[j][
                      idx[
                          : (
                              len(selected_insertion_G2[j])
                              - len(selected_deletion_G1[i])
                          )
                      ]
                  ].sum()
  
              sc_cost = 0.5 * (
                  node_substitution_cost[i, j]
                  + 0.5
                  * max(
                      c1_self.sum()
                      + c2_self.sum()
                      + c1_incoming.sum()
                      + c2_incoming.sum()
                      + c1_outgoing.sum()
                      + c2_outgoing.sum(),
                      edge_hausdorff_lower_bound,
                  )
              )
  
              if cost_G1[i] > sc_cost:
                  cost_G1[i] = sc_cost
              if cost_G2[j] > sc_cost:
                  cost_G2[j] = sc_cost
  
      graph_hausdorff_lower_bound = 0.0
      if num_G1_nodes > num_G2_nodes:
          idx = np.argpartition(
              G1_node_deletion_cost, (num_G1_nodes - num_G2_nodes)
          )
          graph_hausdorff_lower_bound = G1_node_deletion_cost[
              idx[: (num_G1_nodes - num_G2_nodes)]
          ].sum()
      elif num_G1_nodes < num_G2_nodes:
          idx = np.argpartition(
              G2_node_insertion_cost, (num_G2_nodes - num_G1_nodes)
          )
          graph_hausdorff_lower_bound = G2_node_insertion_cost[
              idx[: (num_G2_nodes - num_G1_nodes)]
          ].sum()
  
      graph_hausdorff_cost = max(
          graph_hausdorff_lower_bound, cost_G1.sum() + cost_G2.sum()
      )
      return graph_hausdorff_cost
  
file_path: dgl/examples/pytorch/graph_matching/ged.py
imports: from copy import deepcopy
  from heapq import heapify, heappop, heappush, nsmallest
  import dgl
  import numpy
  from lapjv import lapjv
label_desc: Use image node_id 7 for calling a global function with example usage: hausdorff_matching(G1, G2, node_substitution_cost, edge_substitution_cost, G1_node_deletion_cost, G1_edge_deletion_cost, G2_node_insertion_cost, G2_edge_insertion_cost) and returns: graph_hausdorff_cost