Beispiel #1
0
    def __init__(self, model_graph, node_sizes, node_cpds=[]):
        """
        Initializes BNET object.

        model_graph: Numpy array or Scipy.sparse matrix
            A matrix defining the edges between nodes in the network. If
            graph[i, j] = 1 there exists a directed edge from node i to j.

        node_sizes: List or Int
            A list of the possible number of values a discrete
            node can have. If node_sizes[i] = 2, then the discrete node i
            can have one of 2 possible values, such as True or False. If
            this parameter is passed as an integer, it indicates that all
            nodes have the size indicated by the integer.

        node_cpds: List of CPD objects (cpds.py)
            A list of the CPDs for each node in the BNET.
        """
        """Set the data members to the input values"""
        self.model_graph = model_graph
        self.num_nodes = model_graph.shape[0]
        self.node_sizes = node_sizes.copy()
        self.cpds = node_cpds

        """Convert the graph to a sparse matrix"""
        if ((type(model_graph) == type(np.matrix([0]))) or
           (type(model_graph) == type(np.array([0])))):
            model_graph = sparse.lil_matrix(model_graph)
            
        """Obtain topological order"""
        self.order = graph.topological_sort(self.model_graph)
Beispiel #2
0
 def test_topological_sort(self):
     """
     FUNCTION: topological_sort, in graph.py.
     """
     """Execute the function"""
     order = graph.topological_sort(self.dag)
     """Assert that the functions output matches the expected output"""
     assert order == [0, 1, 2, 3]
Beispiel #3
0
    def test_topo_sort(self):
        g = Graph(n_vertices=3, edges=[(1, 2)])
        l = topological_sort(g)
        self.verify_linearization(l, g)

        g = Graph(n_vertices=5, edges=[(1, 2), (3, 1), (3, 4)])
        l = topological_sort(g)
        self.verify_linearization(l, g)

        g = Graph(n_vertices=6,
                  edges=[(1, 3), (2, 1), (2, 4), (4, 3), (3, 6), (3, 5)])
        l = topological_sort(g)
        print(l)
        self.verify_linearization(l, g)

        # Raise exception if cycle
        g = Graph(n_vertices=3, edges=[(1, 2), (2, 3), (3, 1)])
        self.assertRaises(ValueError, topological_sort, g)
    def test_topological_sort(self):
        """
        FUNCTION: topological_sort, in graph.py.
        """
        """Execute the function"""
        order = graph.topological_sort(self.dag)

        """Assert that the functions output matches the expected output"""
        assert order == [0, 1, 2, 3]
Beispiel #5
0
    def __init__(self,
                 adj_mat,
                 node_sizes,
                 discrete_nodes=None,
                 continuous_nodes=None,
                 node_cpds=None):
        """
        Initializes BNET object.

        adj_mat: Numpy array or Scipy.sparse matrix
            A matrix defining the edges between nodes in the network. If
            graph[i, j] = 1 there exists a directed edge from node i to j.

        node_sizes: List or Int
            A list of the possible number of values a discrete
            node can have. If node_sizes[i] = 2, then the discrete node i
            can have one of 2 possible values, such as True or False. If
            this parameter is passed as an integer, it indicates that all
            nodes have the size indicated by the integer.

        node_cpds: List of CPD objects (node_cpds.py)
            A list of the CPDs for each node in the BNET.

        TODO:
            - ability for different nodes to share the same CPD
        """
        """Set the data members to the input values"""
        super(bnet, self).__init__(node_sizes, discrete_nodes,
                                   continuous_nodes)

        self.adj_mat = adj_mat
        self.num_nodes = adj_mat.shape[0]
        self.node_sizes = node_sizes.copy()

        self.node_cpds_N = len(self.node_sizes)

        if node_cpds is not None:
            #self.node_cpds_N = len(set(node_cpds))  determine shared node_cpds using set
            assert len(node_cpds)==self.node_cpds_N,\
                "Number of node CPDs inconsistent with model"
            self.node_cpds = np.array(node_cpds)
        else:
            self.node_cpds = np.array([], dtype=object)

        self.node_cpds_meta = [None] * self.node_cpds_N
        """Convert the graph to a sparse matrix"""
        if ((type(adj_mat) == type(np.matrix([0])))
                or (type(adj_mat) == type(np.array([0])))):
            adj_mat = sparse.lil_matrix(adj_mat)
        """Obtain topological order"""
        self.order = graph.topological_sort(self.adj_mat)
    def __init__(self, adj_mat, node_sizes, clqs, lattice=False):
        """
        Initializes MRF object.

        adj_mat: Numpy array or Scipy.sparse matrix
            A matrix defining the edges between nodes in the network. If
            graph[i, j] = 1 there exists a undirected edge from node i to j.

        node_sizes: List or Int
            A list of the possible number of values a discrete
            node can have. If node_sizes[i] = 2, then the discrete node i
            can have one of 2 possible values, such as True or False. If
            this parameter is passed as an integer, it indicates that all
            nodes have the size indicated by the integer.

        clqs: List of clique objects (cliques.py)
            A list of the cliques in the MRF.

        lattice: Bool
            Lattice is true if this MRF has a lattice graph structure, and
            false otherwise.
        """
        """Assign the input values to their respective internal data members"""
        self.lattice = lattice
        self.num_nodes = adj_mat.shape[0]
        self.cliques = clqs
        self.node_sizes = np.array(node_sizes)
        self.node_sizes_org = np.array(self.node_sizes)

        """Convert the graph to a sparse matrix"""
        if ((type(adj_mat) == type(np.matrix([0]))) or
           (type(adj_mat) == type(np.array([0])))):
            adj_mat = sparse.lil_matrix(adj_mat)

        """In an MRF, all edges are bi-directional"""
#        self.adj_mat = adj_mat - \
#                           sparse.lil_diags([sparse.extract_diagonal(\
#                               adj_mat)], [0], (adj_mat.shape[0], \
#                                                    adj_mat.shape[0]))\
#                                                    + adj_mat.T

        self.adj_mat = adj_mat

        """
        Obtain elimination order, which is just the input order in the case
        of a lattice.
        """
        if self.lattice == True:
            self.order = range(0, self.adj_mat.shape[0])
        else:
            self.order = graph.topological_sort(self.adj_mat)
