#
# <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 structuralsimilaritymeasure

class ContextualSimilarityMeasure(
  structuralsimilaritymeasure.StructuralSimilarityMeasure):
  """!
  Glowna klasa, ktora umozliwia podpiecie dowolnej funkcji kontekstowej.
  W konstruktorze przekazywana jest funkcja podobienstwa operujaca
  na kontekscie. Dla zadanej funkcji oraz dwoch grafow uruchamiana
  jest wlasnie ta funkcja.

  Zaklada sie, ze funkcja podobienstwa operujaca na kontekscie w argumentach
  wywolania musi przyjac dwa grafy oraz wezel, ktorego podobienstwo bedzie
  oceniane w kontekscie tych grafow.

  Proces obliczania podobienstwa polega na zsumowaniu podobienstwa 
  wszystkich wezlow (w kontekscie obu grafow) i normalizacji przez 
  sume wielkosci obu grafow (liczby wezlow). Uwaga! Obliczanie 
  podobienstwa bazuje na wystepowaniu tego samego wezla w obu grafach.

           SUM(simf(n))
      ---------------------
       || g1 || + || g2 ||

    For n in G1. 

    Mozna przyjac, ze wartosc generowana przez funkcje w ramach
    ContextualSimilarityMeasure, ktora jest wieksza od 1 oznacza, 
    ze oba porownywane grafy sa takie same. Normalizacja przez
    sume wezlow obu grafow, nie zawsze normalizuje sume wartosci
    funkcji podobienstwa otoczenia do przedzialu <0, 1>. Ma to
    zwiazek z wielkoscia otoczenia brana pod uwage podczas okreslania
    podobienstwa danego wzla w obu grafach.

    Dlatego nalezy przyjac, ze jest to przedzial <0, inf>, gdzie:
     * 0 oznacza, ze grafy sa do siebie w ogole nie podobne, 
     * >= 1 oznacza, ze grafy sa takie same
  """

  def __init__(self, options, sim_function,
               str_name = 'ContextualSimilarityMeasure'):
    super(ContextualSimilarityMeasure, self).__init__(options, str_name)
    self.__sim_function = sim_function

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

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

    @return 
    @rtype: double
    """
    if not g1 or not g2:
      return 0
    g1len = len(g1.nodes())
    g2len = len(g2.nodes())
    if g1len == 0 or g2len == 0:
      return 0.0

    # for a little optimization gets smaller graph
    sg = 0.0
    g = g1 if g1len < g2len else g2
    for n1 in g:
      sg += self.__sim_function(g1, g2, n1)
    return sg / (0.0 +len(g))
