# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1365096692 7200
# Node ID 75923589c5e2b47b2265c989a2f6ae5d4421ee24
# Parent b2eea661627f6318598b4c6b92f3f2618aa17f60
Bug in GenericGraph.longest_path because of a bug in DiGraph.(incoming/outgoing)_edge*
diff git a/sage/combinat/root_system/root_lattice_realizations.py b/sage/combinat/root_system/root_lattice_realizations.py
a

b


392  392  """ 
393  393  if self.dynkin_diagram().rank() == 1: 
394  394  return self.simple_roots()[self.index_set()[0]] 
395   longest=self.dynkin_diagram().outgoing_edges()[0] 
396   for j in self.dynkin_diagram().outgoing_edges(): 
 395  longest=self.dynkin_diagram().edge_iterator().next() 
 396  for j in self.dynkin_diagram().edge_iterator(): 
397  397  if j[2]>longest[2]: 
398  398  longest=j 
399  399  return self.simple_roots()[longest[0]] 
diff git a/sage/graphs/digraph.py b/sage/graphs/digraph.py
a

b


1035  1035  
1036  1036  ### Edge Handlers 
1037  1037  
1038   def incoming_edge_iterator(self, vertices=None, labels=True): 
 1038  def incoming_edge_iterator(self, vertices, labels=True): 
1039  1039  """ 
1040   Return an iterator over all arriving edges from vertices, or over 
1041   all edges if vertices is None. 
1042   
 1040  Return an iterator over all arriving edges from vertices. 
 1041  
 1042  INPUT: 
 1043  
 1044   ``vertices``  a vertex or a list of vertices 
 1045  
 1046   ``labels`` (boolean)  whether to return edges as pairs of vertices, 
 1047  or as triples containing the labels. 
 1048  
1043  1049  EXAMPLES:: 
1044   
 1050  
1045  1051  sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } ) 
1046  1052  sage: for a in D.incoming_edge_iterator([0]): 
1047  1053  ... print a 
… 
… 

1056  1062  vertices = [v for v in vertices if v in self] 
1057  1063  return self._backend.iterator_in_edges(vertices, labels) 
1058  1064  
1059   def incoming_edges(self, vertices=None, labels=True): 
 1065  def incoming_edges(self, vertices, labels=True): 
1060  1066  """ 
1061  1067  Returns a list of edges arriving at vertices. 
1062   
 1068  
1063  1069  INPUT: 
1064   
1065   
1066    ``labels``  if False, each edge is a tuple (u,v) of 
1067   vertices. 
1068   
1069   
 1070  
 1071   ``vertices``  a vertex or a list of vertices 
 1072  
 1073   ``labels`` (boolean)  whether to return edges as pairs of vertices, 
 1074  or as triples containing the labels. 
 1075  
1070  1076  EXAMPLES:: 
1071   
 1077  
1072  1078  sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } ) 
1073  1079  sage: D.incoming_edges([0]) 
1074  1080  [(1, 0, None), (4, 0, None)] 
1075  1081  """ 
1076  1082  return list(self.incoming_edge_iterator(vertices, labels=labels)) 
1077  1083  
1078   def outgoing_edge_iterator(self, vertices=None, labels=True): 
 1084  def outgoing_edge_iterator(self, vertices, labels=True): 
1079  1085  """ 
1080   Return an iterator over all departing edges from vertices, or over 
1081   all edges if vertices is None. 
1082   
 1086  Return an iterator over all departing edges from vertices. 
 1087  
 1088  INPUT: 
 1089  
 1090   ``vertices``  a vertex or a list of vertices 
 1091  
 1092   ``labels`` (boolean)  whether to return edges as pairs of vertices, 
 1093  or as triples containing the labels. 
 1094  
1083  1095  EXAMPLES:: 
1084   
 1096  
1085  1097  sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } ) 
1086  1098  sage: for a in D.outgoing_edge_iterator([0]): 
1087  1099  ... print a 
… 
… 

1097  1109  vertices = [v for v in vertices if v in self] 
1098  1110  return self._backend.iterator_out_edges(vertices, labels) 
1099  1111  
1100   def outgoing_edges(self, vertices=None, labels=True): 
 1112  def outgoing_edges(self, vertices, labels=True): 
1101  1113  """ 
1102  1114  Returns a list of edges departing from vertices. 
1103   
 1115  