Beispiel #7
0
    def __init__(self, adj_mat, node_sizes, clqs, lattice=False):
        """
        Initializes MRF object.

        adj_mat: Numpy array or Scipy.sparse matrix
            A matrix defining the edges between nodes in the network. If
            graph[i, j] = 1 there exists a undirected edge from node i to j.

        node_sizes: List or Int
            A list of the possible number of values a discrete
            node can have. If node_sizes[i] = 2, then the discrete node i
            can have one of 2 possible values, such as True or False. If
            this parameter is passed as an integer, it indicates that all
            nodes have the size indicated by the integer.

        clqs: List of clique objects (cliques.py)
            A list of the cliques in the MRF.

        lattice: Bool
            Lattice is true if this MRF has a lattice graph structure, and
            false otherwise.
        """
        """Assign the input values to their respective internal data members"""
        self.lattice = lattice
        self.num_nodes = adj_mat.shape[0]
        self.cliques = clqs
        self.node_sizes = np.array(node_sizes)
        self.node_sizes_org = np.array(self.node_sizes)
        """Convert the graph to a sparse matrix"""
        if ((type(adj_mat) == type(np.matrix([0])))
                or (type(adj_mat) == type(np.array([0])))):
            adj_mat = sparse.lil_matrix(adj_mat)
        """In an MRF, all edges are bi-directional"""
        #        self.adj_mat = adj_mat - \
        #                           sparse.lil_diags([sparse.extract_diagonal(\
        #                               adj_mat)], [0], (adj_mat.shape[0], \
        #                                                    adj_mat.shape[0]))\
        #                                                    + adj_mat.T

        self.adj_mat = adj_mat
        """
        Obtain elimination order, which is just the input order in the case
        of a lattice.
        """
        if self.lattice == True:
            self.order = range(0, self.adj_mat.shape[0])
        else:
            self.order = graph.topological_sort(self.adj_mat)
    def __init__(self, adj_mat, node_sizes, discrete_nodes=None, continuous_nodes=None, node_cpds=None):
        """
        Initializes BNET object.

        adj_mat: Numpy array or Scipy.sparse matrix
            A matrix defining the edges between nodes in the network. If
            graph[i, j] = 1 there exists a directed edge from node i to j.

        node_sizes: List or Int
            A list of the possible number of values a discrete
            node can have. If node_sizes[i] = 2, then the discrete node i
            can have one of 2 possible values, such as True or False. If
            this parameter is passed as an integer, it indicates that all
            nodes have the size indicated by the integer.

        node_cpds: List of CPD objects (node_cpds.py)
            A list of the CPDs for each node in the BNET.

        TODO:
            - ability for different nodes to share the same CPD
        """
        """Set the data members to the input values"""
        super(bnet, self).__init__(node_sizes, discrete_nodes, continuous_nodes)
        
        self.adj_mat = adj_mat
        self.num_nodes = adj_mat.shape[0]
        self.node_sizes = node_sizes.copy()

        self.node_cpds_N = len(self.node_sizes)

        if node_cpds is not None:
            #self.node_cpds_N = len(set(node_cpds))  determine shared node_cpds using set
            assert len(node_cpds)==self.node_cpds_N,\
                "Number of node CPDs inconsistent with model"
            self.node_cpds = np.array(node_cpds)
        else:
            self.node_cpds = np.array([],dtype=object)

        self.node_cpds_meta = [None]*self.node_cpds_N

        """Convert the graph to a sparse matrix"""
        if ((type(adj_mat) == type(np.matrix([0]))) or
           (type(adj_mat) == type(np.array([0])))):
            adj_mat = sparse.lil_matrix(adj_mat)
            
        """Obtain topological order"""
        self.order = graph.topological_sort(self.adj_mat)
    def dag_shortest_path(self, g : _g.Graph, s : _g.Vertex):
        '''
        按顶点的拓扑序列对某加权dag图(有向无回路图)G=(V,E)的边进行松弛后
        就可以在Θ(V+E)时间内计算出单源最短路径.

        Args
        ===
        `g` : 有向无回路图G=(V,E) 

        `s` : 源顶点

        '''
        sort_list = _g.topological_sort(g)
        self.initialize_single_source(g, s)
        for u in sort_list:
            u = g.veterxs_atkey(u)
            adj = g.getvertexadj(u)
            for v in adj:
                edge = g.getedge(u, v)
                self.relax(u, v, edge.weight)
Beispiel #10
0
def main(filename):
  with open(filename, 'r') as f:
    edges = parse(get_lines(filename))
    graph = make_graph(edges)
  source = raw_input("Source vertex:")
  while not in_graph(graph, source):
    source = raw_input("Bad source\nSource vertex:")
    
  vec, back_edges = topological_sort(graph)
  negs = False
  for _, _, w in edges:
    if w < 0:
      negs = True
  cycle = len(back_edges) > 0

  if not cycle:
    print "Graph is a DAG, running DAG SP algorithm"
    d, parent = dag_sp(graph, vec, source)
  elif not negs:
    print "Graph has no negative edges, running Dijkstra's algorithm"
    d, parent = dijkstra(graph, source)
  else:
    print "Running Bellman-Ford algorithm"
    d, parent = bellman_ford(graph, source)

  if d == None: ## Sufficent to assume parent is also None
    print "Graph contains a negative-weight cycle."
    sys.exit(0)

  while True:
    dest = raw_input("Destination vertex:")
    while not in_graph(graph, dest):
      dest = raw_input("Bad destination\nDestination vertex:")
    dist, order = get_shortest_path(d, parent, dest)
    if dist >= INFINITY:
      print "There is no way to reach the destination from the source"
    else:
      print "The distance between the vertices is %d" % dist
      print "The shortest path is %s" % pprint_path(order)
