# <one line to give the library's name and an idea of what it does.>
# Copyright (C) 2014  <copyright holder> <email>
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 
#

import contextualsimilaritymeasure

class ContextualBOWSimilarityMeasure(
  contextualsimilaritymeasure.ContextualSimilarityMeasure):
  """!
  Dla zadanego wezla liczy podobienstwo jego otoczenia na zasadzie 
  przeciecia sie kontekstu wezlow w dwoch grafach. Kontekst w tej chwili
  to najblizsi sasiedzi danego wezla (bezposrednie poprzedniki 
  oraz bezposrednie nastepniki). Liczba wspolnych sasiadow normalizowana
  jest przez wielkosc sasiedztwa. Wartosc taka jest zwracana:

                   || {g1nodes} /\ {g2nodes} ||
    sim(c1, c2) = --------------------------------
                   || {g1nodes} \/ {g2nodes} ||

  Funkcja __sim_bow_function przyjmuje w argumentach dwa grafy, 
  na podstawie których oceniane bedzie podobienstwo wezla n w obu
  tych grafach. Wezel n rowniez przekazywany jest w argumencie funckji.

  Funkcja nie rozroznia wezlow wchodzacych od wychodzacych. Sprawdza jedynie 
  czy sasiedztwa (wezly) sa do siebie podobne. Do wielkosci sasiedztwa nie sa
  wliczane wezly, dla ktorych sprawdzane jest podobienstwo. Miara dobrze
  moze wspolgrac jako zlozenie z SameNodeSimilarityMeasure
  """

  def __init__(self, options, str_name = 'ContextualBOWSimilarityMeasure'):
    super(ContextualBOWSimilarityMeasure, self).__init__(
      options, self.__sim_bow_function, str_name)

  def __sim_bow_function(self, g1, g2, n):
    """!
    @param g1 first graph
    @type g1: networgx.DiGraph/networkx.MultiDiGraph

    @param g2 second graph
    @type g1: networgx.DiGraph/networkx.MultiDiGraph

    @param n node into graphs
    @type n: networkx.node

    @return
    @rtype: double
    """
    if not g1.has_node(n) or not g2.has_node(n):
      return 0.0
    g1nodes = set(g1.predecessors(n) + g1.successors(n))
    g2nodes = set(g2.predecessors(n) + g2.successors(n))
    samenodes = len(g1nodes.union(g2nodes))
    if samenodes == 0:
      return 0.0
    return (len(g1nodes.intersection(g2nodes)) /  (0.0 + samenodes))