1104  1116  INPUT: 
1105   
1106   
1107    ``labels``  if False, each edge is a tuple (u,v) of 
1108   vertices. 
1109   
1110   
 1117  
 1118   ``vertices``  a vertex or a list of vertices 
 1119  
 1120   ``labels`` (boolean)  whether to return edges as pairs of vertices, 
 1121  or as triples containing the labels. 
 1122  
1111  1123  EXAMPLES:: 
1112   
 1124  
1113  1125  sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } ) 
1114  1126  sage: D.outgoing_edges([0]) 
1115  1127  [(0, 1, None), (0, 2, None), (0, 3, None)] 
diff git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
a

b


5363  5363  ValueError: algorithm must be either 'backtrack' or 'MILP' 
5364  5364  
5365  5365  Disconnected graphs not weighted:: 
5366   
 5366  
5367  5367  sage: g1 = graphs.PetersenGraph() 
5368  5368  sage: g2 = 2 * g1 
5369  5369  sage: lp1 = g1.longest_path() 
… 
… 

5418  5418  ... not max(lp.in_degree()) <= 1 or 
5419  5419  ... not lp.is_connected()): 
5420  5420  ... print("Error!") 
 5421  ... print g.edges() 
5421  5422  ... break 
5422  5423  
5423  5424  :trac:`13019`:: 
… 
… 

5425  5426  sage: g = graphs.CompleteGraph(5).to_directed() 
5426  5427  sage: g.longest_path(s=1,t=2) 
5427  5428  Subgraph of (Complete graph): Digraph on 5 vertices 
 5429  
 5430  :trac:`14412`:: 
 5431  
 5432  sage: l = [(0, 1), (0, 3), (2, 0)] 
 5433  sage: G = DiGraph(l) 
 5434  sage: G.longest_path().edges() 
 5435  [(0, 1, None), (2, 0, None)] 