Beispiel #11
0
def compute_p0_matrix_single_r(net, ncnodes, R, r_index):
  # MATLAB: function p0matrix = compute_p0_matrix(net, ncnodes, R)
  # Computes the loss probability p0 for every node and for every receiver
  #  p0(node, receiver) = the probability that a packet sent by node 'node' will not reach receiver 'receiver', even if it is duplicated along the way
  #  (i.e. neither the sent packet nor any of its possible duplicates won't reach the receiver)
  #
  # Inputs:
  #       net
  #       ncnodes      = vector of NC nodes (to exclude form normal
  #                          computations)
  # Outputs:
  #     p0matrix = array holding the p0 value of every node, for every
  #     receiver
  #
  # Nicolae Cleju, EPFL, 2008/2009, TUIASI, 2009/2010
  #==========================================================================
  
  #-------------------------------------------
  # Init
  #-------------------------------------------
  
  # Total number of nodes
  #N = size(net.capacities,1);
  N = net['capacities'].shape[0]

  # Number of input and output packets
  #b_i = sum(net.capacities .* (1-net.errorrates), 1);
  #b_o = sum(net.capacities, 2)';
  b_i = numpy.sum(net['capacities'] * (1 - net['errorrates']), 0)
  b_o = numpy.sum(net['capacities'], 1)

  # Hold the transpose of capacities for faster access
  capT = net['capacities'].T

  # The topological order
  #order = topological_order(sparse(net.capacities));
  #xs, ys = numpy.nonzero(net['capacities'])
  #order = graph.topological_sort([(xs[i], ys[i]) for i in range(xs.size)])
  order = graph.topological_sort(net['capacities'])

  # Init output matrix
  #p0matrix = zeros(N, numel(net.receivers));
  #p0matrix = zeros(N, 1);
  #p0matrix = numpy.zeros(N, net['rceivers'].size)
  p0matrix = numpy.zeros(N)

  # Holds floor(replication rate)
  #M = zeros(1,N);
  M = numpy.zeros(N)

  # Holds the probability that an input packet is replicated M times in node n
  #p_rep_M = zeros(1,N);
  p_rep_M = numpy.zeros(N)

  # Holds the probability that an input packet is not lost in a buffer overflow in node n
  #p_ov = zeros(1,N);
  p_ov = numpy.zeros(N)

  # for each client c seperately
  #for r_index = 1:numel(net.receivers)
  #r = net.receivers(r_index);
  #for r_index in range(net['receivers'].size):
  r = net['receivers'][r_index]

  # Prepare data
  # For every node in topo order
  #for n = order'
  for n in order:

      # If not source
      #if b_i(n) ~= 0
      if b_i[n] != 0:
          
          # M = floor(replication rate)
          #M(n) = floor(R(r_index,n));
          M[n] = math.floor(R[r_index,n])

          # Probability of M(n) - for linear interpolation
          #p_rep_M(n) = 1 - (  R(r_index,n) - M(n)  );
          p_rep_M[n] = 1. - (  R[r_index,n] - M[n]  )

          # Probability of not buffer overflow
          #if b_o(n) > b_i(n)
          if b_o[n] > b_i[n]:
              #p_ov(n) = 0;       # No overflow
              p_ov[n] = 0.
          else:
              #p_ov(n) = 1 - b_o(n) /b_i(n) ;    # Buffer overflow
              p_ov[n] = 1. - b_o[n] / b_i[n]
          #end
      #end
  #end
  
  # restrict list only to nodes ahead of the receiver (without the receiver itself)
  #partial_limit = find(order == r, 1) - 1;
  partial_limit = numpy.nonzero(order == r)[0] - 1;
  
  # for the receiver, initialize p0 to 0
  #p0matrix(r, r_index) = 0; #0# losses, 100# one copy
  #p0matrix(r) = 0; %0% losses, 100% one copy
  #p0matrix[r, r_index] = 0.
  p0matrix[r] = 0. #0% losses, 100% one copy
  
  # for all nodes after the receiver (which cannot reach the receiver) set the p0 to 1 (100# loss)
  #for n_index = (find(order == r, 1) + 1) : N
  for n_index in range((numpy.nonzero(order == r)[0] + 1), N):
      #n = order(n_index);
      n = order[n_index]
      #p0matrix(n, r_index) = 1;
      #p0matrix(n) = 1;
      #p0matrix[n, r_index] = 1.
      p0matrix[n] = 1.
  #end
  
  # go only from the receiver r backwards
  #for u_index = partial_limit:-1:1
  for u_index in range(partial_limit,-1,-1):  # need to include the end, 0
      #u = order(u_index);
      u = order[u_index]
      
      # find child nodes of node u
      #children = find(net.capacities(u,:));
      #children = find(capT(:,u));
      #children = numpy.nonzero(net['capacities'][u,:])
      children = numpy.nonzero(capT[:,u])[0]
      
      # if u has no children, set p0 to 1 (100# loss)
      #  this may happen if u is another receiver sitting before the
      #  current one in the topo order
      #if (isempty(children))
      if children.size == 0:
          #p0matrix(u,r_index) = 1;
          #p0matrix(u) = 1;
          #p0matrix[u,r_index] = 1.
          p0matrix[u] = 1.
      else:
          
          # initialize sum of children probabilities
          #p0_partsum = 0;
          p0_partsum = 0.
          
          # for each child
          #for child_index = 1:numel(children)
          for child_index in range(children.size):
             #child = children(child_index);
             child = children[child_index]
            
             # initialize p0 of u through this child
             #p0_child = 0;
             p0_child = 0.

             # probability that a packet from node 'u' is sent on the link to child 'child'
             #rho = net.capacities(u,child) / b_o(u);
             rho = net['capacities'][u,child] / b_o[u]
             
             #------------------------------------------------------------------
             # if child is receiver, loss prob = rho * errorrate
             #if child == r
             if child == r:
                 #p0_child = rho * net.errorrates(u,child);
                 p0_child = rho * net['errorrates'][u,child]

             else:
                 # child is not the receiver                   
                 
                 # make sure child is not a NC node (not in ncnodes)
                 #if any(ncnodes == child)
                 #if child == ncnodes
                 #if numpy.any(ncnodes == child):
                 #if ncnodes.contains(child):
                 if child in ncnodes:
                     
                     # child is NC node, make p0 equal to 1, because we exclude paths which go through NC nodes
                     #p0_child = rho * 1; # 100# losses
                     p0_child = rho * 1. # 100# losses

                 else:  
                     # child is not a NC node, process it
                     # p0 = rho * (probab. lost on the link from u to child + 
                     #              + not lost on the link. but lost in a buffer overflow in child
                     #              + not lost on the link, survives buffer overflow, is replicated M times and all M+1 copies are lost after the child node
                     #                      or is replicated M+1 times and all M+2 copies are lost after the chlid node)

                      # if is replicating node, no chance of buffer
                      # overflow
  #                         if new_p_ov(child) == 1
  #                             p0_child  = rho * (...
  #                                             errorrates(u,child) + ...
  #                                             (1-errorrates(u,child)) * ( new_p_rep_M(child)*p0(child, r_index)^(new_M(child)) + (1-new_p_rep_M(child))*p0(child, r_index)^(new_M(child) + 1)));
  #                         else
  #                             p0_child  = rho * (...
  #                                             errorrates(u,child) + ...
  #                                             (1-errorrates(u,child))*(1-new_p_ov(child)) + ...
  #                                             (1-errorrates(u,child)) * new_p_ov(child) * p0(child, r_index));
  #                         end          
                      #pi = net.errorrates(u,child);
                      pi = net['errorrates'][u,child]
                      #Beta = p_ov(child);
                      Beta = p_ov[child]
                      #exponent = R(r_index, child);
                      exponent = R[r_index, child]
                      #if exponent < 1 exponent = 1; end
                      if exponent < 1:
                        exponent = 1
                      #p0_child = rho * (pi + (1-pi)*Beta + (1-pi)*(1-Beta)* p0matrix(child,r_index)^exponent);
                      #p0_child = rho * (pi + (1-pi)*Beta + (1-pi)*(1-Beta)* p0matrix(child)^exponent);
                      #p0_child = rho * (pi + (1-pi)*Beta + (1-pi)*(1-Beta)* p0matrix[child,r_index]**exponent)
                      p0_child = rho * (pi + (1-pi)*Beta + (1-pi)*(1-Beta)* p0matrix[child]**exponent)

                      # Sanity check
                      # Comment this to increase speed
                      #assert(~isnan(p0_child));
                 #end

             #end

             # add p0 to partial sum
             #p0_partsum = p0_partsum + p0_child;
             p0_partsum = p0_partsum + p0_child
          #end

          # check 0 < p0 < 1, allow for some margin of numerical error
          #if p0_partsum < -1e-6 || p0_partsum > (1 + 1e-6)
          if p0_partsum < -1e-6 or p0_partsum > (1 + 1e-6):
              #disp(['p0 = ' num2str(p0_partsum)]);
              print('p0 = ' + str(p0_partsum))
              #error('Error: p0 not ok!');
              raise
          #end
          
          # round small numerical errors
          #if -1e-6 < p0_partsum && p0_partsum < 0
          if -1e-6 < p0_partsum and p0_partsum < 0:
              #p0_partsum = 0;
              p0_partsum = 0.
          #end
          #if 1 < p0_partsum && p0_partsum < (1+(1e-6))
          if 1 < p0_partsum and p0_partsum < (1+(1e-6)):
              #p0_partsum = 1;
              p0_partsum = 1.
          #end
          
          # Save final probability density function
          #p0matrix(u,r_index) = p0_partsum;
          #p0matrix(u) = p0_partsum;
          #p0matrix[u,r_index] = p0_partsum
          p0matrix[u] = p0_partsum
      #end
  #end
  #end
  
  return p0matrix
