code: def contextual_cost_matrix_construction(
      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 linear assignment on the nodes with bipartite algorithm
      # 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()
  
      cost_upper_bound = 2 * (
          node_substitution_cost.sum()
          + G1_node_deletion_cost.sum()
          + G2_node_insertion_cost.sum()
          + 1
      )
      cost_matrix = np.zeros(
          (num_G1_nodes + num_G2_nodes, num_G1_nodes + num_G2_nodes),
          dtype=float,
      )
  
      cost_matrix[
          0:num_G1_nodes, 0:num_G2_nodes
      ] = node_substitution_cost
      cost_matrix[
          0:num_G1_nodes, num_G2_nodes : num_G2_nodes + num_G1_nodes
      ] = np.array(
          [
              G1_node_deletion_cost[i] if i == j else cost_upper_bound
              for i in range(num_G1_nodes)
              for j in range(num_G1_nodes)
          ]
      ).reshape(
          num_G1_nodes, num_G1_nodes
      )
      cost_matrix[
          num_G1_nodes : num_G1_nodes + num_G2_nodes, 0:num_G2_nodes
      ] = np.array(
          [
              G2_node_insertion_cost[i] if i == j else cost_upper_bound
              for i in range(num_G2_nodes)
              for j in range(num_G2_nodes)
          ]
      ).reshape(
          num_G2_nodes, num_G2_nodes
      )
  
      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_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())
      ]
  
      # Add the cost of edge edition which are dependent of a node (see this as the cost associated with a substructure)
      for i in range(num_G1_nodes):
          for j in range(num_G2_nodes):
              m = (
                  len(self_edge_list_G1[i])
                  + len(incoming_edges_G1[i])
                  + len(outgoing_edges_G1[i])
              )
              n = (
                  len(self_edge_list_G2[j])
                  + len(incoming_edges_G2[j])
                  + len(outgoing_edges_G2[j])
              )
  
              matrix_dim = m + n
  
              if matrix_dim == 0:
                  continue
              temp_edge_cost_matrix = np.empty((matrix_dim, matrix_dim))
              temp_edge_cost_matrix.fill(cost_upper_bound)
  
              temp_edge_cost_matrix[
                  : len(self_edge_list_G1[i]),
                  : len(self_edge_list_G2[j]),
              ] = edge_substitution_cost[self_edge_list_G1[i], :][
                  :, self_edge_list_G2[j]
              ]
              temp_edge_cost_matrix[
                  len(self_edge_list_G1[i]) : len(self_edge_list_G1[i])
                  + len(incoming_edges_G1[i]),
                  len(self_edge_list_G2[j]) : len(self_edge_list_G2[j])
                  + len(incoming_edges_G2[j]),
              ] = edge_substitution_cost[incoming_edges_G1[i], :][
                  :, incoming_edges_G2[j]
              ]
              temp_edge_cost_matrix[
                  len(self_edge_list_G1[i])
                  + len(incoming_edges_G1[i]) : m,
                  len(self_edge_list_G2[j])
                  + len(incoming_edges_G2[j]) : n,
              ] = edge_substitution_cost[outgoing_edges_G1[i], :][
                  :, outgoing_edges_G2[j]
              ]
  
              np.fill_diagonal(
                  temp_edge_cost_matrix[:m, n:], selected_deletion_G1[i]
              )
              np.fill_diagonal(
                  temp_edge_cost_matrix[m:, :n],
                  selected_insertion_G2[j],
              )
  
              temp_edge_cost_matrix[m:, n:].fill(0)
              row_ind, col_ind, _ = lapjv(temp_edge_cost_matrix)
              lap_cost = 0.00
              for k in range(len(row_ind)):
                  lap_cost += temp_edge_cost_matrix[k, row_ind[k]]
  
              cost_matrix[i, j] += lap_cost
  
      for i in range(num_G1_nodes):
          cost_matrix[i, num_G2_nodes + i] += selected_deletion_G1[
              i
          ].sum()
  
      for i in range(num_G2_nodes):
          cost_matrix[num_G1_nodes + i, i] += selected_insertion_G2[
              i
          ].sum()
  
      return cost_matrix
  
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 6 for calling a global function with example usage: contextual_cost_matrix_construction(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: cost_matrix