5428  5436  """ 
5429  5437  if use_edge_labels: 
5430  5438  algorithm = "MILP" 
… 
… 

5448  5456  # Stupid cases 
5449  5457  #  Graph having <= 1 vertex. 
5450  5458  # 
5451   #  The source has outdegree 0 in a directed graph, or 
 5459  #  The source has outdegree 0 in a directed graph, or 
5452  5460  # degree 0, or is not a vertex of the graph. 
5453  5461  # 
5454  5462  #  The destination has indegree 0 in a directed graph, or 
… 
… 

5485  5493  
5486  5494  # Epsilon... Must be less than 1/(n+1), but we want to avoid 
5487  5495  # numerical problems... 
5488   epsilon = 1/(6*float(self.order())) 
 5496  epsilon = 1/(2*float(self.order())) 
5489  5497  
5490  5498  # Associating a weight to a label 
5491  5499  if use_edge_labels: 
… 
… 

5494  5502  weight = lambda x: 1 
5495  5503  
5496  5504  from sage.numerical.mip import MixedIntegerLinearProgram 
5497   p = MixedIntegerLinearProgram() 
5498   
 5505  p = MixedIntegerLinearProgram(solver=solver) 
 5506  
5499  5507  # edge_used[(u,v)] == 1 if (u,v) is used 
5500  5508  edge_used = p.new_variable(binary=True) 
5501  5509  
… 
… 

5507  5515  vertex_used = p.new_variable(binary=True) 
5508  5516  
5509  5517  if self._directed: 
 5518  
5510  5519  # if edge uv is used, vu can not be 
5511  5520  for u, v in self.edges(labels=False): 
5512  5521  if self.has_edge(v, u): 
5513   p.add_constraint(edge_used[(u,v)] + edge_used[(v,u)], max=1) 
 5522  p.add_constraint(edge_used[(u,v)] + edge_used[(v,u)] <= 1) 
 5523  
5514  5524  # A vertex is used if one of its incident edges is 
5515   for v in self: 
5516   for e in self.incoming_edges(labels=False): 
5517   p.add_constraint(vertex_used[v]  edge_used[e], min=0) 
5518   for e in self.outgoing_edges(labels=False): 
5519   p.add_constraint(vertex_used[v]  edge_used[e], min=0) 
 5525  for u,v in self.edges(labels = False): 
 5526  p.add_constraint(vertex_used[v] >= edge_used[(u,v)]) 
 5527  p.add_constraint(vertex_used[u] >= edge_used[(u,v)]) 
 5528  
5520  5529  # A path is a tree. If n vertices are used, at most n1 edges are 
5521  5530  p.add_constraint( 
5522   p.sum(vertex_used[v] for v in self) 
5523    p.sum(edge_used[e] for e in self.edges(labels=False)), 
5524   min=1, max=1) 
 5531  p.sum(vertex_used[v] for v in self) 
 5532   p.sum(edge_used[e] for e in self.edges(labels=False)) 
 5533  == 1) 
 5534  
5525  5535  # A vertex has at most one incoming used edge and at most 
5526  5536  # one outgoing used edge 
5527  5537  for v in self: 
5528  5538  p.add_constraint( 
5529   p.sum(edge_used[(u,v)] for u in self.neighbors_in(v)), 
5530   max=1) 
 5539  p.sum(edge_used[(u,v)] for u in self.neighbors_in(v)) <= 1) 
5531  5540  p.add_constraint( 
5532   p.sum(edge_used[(v,u)] for u in self.neighbors_out(v)), 
5533   max=1) 
 5541  p.sum(edge_used[(v,u)] for u in self.neighbors_out(v)) <= 1) 
 5542  
5534  5543  # r_edge_used is "more" than edge_used, though it ignores 
5535  5544  # the direction 
5536  5545  for u, v in self.edges(labels=False): 
5537   p.add_constraint(r_edge_used[(u,v)] 
5538   + r_edge_used[(v,u)] 
5539    edge_used[(u,v)], 
5540   min=0) 
 5546  p.add_constraint(r_edge_used[(u,v)] + r_edge_used[(v,u)] 
 5547  >= edge_used[(u,v)]) 
 5548  
5541  5549  # No cycles 
5542  5550  for v in self: 
5543  5551  p.add_constraint( 
5544   p.sum(r_edge_used[(u,v)] for u in self.neighbors(v)), 
5545   max=1epsilon) 
 5552  p.sum(r_edge_used[(u,v)] for u in self.neighbors(v)) 
 5553  <= 1epsilon) 
 5554  
5546  5555  # Enforcing the source if asked.. If s is set, it has no 
5547  5556  # incoming edge and exactly one son 
5548  5557  if s is not None: 
… 
… 

5552  5561  p.add_constraint( 
5553  5562  p.sum(edge_used[(s,u)] for u in self.neighbors_out(s)), 
5554  5563  min=1, max=1) 
 5564  
5555  5565  # Enforcing the destination if asked.. If t is set, it has 
5556  5566  # no outgoing edge and exactly one parent 
5557  5567  if t is not None: 
… 
… 

5561  5571  p.add_constraint( 
5562  5572  p.sum(edge_used[(t,u)] for u in self.neighbors_out(t)), 
5563  5573  max=0, min=0) 
 5574  
5564  5575  # Defining the objective 
5565  5576  p.set_objective( 
5566  5577  p.sum(weight(l) * edge_used[(u,v)] for u, v, l in self.edges())) 
… 
… 

5609  5620  # Computing the result. No exception has to be raised, as this 
5610  5621  # problem always has a solution (there is at least one edge, 
5611  5622  # and a path from s to t if they are specified). 
5612   p.solve(solver=solver, log=verbose) 
 5623  p.solve(log=verbose) 
5613  5624  edge_used = p.get_values(edge_used) 
5614  5625  vertex_used = p.get_values(vertex_used) 
5615  5626  if self._directed: 