Beispiel #12
0
#!/usr/bin/env python
from input import get_lines, parse
from graph import make_graph, topological_sort
import sys
from os.path import isfile

filename = sys.argv[1]
if not isfile(filename):
  exit(1)

lines = get_lines(filename)
edges = parse(lines)
graph = make_graph(edges)
path, back_edges = topological_sort(graph)

if not back_edges:
  print "The path is: " + str(path)
else:
  print "The graph is cyclic. Back edges: " + str(back_edges)

Beispiel #13
0
from input import get_lines, parse
from graph import make_graph, topological_sort
from sp import dag_sp, bellman_ford, dijkstra, get_shortest_path

edges = parse(get_lines("dag.txt"))
graph = make_graph(edges)
vec, backs = topological_sort(graph)

negs = False
for _, _, w in edges:
    if w < 0:
        negs = True
cycle = len(backs) > 0

if negs:
    print "Negatives"
if cycle:
    print "Cyclic"
    print backs

dag_sol = dag_sp(graph, vec, '1')
bf_sol = bellman_ford(graph, '1')
dijk_sol = dijkstra(graph, '1')

print dag_sol
print bf_sol
print dijk_sol

d, parent = dag_sol
print get_shortest_path(d, parent, '5')
Beispiel #14
0
def make_node_silent(net,node):
    #MATLAB function newnet = make_node_silent(net, node)
    # Generates a new net structure by removing all outgoing links of node 'node' and then adjusting all following links of the graphs as to preserve
    #  the same replication rate of all nodes
    # The replication rate of all nodes is thus preserved in the new net (except of course node 'node' whose outgoing links are removed)
    #
    # Inputs:
    #   net  =  network configuration structure, with the fields:
    #         capacities  = capacities matrix, in packets (A(i,j) = x means there is an edge from node i to node j of capacity x packets)
    #         errorrates  = error rates matrix
    #         sources     = vector containing the source nodes
    #         helpers     = vector containing the helper nodes (helper = not source and not client)
    #         receivers   = vector containing the client (receiver) nodes
    #   node =  the node whose outgoing links are to be removed
    #
    # Outputs:
    #   newnet = the new network configuration structure, containing the same fields as the input one
    #
    # Nicolae Cleju, EPFL, 2008/2009, TUIASI, 2009/2010
    #==========================================================================
    
    # Create output structure
    #newnet = net;
    #newnet = net.copy()
    # BUG: dict.copy() is shallow copy, so the underlying arrays were not copied    
    #  use copy.deepcopy() instead
    newnet = copy.deepcopy(net)
    
    # Compute the original NI and NO
    #NI = sum(net.capacities .* (1-net.errorrates), 1);
    #NO = sum(net.capacities, 2);    
    NI = numpy.sum(net['capacities'] * (1.-net['errorrates']), 0)
    NO = numpy.sum(net['capacities'], 1)
    
    # Compute the original Nrepl
    #Nrepl = NO' - NI;
    #Nrepl(Nrepl < 0) = 0;
    #Nrepl(net.sources) = 0;
    Nrepl = NO - NI
    Nrepl[Nrepl < 0] = 0
    Nrepl[net['sources']] = 0
    
    # Compute topological order
    #order = topological_order(sparse(net.capacities));
    #xs, ys = numpy.nonzero(net['capacities'])
    #order = graph.topological_sort([(xs[i], ys[i]) for i in range(xs.size)])    
    order = graph.topological_sort(net['capacities'])
    
    # remove node's outgoing links
    #newnet.capacities(node, :) = zeros(1, newnet.nnodes);
    #newnet.errorrates(node, :) = zeros(1, newnet.nnodes);
    newnet['capacities'][node, :] = numpy.zeros(newnet['nnodes'])
    newnet['errorrates'][node, :] = numpy.zeros(newnet['nnodes'])
    
    # For all following nodes in the topo order, adjust outgoing links to maintain the original replication rate
    
    # generate partial list with all nodes following 'node' in the topo order,
    #partial_list = order( (find(order == node, 1) + 1) : numel(order) ); 
    partial_list = order[ (numpy.nonzero(order == node)[0] + 1) : ]
    
    #newNO = NO;
    #newNI = NI;
    newNO = NO.copy()
    newNI = NI.copy()
    
    #for n_index = 1:numel(partial_list)
    for n_index in range(partial_list.size ):
        #n = partial_list(n_index);
        n = partial_list[n_index]
        
        # compute the new NI
        #newNI(n) = sum(newnet.capacities(:,n) .* (1-newnet.errorrates(:,n)));
        newNI[n] = numpy.sum(newnet['capacities'][:,n] * (1-newnet['errorrates'][:,n]))
        
        # if new NI < original NI, adjust outgoing links with the same factor
        #if (newNI(n) < NI(n))
        if newNI[n] < NI[n]:
            #newnet.capacities(n,:) = (newNI(n)/NI(n)) * newnet.capacities(n,:);
            newnet['capacities'][n,:] = (newNI[n]/NI[n]) * newnet['capacities'][n,:]
        #end
        
        # compute the new NO
        #newNO(n) = sum(newnet.capacities(n,:));
        newNO[n] = numpy.sum(newnet['capacities'][n,:])
    #end
    
    # checking
    #f1 = (NI ./ NO');
    f1 = NI / NO
    #f1(isinf(f1)) = 0;
    f1[numpy.isinf(f1)] = 0
    #f1(isnan(f1)) = 0;
    f1[numpy.isnan(f1)] = 0
    #f2 = (newNI ./ newNO');
    f2 = newNI / newNO
    #f2(isinf(f2)) = 0;
    f2[numpy.isinf(f2)] = 0
    #f2(isnan(f2)) = f1(isnan(f2));
    f2[numpy.isnan(f2)] = f1[numpy.isnan(f2)]
    #diff =  f1 - f2;
    diff =  f1 - f2
    #assert(all(diff.^2 < 0.001));
    assert(numpy.all(diff**2 < 0.001))
    
    return newnet
    
