#
# <one line to give the library's name and an idea of what it does.>
# Copyright (C) 2015  <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 networkx
import spreadinginterface

class PageRankSpreading(spreadinginterface.SpreadingInterface):
  """!
  This class uses the PageRank algorithm to spread weights into graph.
  """

  def __init__(self, str_name = 'PageRankSpreading'):
    """!
    Constructor only sets the name of spreading 
    and calls the partens constructor.

    @param str_name Name of spreading method
    @type str_name: String
    """
    super(PageRankSpreading, self).__init__(str_name)

  def spread(self, g, max_it, max_depth):
    """!
    PageRank based weights spreading.

    There is a little hax: when the sum of node values is not greater than zero
    then PageRank is run without personalization vector. When sum of values
    is greater than zero, then PageRank is run with personalization vector.
    The spreading belongs on makes the node ranking and store this ranking to
    the nodes.

    @param g Graph into which the weight will be spread
    @type g: networkx.DiGraph/networkx.MultiDiGraph
    @param max_it Number of iterations of spreading
    @type max_it: Integer
    @param max_depth The number of graph levelst to spread the value
    @type max_depth: Positive integer
    """
    assert(max_it > 0), "Number of iteration have to be greater than zero!"

    nnz = 0
    pers_v = dict()
    for n in g.nodes():
      pers_v[n] = g.node[n].get('value', 0)
      nnz += pers_v[n]
    try:
      rank = \
        networkx.pagerank(g, personalization=pers_v, max_iter=max_it) if nnz > 0 \
          else networkx.pagerank(g, max_iter=max_it)
      for node, r in rank.iteritems():
        g.node[node]['value'] = r
    except ZeroDivisionError:
      import sys
      print >> sys.stderr, 'Division by zero while PageRank!'