You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

bipartite.py 4.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Created on Thu Jun 18 16:09:29 2020
  5. @author: ljia
  6. """
  7. import numpy as np
  8. import networkx as nx
  9. from gklearn.ged.methods import LSAPEBasedMethod
  10. from gklearn.ged.util import LSAPESolver
  11. from gklearn.utils import SpecialLabel
  12. class Bipartite(LSAPEBasedMethod):
  13. def __init__(self, ged_data):
  14. super().__init__(ged_data)
  15. self._compute_lower_bound = False
  16. ###########################################################################
  17. # Inherited member functions from LSAPEBasedMethod.
  18. ###########################################################################
  19. def _lsape_populate_instance(self, g, h, master_problem):
  20. # #ifdef _OPENMP
  21. for row_in_master in range(0, nx.number_of_nodes(g)):
  22. for col_in_master in range(0, nx.number_of_nodes(h)):
  23. master_problem[row_in_master, col_in_master] = self._compute_substitution_cost(g, h, row_in_master, col_in_master)
  24. for row_in_master in range(0, nx.number_of_nodes(g)):
  25. master_problem[row_in_master, nx.number_of_nodes(h) + row_in_master] = self._compute_deletion_cost(g, row_in_master)
  26. for col_in_master in range(0, nx.number_of_nodes(h)):
  27. master_problem[nx.number_of_nodes(g) + col_in_master, col_in_master] = self._compute_insertion_cost(h, col_in_master)
  28. # for row_in_master in range(0, master_problem.shape[0]):
  29. # for col_in_master in range(0, master_problem.shape[1]):
  30. # if row_in_master < nx.number_of_nodes(g) and col_in_master < nx.number_of_nodes(h):
  31. # master_problem[row_in_master, col_in_master] = self._compute_substitution_cost(g, h, row_in_master, col_in_master)
  32. # elif row_in_master < nx.number_of_nodes(g):
  33. # master_problem[row_in_master, nx.number_of_nodes(h)] = self._compute_deletion_cost(g, row_in_master)
  34. # elif col_in_master < nx.number_of_nodes(h):
  35. # master_problem[nx.number_of_nodes(g), col_in_master] = self._compute_insertion_cost(h, col_in_master)
  36. ###########################################################################
  37. # Helper member functions.
  38. ###########################################################################
  39. def _compute_substitution_cost(self, g, h, u, v):
  40. # Collect node substitution costs.
  41. cost = self._ged_data.node_cost(g.nodes[u]['label'], h.nodes[v]['label'])
  42. # Initialize subproblem.
  43. d1, d2 = g.degree[u], h.degree[v]
  44. subproblem = np.ones((d1 + d2, d1 + d2)) * np.inf
  45. subproblem[d1:, d2:] = 0
  46. # subproblem = np.empty((g.degree[u] + 1, h.degree[v] + 1))
  47. # Collect edge deletion costs.
  48. i = 0 # @todo: should directed graphs be considered?
  49. for label in g[u].values(): # all u's neighbor
  50. subproblem[i, d2 + i] = self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY)
  51. # subproblem[i, h.degree[v]] = self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY)
  52. i += 1
  53. # Collect edge insertion costs.
  54. i = 0 # @todo: should directed graphs be considered?
  55. for label in h[v].values(): # all u's neighbor
  56. subproblem[d1 + i, i] = self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label'])
  57. # subproblem[g.degree[u], i] = self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label'])
  58. i += 1
  59. # Collect edge relabelling costs.
  60. i = 0
  61. for label1 in g[u].values():
  62. j = 0
  63. for label2 in h[v].values():
  64. subproblem[i, j] = self._ged_data.edge_cost(label1['label'], label2['label'])
  65. j += 1
  66. i += 1
  67. # Solve subproblem.
  68. subproblem_solver = LSAPESolver(subproblem)
  69. subproblem_solver.set_model(self._lsape_model)
  70. subproblem_solver.solve()
  71. # Update and return overall substitution cost.
  72. cost += subproblem_solver.minimal_cost()
  73. return cost
  74. def _compute_deletion_cost(self, g, v):
  75. # Collect node deletion cost.
  76. cost = self._ged_data.node_cost(g.nodes[v]['label'], SpecialLabel.DUMMY)
  77. # Collect edge deletion costs.
  78. for label in g[v].values():
  79. cost += self._ged_data.edge_cost(label['label'], SpecialLabel.DUMMY)
  80. # Return overall deletion cost.
  81. return cost
  82. def _compute_insertion_cost(self, g, v):
  83. # Collect node insertion cost.
  84. cost = self._ged_data.node_cost(SpecialLabel.DUMMY, g.nodes[v]['label'])
  85. # Collect edge insertion costs.
  86. for label in g[v].values():
  87. cost += self._ged_data.edge_cost(SpecialLabel.DUMMY, label['label'])
  88. # Return overall insertion cost.
  89. return cost

A Python package for graph kernels, graph edit distances and graph pre-image problem.