Beispiel #15
0
import re

from graph import Graph, is_dag, topological_sort, find_longest_path_distance

n_vertices = None
edges = []

print("Specify a graph. (A blank line stops input)")
while True:
    value = input()

    # Stop input line only contains white space
    if re.match('^\s*$', value):
        break

    if n_vertices is None:
        n_vertices = int(value)
    else:
        u, v = map(int, value.split(','))
        edges.append((u, v))

graph = Graph(n_vertices, edges)
print('YES') if is_dag(graph) else print('NO')
print(*topological_sort(graph))
print(find_longest_path_distance(graph, 1))
Beispiel #16
0
def convert_subgraph_to_module(graph, full_graph, num_subgraphs, module_name,
                               initialize_weights, model_template_filename,
                               output_filename):
    model_template = open(model_template_filename, 'r').read()
    nodes = graph.topological_sort()
    f1 = "../../profiler/image_classification/models/language_modelling"
    f2 = "../../profiler/image_classification/models/ImageNet"
    import_statements = [
        f"import sys \nsys.path.insert(0, \"{f1}\")\nimport transformer as transformer_layers\n \nsys.path.insert(0, \"{f2}\")\nimport resnet\n"
    ]

    module_methods = []

    counter = 0
    layer_names = {}
    layer_names_and_declarations = []
    function_definition = []
    input_names = get_input_names(graph, full_graph)
    num_inputs = len(input_names)
    output_names = input_names.copy()
    sources = graph.sources()

    # Now, generate expressions for each node.
    # Iterate through nodes in topological order, and add output_name mappings for
    # each expression. Use this output_name mapping when generating expressions
    # in the model's implementation file.
    # TODO: Make sure that nodes with multiple inputs have the inputs in the
    # right order (even though this probably does not matter in practice).
    for node_id in input_names:
        output_name = "out%d" % counter
        function_definition.append("%s = %s.clone()" %
                                   (output_name, input_names[node_id]))
        output_names[node_id] = output_name
        counter += 1

    for node in nodes:
        layer_call = None
        layer_name = "self.layer%d" % counter
        output_name = "out%d" % counter
        # layer_declaration = "torch.nn.%s" % (
        #     node.node_desc.replace("inplace", "inplace=True"))
        print("=== ", node.node_desc[:node.node_desc.find('(')])
        in_resnet = hasattr(resnet, node.node_desc[:node.node_desc.find('(')])
        if in_resnet:
            layer_declaration = "resnet.%s" % (node.node_desc)
            print("found ", node.node_desc[:node.node_desc.find('(')],
                  "in resnet")
        elif hasattr(torch.nn, node.node_desc[:node.node_desc.find('(')]):
            layer_declaration = "torch.nn.%s" % (node.node_desc)
            print("found in torch.nn")
        elif hasattr(transformer_layers,
                     node.node_desc[:node.node_desc.find('(')]):
            layer_declaration = "transformer_layers.%s" % (node.node_desc)
            print("found in transformer layers")

        elif node.node_desc.startswith("Input"):
            layer_declaration = "torch.nn.%s" % (node.node_desc)
        else:
            print("not found ", node.node_desc[:node.node_desc.find('(')],
                  "anywhere")
            print(node.node_desc)
            exit(-1)
        layer_names[node.node_id] = layer_name
        if node.node_id not in output_names:
            output_names[node.node_id] = output_name

        # Skip layers that don't need a declaration (example: '+=').
        for declaration in declaration_specialcase:
            if node.node_desc.startswith(declaration):
                found = True
                if declaration == "EmuBidirLSTM":
                    m = re.search(r'.*LSTM\((\d+), (\d+)\).*', node.node_desc)
                    input_size = int(m.group(1))
                    hidden_size = int(m.group(2))
                    layer_declaration = "EmuBidirLSTM(%d, %d)" % (input_size,
                                                                  hidden_size)
                    import_statements.append(
                        "from seq2seq.models.encoder import EmuBidirLSTM")
                elif declaration == "RecurrentAttention":
                    m = re.search(r'.*LSTM\((\d+), (\d+)\).*', node.node_desc)
                    input_size = int(m.group(1))
                    hidden_size = int(m.group(2))
                    m = re.search(r'.*in_features=(\d+), out_features=(\d+).*',
                                  node.node_desc)
                    context_size = int(m.group(1))
                    layer_declaration = "RecurrentAttention(%d, %d, %d)" % (
                        input_size, hidden_size, context_size)
                    import_statements.append(
                        "from seq2seq.models.decoder import RecurrentAttention"
                    )
                elif declaration == "Classifier":
                    m = re.search(r'.*in_features=(\d+), out_features=(\d+).*',
                                  node.node_desc)
                    in_features = int(m.group(1))
                    out_features = int(m.group(2))
                    layer_declaration = "Classifier(%d, %d)" % (in_features,
                                                                out_features)
                    import_statements.append(
                        "from seq2seq.models.decoder import Classifier")
                elif declaration == "MaskConv":
                    node_desc = node.node_desc
                    modules = node_desc.split("    ")[1:-1]
                    module_declarations = []
                    for module in modules:
                        module_declaration = "torch.nn." + module.split(
                            ": ")[1].replace("inplace", "inplace=True")
                        module_declarations.append(module_declaration)
                    layer_declaration = "MaskConv(torch.nn.Sequential(%s))" % ",\n            ".join(
                        module_declarations)
                    import_statements.append("from model import MaskConv")
                    module_methods.append(
                        """def get_seq_lens(self, input_length):
        seq_len = input_length
        for m in %s.modules():
            if type(m) == torch.nn.modules.conv.Conv2d:
                seq_len = ((seq_len + 2 * m.padding[1] - m.dilation[1] * (m.kernel_size[1] - 1) - 1) / m.stride[1] + 1)
        return seq_len.int()""" % layer_name)
                elif declaration == "BatchRNN":
                    if "batch_norm" in node.node_desc:
                        batch_norm = True
                    else:
                        batch_norm = False
                    if "LSTM" in node.node_desc:
                        rnn_type = "torch.nn.LSTM"
                        m = re.search(
                            r'LSTM\((\d+), (\d+), bidirectional=([a-zA-Z]+)\)',
                            node.node_desc)
                        input_size = int(m.group(1))
                        hidden_size = int(m.group(2))
                        bidirectional = m.group(3)
                    elif "GRU" in node.node_desc:
                        rnn_type = "torch.nn.GRU"
                        m = re.search(
                            r'GRU\((\d+), (\d+), bidirectional=([a-zA-Z]+)\)',
                            node.node_desc)
                        input_size = int(m.group(1))
                        hidden_size = int(m.group(2))
                        bidirectional = m.group(3)
                    else:
                        # TODO: Do something else?
                        pass
                    # TODO: Pass remaining arguments.
                    # TODO: Get hidden and input size.
                    layer_declaration = "BatchRNN(%d, %d, rnn_type=%s, batch_norm=%s, bidirectional=%s)" % (
                        input_size, hidden_size, rnn_type, batch_norm,
                        bidirectional)
                    import_statements.append("from model import BatchRNN")
                elif declaration == "ResizeInput":
                    layer_declaration = "ResizeInput()"
                    import_statements.append("from model import ResizeInput")
                elif declaration == "SequenceWise":
                    node_desc = node.node_desc
                    modules = node_desc[:-2].split("  ")[1:]
                    module_declarations = []
                    for module in modules:
                        module_declaration = "torch.nn." + module.split(
                            ": ")[1].replace("inplace", "inplace=True")
                        module_declarations.append(module_declaration)
                    layer_declaration = "SequenceWise(torch.nn.Sequential(%s))" % ",\n            ".join(
                        module_declarations)
                    import_statements.append("from model import SequenceWise")
                elif declaration == "InferenceBatchSoftmax":
                    layer_declaration = "InferenceBatchSoftmax()"
                    import_statements.append(
                        "from model import InferenceBatchSoftmax")
                break

        import_statements = list(set(import_statements))
        found = False
        for declaration in declaration_whitelist:
            if node.node_desc.startswith(declaration):
                found = True
        if not found:
            layer_names_and_declarations.append(
                (layer_name, layer_declaration))
        if node.node_id in full_graph.in_edges:
            in_edges = full_graph.in_edges[node.node_id]
        else:
            in_edges = []
        if len(in_edges) == 0 and node.node_desc.startswith("Input"):
            pass  # Don't need to do anything for this case.
        else:
            if node.node_desc.startswith("Size"):
                assert (len(in_edges) == 1)
                m = re.search(r'Size\((-?\d+)\)', node.node_desc)
                idx = int(m.group(1))
                layer_call = "%s = %s.size(%d)" % (
                    output_name, output_names[in_edges[0].node_id], idx)
            elif node.node_desc.startswith("View"):
                size_node_ids = []
                input_node_id = None
                for i in range(len(in_edges)):
                    if in_edges[i].node_desc.startswith("Size"):
                        size_node_id = in_edges[i].node_id
                        size_node_ids.append(size_node_id)
                    else:
                        input_node_id = in_edges[i].node_id
                m = re.search(r'View\((-?\d+)\)', node.node_desc)
                if m is None:
                    size_output_names = [
                        output_names[size_node_id]
                        for size_node_id in size_node_ids
                    ]
                    layer_call = "%s = %s.view(%s)" % (
                        output_name, output_names[input_node_id],
                        ", ".join(size_output_names))
                else:
                    size = int(m.group(1))
                    layer_call = "%s = %s.view(%s, %d)" % (
                        output_name, output_names[input_node_id],
                        output_names[size_node_id], size)
            elif node.node_desc.startswith("__getitem__"):
                assert (len(in_edges) == 1)
                m = re.search(r'__getitem__\((\d+)\)', node.node_desc)
                idx = int(m.group(1))
                if "hidden" in in_edges[0].node_desc:
                    layer_call = "%s = None" % output_name
                else:
                    layer_call = "%s = %s[%d]" % (
                        output_name, output_names[in_edges[0].node_id], idx)
            elif node.node_desc.startswith("Add"):
                assert (len(in_edges) == 2)
                node1 = in_edges[0]
                node2 = in_edges[1]
                if len(full_graph.edges[node1.node_id]) > 1:
                    tmp = node1
                    node1 = node2
                    node2 = tmp
                layer_call = "%s = %s + %s" % (output_names[node1.node_id],
                                               output_names[node1.node_id],
                                               output_names[node2.node_id])
                output_names[node.node_id] = output_names[node1.node_id]
            elif node.node_desc.startswith("Mul"):
                assert (len(in_edges) == 2)
                node1 = in_edges[0]
                node2 = in_edges[1]
                if len(full_graph.edges[node1.node_id]) > 1:
                    tmp = node1
                    node1 = node2
                    node2 = tmp
                layer_call = "%s = %s * %s" % (output_names[node1.node_id],
                                               output_names[node1.node_id],
                                               output_names[node2.node_id])
                output_names[node.node_id] = output_names[node1.node_id]
            elif node.node_desc.startswith("Concat"):
                m = re.search(r'Concat\((-?\d+)\)', node.node_desc)
                dim = int(m.group(1))
                layer_call = "%s = torch.cat([%s], %d)" % (
                    output_name, ", ".join([
                        output_names[in_node.node_id] for in_node in in_edges
                    ]), dim)
            elif node.node_desc.startswith("Transpose"):
                m = re.search(r'Transpose\((.+)\)', node.node_desc)
                args = m.group(1)
                assert (len(in_edges) == 1)
                node1 = in_edges[0]
                layer_call = "%s = %s.transpose(%s)" % (
                    output_name, output_names[node1.node_id], args)
            elif node.node_desc.startswith("hidden"):
                pass
            elif node.node_desc == "self.get_seq_lens":
                assert (len(in_edges) == 1)
                in_node = in_edges[0]
                layer_call = "%s = %s(%s)" % (output_name, node.node_desc,
                                              output_names[in_node.node_id])
            else:
                layer_call = "%s = %s(%s)" % (output_name, layer_name,
                                              ", ".join([
                                                  output_names[in_node.node_id]
                                                  for in_node in in_edges
                                              ]))
        if layer_call is not None:
            function_definition.append(layer_call)
        counter += 1

    # Ensure that outputs of a module are returned in the same order as
    # the original model implementation.
    # TODO: This might not work as intended for sub-graphs.
    full_graph.populate_depths()
    graph_output_names, _ = get_output_names(graph, full_graph, 0)
    for key in graph_output_names:
        graph_output_names[key] = output_names[key]
    output_names_list = get_tensor_names_list(graph_output_names)
    num_outputs = len(output_names_list)
    function_definition.append("return %s" %
                               get_output_tuple_str(output_names_list))

    # Layer declarations are added to the constructor of the module.
    # Function definitions are added to the `forward()' method of the
    # module.
    layer_declarations_str = "\n        ".join(
        ["%s = %s" % (x[0], x[1]) for x in layer_names_and_declarations])

    if initialize_weights:
        layer_declarations_str += "\n        self._initialize_weights()"
        module_methods.append("""def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, torch.nn.Conv2d):
                torch.nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    torch.nn.init.constant_(m.bias, 0)
            elif isinstance(m, torch.nn.BatchNorm2d):
                torch.nn.init.constant_(m.weight, 1)
                torch.nn.init.constant_(m.bias, 0)
            elif isinstance(m, torch.nn.Linear):
                torch.nn.init.normal_(m.weight, 0, 0.01)
                torch.nn.init.constant_(m.bias, 0)""")
    function_definition_str = "\n        ".join(function_definition)
    input_names_list = get_tensor_names_list(input_names)
    input_names = ", ".join(input_names_list)
    model = model_template % {
        "layer_declarations": layer_declarations_str,
        "function_definition": function_definition_str,
        "module_name": module_name,
        "inputs": input_names,
        "import_statements": "\n".join(import_statements),
        "module_methods": "\n\n".join(module_methods)
    }

    with open(output_filename, 'w') as f:
        f.write(model)
    return num_inputs, num_outputs
Beispiel #17
0
def Algo1_delay_computation(net, sim, ncnodes, prev_estim):
    #MATLAB function tc = Algo1_delay_computation(net, sim, ncnodes, prev_estim)
    
    ##compute_p0_matrix = @compute_p0_matrix;
    ##compute_p0_matrix = @compute_p0_matrix_optimized;
    
    # Precision for iterations
    #precision = 5e-2;
    precision = 5e-2
    
    # Number of nodes
    #N = size(net.capacities,1);
    N = net['capacities'].shape[0]
    
    # Nodes' input capacities
    #b_i = sum(net.capacities .* (1-net.errorrates), 1);
    b_i = numpy.sum(net['capacities'] * (1-net['errorrates']), 0)
    # Nodes' output capacities
    #b_o = sum(net.capacities, 2)';
    b_o = numpy.sum(net['capacities'], 1)
    
    # Generation size
    #gensize = sim.N;
    gensize = sim['N']
    
    # Initialize replication rates
    # Careful to avoid NaN = 0/0
    #R = zeros(1, numel(b_i));
    R = numpy.zeros(b_i.size)
    #R(b_i ~= 0) = b_o(b_i ~= 0) ./ b_i(b_i~=0);
    R[b_i!=0] = b_o[b_i != 0] / b_i[b_i!=0]
    #R = repmat(R, numel(net.receivers), 1);
    R = numpy.tile(R, (net['receivers'].size, 1))
    #Rinit = R;
    Rinit = R.copy()
    
    # Better estimate replication rates if previous delay estimates available
    #if ~isempty(prev_estim)
    #if prev_estim.size != 0:
    if prev_estim:
        #p0matrix_prevestim = compute_p0_matrix(net, prev_estim.ncnodes, R);
        p0matrix_prevestim = computings.compute_p0_matrix(net, prev_estim['ncnodes'], R)
        # Update R
        #R = update_R(R, net, p0matrix_prevestim, prev_estim.ncnodes, prev_estim.tc);
        R = updateR.update_R(R, net, p0matrix_prevestim, prev_estim['ncnodes'], prev_estim['tc'])
    else:
        #p0matrix_prevestim = compute_p0_matrix(net, [], R);
        p0matrix_prevestim = computings.compute_p0_matrix(net, numpy.array([]), R)
    #end
    
    # Nic: Python says: init tc
    tc = numpy.Inf * numpy.ones(net['receivers'].size)
    
    # Repeat until converged
    #converged_tc = false;
    converged_tc = False
    #prev_tc = Inf * ones(1, numel(net.receivers));
    prev_tc = numpy.Inf * numpy.ones(net['receivers'].size)
    #max_tc = zeros(1, numel(net.receivers));
    max_tc = numpy.zeros(net['receivers'].size)
    #niter = 0;
    niter = 0
    #maxiter = 50;
    maxiter = 50
    #while ~converged_tc && niter < maxiter
    while (not converged_tc) and (niter < maxiter):
    
        # Compute p0 matrix for all clients at once
        #p0matrix_allncnodes = compute_p0_matrix(net, ncnodes, R);
        p0matrix_allncnodes = computings.compute_p0_matrix(net, ncnodes, R)
        
        # Repeat for each client r
        #for r_idx = 1:numel(net.receivers)
        for r_idx in range(net['receivers'].size):
            #r = net.receivers(r_idx);
            #r = net['receivers'][r_idx]
            
            #Nc = zeros(1, N);
            Nc = numpy.zeros(N)
            
            #Nc(net.sources) = b_o(net.sources)' .* (1 - p0matrix_allncnodes(net.sources, r_idx));
            Nc[net['sources']] = b_o[net['sources']] * (1 - p0matrix_allncnodes[net['sources'], r_idx])
    
            # For each NC node u
            # Go in topo order
            #order = topological_order(sparse(net.capacities));
            #xs, ys = numpy.nonzero(net['capacities'])
            #order = graph.topological_sort([(xs[i], ys[i]) for i in range(xs.size)])                
            order = graph.topological_sort(net['capacities'])
            # is member returns a logical array of size(order) with 1 on the
            # positions where the node is in ncnodes
            #ncnodes_topo = order(ismember(order, ncnodes));
            ncnodes_topo = order[numpy.in1d(order,ncnodes)]
    
            # For each NC node u
            #for u_idx = 1:numel(ncnodes_topo)
            for u_idx in range(ncnodes_topo.size):
                #u = ncnodes_topo(u_idx);
                u = ncnodes_topo[u_idx]
    
                # Compute p0 matrix with only the previous NC ndoes
                ##p0matrix_prevNC = compute_p0_matrix(net, ncnodes_topo(1:u_idx-1), R);
                #p0matrix_prevNC_single_r = compute_p0_matrix_single_r(net, ncnodes_topo(1:u_idx-1), R, r_idx);
                p0matrix_prevNC_single_r = computings.compute_p0_matrix_single_r(net, ncnodes_topo[:u_idx], R, r_idx)
                
                # Compute t_c(u) with u SF
                ##tc1 = compute_tc(net, sim, ncnodes_topo(1:u_idx-1), Nc, p0matrix_prevNC(:,r_idx));
                #tc1 = compute_tc(net, sim, ncnodes_topo(1:u_idx-1), Nc, p0matrix_prevNC_single_r);
                tc1 = computings.compute_tc(net, sim, ncnodes_topo[:u_idx], Nc, p0matrix_prevNC_single_r)
                
                # Make node u silent
                #silent_net = make_node_silent(net,u);
                silent_net = dist_specific.make_node_silent(net,u)
                
                # Compute p0 matrix for silent network
                ##p0matrix_silent = compute_p0_matrix(silent_net, ncnodes_topo(1:u_idx-1), R);
                #p0matrix_silent_single_r = compute_p0_matrix_single_r(silent_net, ncnodes_topo(1:u_idx-1), R, r_idx);
                p0matrix_silent_single_r = computings.compute_p0_matrix_single_r(silent_net, ncnodes_topo[:u_idx], R, r_idx)
    
                # Compute t_c(u) with u silent
                ##tc2 = compute_tc(silent_net, sim, ncnodes_topo(1:u_idx-1), Nc, p0matrix_silent(:,r_idx));
                #tc2 = compute_tc(silent_net, sim, ncnodes_topo(1:u_idx-1), Nc, p0matrix_silent_single_r);
                tc2 = computings.compute_tc(silent_net, sim, ncnodes_topo[:u_idx], Nc, p0matrix_silent_single_r)
                
                #delta_tc = tc2 - tc1;
                #delta_tc = tc2 - tc1
                #delta_Nc = gensize * (1/tc1 - 1/tc2);
                delta_Nc = gensize * (1./tc1 - 1./tc2)
                 
                #sanity check
                #if delta_Nc < 0
                if delta_Nc < 0:
                    #delta_Nc = 0;
                    delta_Nc = 0.
                #end
                
                # Compute Nc(u) using equation 8
                # sanity check (avoid division by 0)
                #if abs( p0matrix_prevNC(u,r_idx) - 1) < 1e-6
                if abs( p0matrix_prevNC_single_r[u] - 1) < 1e-6:
                    #Nc(u) = 0;
                    Nc[u] = 0
                else:
                    #if b_o(u) > b_i(u)
                    if b_o[u] > b_i[u]:
                        ##Nc(u) = delta_Nc / (1 - p0matrix_prevNC(u,r_idx)^R(r_idx,u));
                        #Nc(u) = delta_Nc / (1 - p0matrix_prevNC_single_r(u)^R(r_idx,u));
                        Nc[u] = delta_Nc / (1. - p0matrix_prevNC_single_r[u]**R[r_idx,u])
                    else:
                        ##Nc(u) = delta_Nc / ( b_o(u) / b_i(u) * (1 - p0matrix_prevNC(u,r_idx)));
                        #Nc(u) = delta_Nc / ( b_o(u) / b_i(u) * (1 - p0matrix_prevNC_single_r(u)));
                        Nc[u] = delta_Nc / ( b_o[u] / b_i[u] * (1. - p0matrix_prevNC_single_r[u]))
                    #end
                #end
                # sanity check
                #if abs(Nc(u)) < 1e-6
                if abs(Nc[u]) < 1e-6:
                    #Nc(u) = 0;
                    Nc[u] = 0
                #end
            #end
            
            # Compute the average decoding delay tc considering all sources and
            # NC nodes simultaneously with Eq. (16)
            #tc(r_idx) = compute_tc(net, sim, ncnodes, Nc, p0matrix_allncnodes(:,r_idx));
            tc[r_idx] = computings.compute_tc(net, sim, ncnodes, Nc, p0matrix_allncnodes[:,r_idx])
        #end
        
        # Update R
        ##R1 = update_R(R, net, p0matrix_allncnodes, ncnodes, tc);
        ##R = update_R_vectorized(R, net, p0matrix_allncnodes, ncnodes, tc);
        ##R = update_R_vectorized(Rinit, net, p0matrix_allncnodes, ncnodes, tc);
        #R = update_R_vectorized(Rinit, net, p0matrix_prevestim, ncnodes, tc);
        R = updateR.update_R_vectorized(Rinit, net, p0matrix_prevestim, ncnodes, tc)
        ##assert(norm(R1 - R2) < 1e-6);
    
        ##disp(['Average tc = ' num2str(mean(tc))]);
        
        # If tc has Inf values (this may happen for distrib algorithm), ignore
        #  them
        #if norm(tc(isfinite(tc)) - prev_tc(isfinite(tc))) <= precision * norm(tc(isfinite(tc)))
        if numpy.linalg.norm(tc[numpy.isfinite(tc)] - prev_tc[numpy.isfinite(tc)]) <= precision * numpy.linalg.norm(tc[numpy.isfinite(tc)]):
            #converged_tc = true;
            converged_tc = True
        #end
        
        #prev_tc = tc;
        prev_tc = tc.copy()
        
        # Save max tc
        #max_tc(tc > max_tc) = tc(tc > max_tc);
        max_tc[tc > max_tc] = tc[tc > max_tc]
        
        #niter = niter + 1;
        niter = niter + 1
    #end
    
    # Check if converged or not
    #if niter == maxiter
    if niter == maxiter:
        #tc = Inf * ones(1, numel(net.receivers)); # not converged
        #If not converged, don't put Inf, put largest values instead
        #tc = max_tc;
        tc = max_tc.copy()
    #end
    
    return tc