Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
trac #27408: Merged with 8.9.beta3
Browse files Browse the repository at this point in the history
  • Loading branch information
dcoudert committed Jul 21, 2019
2 parents a1e1a8f + 575420c commit 5cd8c5e
Show file tree
Hide file tree
Showing 15 changed files with 765 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/doc/en/reference/graphs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Graph objects and methods
sage/graphs/graph
sage/graphs/digraph
sage/graphs/bipartite_graph

sage/graphs/views

Constructors and databases
--------------------------
Expand Down
3 changes: 3 additions & 0 deletions src/module_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ def uname_specific(name, value, alternative):
Extension('sage.graphs.base.boost_graph',
sources = ['sage/graphs/base/boost_graph.pyx']),

Extension('sage.graphs.views',
sources = ['sage/graphs/views.pyx']),

################################
##
## sage.groups
Expand Down
3 changes: 2 additions & 1 deletion src/sage/combinat/cluster_algebra_quiver/quiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from copy import copy
from sage.rings.all import ZZ, CC, infinity
from sage.graphs.all import Graph, DiGraph
from sage.graphs.views import EdgesView
from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix
from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part, _digraph_mutate, _matrix_to_digraph, _dg_canonical_form, _mutation_class_iter, _digraph_to_dig6, _dig6_to_matrix
from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type, _mutation_type_from_data, is_mutation_finite
Expand Down Expand Up @@ -453,7 +454,7 @@ def __init__(self, data, frozen=None, user_labels=None):

# if data is a list of edges, the appropriate digraph is constructed.

elif isinstance(data, list) and all(isinstance(x, (list,tuple)) for x in data):
elif isinstance(data, (list, EdgesView)) and all(isinstance(x, (list,tuple)) for x in data):
dg = DiGraph(data)
self.__init__(data=dg, frozen=frozen)

Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/root_system/type_C.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def dynkin_diagram(self):
O---O=<=O
1 2 3
C3
sage: e = c.edges(); e.sort(); e
sage: c.edges(sort=True)
[(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)]
sage: b = CartanType(['C',1]).dynkin_diagram()
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/comparability.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True,
return False, co_certif
# Building the two orderings
tmp = co_certif.edges(labels=False, sort=False)
tmp = list(co_certif.edges(labels=False, sort=False))
for u,v in certif.edge_iterator(labels=False):
co_certif.add_edge(v,u)
certif.add_edges(tmp)
Expand Down
4 changes: 2 additions & 2 deletions src/sage/graphs/connectivity.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2261,15 +2261,15 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0):
sage: T = G.spqr_tree(algorithm="cleave")
sage: Counter(u[0] for u in T)
Counter({'R': 1})
sage: for u,v in G.edges(labels=False, sort=False):
sage: for u,v in list(G.edges(labels=False, sort=False)):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: sorted(Counter(u[0] for u in T).items())
[('P', 15), ('R', 1), ('S', 15)]
sage: T = G.spqr_tree(algorithm="cleave")
sage: sorted(Counter(u[0] for u in T).items())
[('P', 15), ('R', 1), ('S', 15)]
sage: for u,v in G.edges(labels=False, sort=False):
sage: for u,v in list(G.edges(labels=False, sort=False)):
....: G.add_path([u, G.add_vertex(), G.add_vertex(), v])
sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan")
sage: sorted(Counter(u[0] for u in T).items())
Expand Down
12 changes: 7 additions & 5 deletions src/sage/graphs/digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
from sage.graphs.dot2tex_utils import have_dot2tex
from sage.misc.misc_c import prod
from sage.categories.cartesian_product import cartesian_product
from sage.graphs.views import EdgesView

class DiGraph(GenericGraph):
r"""
Expand Down Expand Up @@ -668,9 +669,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
if (format is None and
isinstance(data, list) and
len(data) == 2 and
isinstance(data[0], list) and # a list of two lists, the second of
isinstance(data[1], list) and # which contains iterables (the edges)
(not data[1] or callable(getattr(data[1][0], "__iter__", None)))):
isinstance(data[0], list) and # a list of two lists, the second of
((isinstance(data[1], list) and # which contains iterables (the edges)
(not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or
(isinstance(data[1], EdgesView)))):
format = "vertices_and_edges"

if format is None and isinstance(data, dict):
Expand Down Expand Up @@ -706,8 +708,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
format = 'int'
data = 0

# Input is a list of edges
if format is None and isinstance(data,list):
# Input is a list of edges or an EdgesView
if format is None and isinstance(data, (list, EdgesView)):
format = "list_of_edges"
if weighted is None:
weighted = False
Expand Down
38 changes: 22 additions & 16 deletions src/sage/graphs/generic_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
:meth:`~GenericGraph.delete_multiedge` | Delete all edges from ``u`` to ``v``.
:meth:`~GenericGraph.set_edge_label` | Set the edge label of a given edge.
:meth:`~GenericGraph.has_edge` | Check whether ``(u, v)`` is an edge of the (di)graph.
:meth:`~GenericGraph.edges` | Return a list of edges.
:meth:`~GenericGraph.edges` | Return a :class:`~EdgesView` of edges.
:meth:`~GenericGraph.edge_boundary` | Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1``
:meth:`~GenericGraph.edge_iterator` | Return an iterator over edges.
:meth:`~GenericGraph.edges_incident` | Return incident edges to some vertices.
Expand Down Expand Up @@ -425,6 +425,7 @@

from copy import copy

from sage.graphs.views import EdgesView
from .generic_graph_pyx import GenericGraph_pyx, spring_layout_fast
from .dot2tex_utils import assert_have_dot2tex

Expand Down Expand Up @@ -4356,7 +4357,7 @@ def weight_function(e):
v = next(self.vertex_iterator())
else:
v = starting_vertex
sorted_edges = self.edges(key=wfunction_float)
sorted_edges = sorted(self.edges(sort=False), key=wfunction_float)
tree = set([v])
edges = []
for _ in range(self.order() - 1):
Expand Down Expand Up @@ -11483,7 +11484,7 @@ def has_edge(self, u, v=None, label=None):

def edges(self, labels=True, sort=True, key=None):
r"""
Return a list of edges.
Return a :class:`~EdgesView` of edges.

Each edge is a triple ``(u, v, l)`` where ``u`` and ``v`` are vertices
and ``l`` is a label. If the parameter ``labels`` is ``False`` then a
Expand All @@ -11503,7 +11504,7 @@ def edges(self, labels=True, sort=True, key=None):
one argument and returns a value that can be used for comparisons in
the sorting algorithm

OUTPUT: A list of tuples. It is safe to change the returned list.
OUTPUT: A :class:`~EdgesView`.

.. WARNING::

Expand Down Expand Up @@ -11562,21 +11563,27 @@ def edges(self, labels=True, sort=True, key=None):
sage: P.edges(sort=False, key=lambda x: x)
Traceback (most recent call last):
...
ValueError: sort keyword is False, yet a key function is given
ValueError: sort keyword is not True, yet a key function is given

sage: G = Graph()
sage: G.add_edge(0, 1, [7])
sage: G.add_edge(0, 2, [7])
sage: G.edge_label(0, 1)[0] += 1
sage: G.edges()
[(0, 1, [8]), (0, 2, [7])]

Deprecation warning for ``sort=None`` (:trac:`27408`)::

sage: G = graphs.HouseGraph()
sage: G.edges(sort=None)
doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future
See https://trac.sagemath.org/27408 for details.
[(0, 1, None), (0, 2, None), (1, 3, None), (2, 3, None), (2, 4, None), (3, 4, None)]
"""
if (not sort) and key:
raise ValueError('sort keyword is False, yet a key function is given')
L = list(self.edge_iterator(labels=labels))
if sort:
L.sort(key=key)
return L
if sort is None:
deprecation(27408, "parameter 'sort' will be set to False by default in the future")
sort = True
return EdgesView(self, labels=labels, sort=sort, key=key)

def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False):
r"""
Expand Down Expand Up @@ -16714,9 +16721,9 @@ def weight_function(e):
else:
# Needed to remove labels.
if self.is_directed():
G = networkx.DiGraph(self.edges(labels=False, sort=False))
G = networkx.DiGraph(list(self.edges(labels=False, sort=False)))
else:
G = networkx.Graph(self.edges(labels=False, sort=False))
G = networkx.Graph(list(self.edges(labels=False, sort=False)))
G.add_nodes_from(self)
return networkx.single_source_dijkstra_path(G, u)

Expand Down Expand Up @@ -16937,9 +16944,9 @@ def weight_function(e):
else:
# Needed to remove labels.
if self.is_directed():
G = networkx.DiGraph(self.edges(labels=False, sort=False))
G = networkx.DiGraph(list(self.edges(labels=False, sort=False)))
else:
G = networkx.Graph(self.edges(labels=False, sort=False))
G = networkx.Graph(list(self.edges(labels=False, sort=False)))
G.add_nodes_from(self)
return networkx.single_source_dijkstra_path_length(G, u)

Expand Down Expand Up @@ -17840,7 +17847,6 @@ def depth_first_search(self, start, ignore_direction=False,
[0, 2, 1]

"""
from sage.misc.superseded import deprecation
if distance is not None:
deprecation(19227, "Parameter 'distance' is broken. Do not use.")

Expand Down
33 changes: 17 additions & 16 deletions src/sage/graphs/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@
from __future__ import print_function, absolute_import
import six
from six.moves import range
import itertools

from copy import copy
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
Expand All @@ -421,6 +422,7 @@
from sage.graphs.digraph import DiGraph
from sage.graphs.independent_sets import IndependentSets
from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index
from sage.graphs.views import EdgesView


class Graph(GenericGraph):
Expand Down Expand Up @@ -1073,17 +1075,18 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
if (format is None and
isinstance(data, list) and
len(data) == 2 and
isinstance(data[0], list) and # a list of two lists, the second of
isinstance(data[1], list) and # which contains iterables (the edges)
(not data[1] or callable(getattr(data[1][0], "__iter__", None)))):
isinstance(data[0], list) and # a list of two lists, the second of
((isinstance(data[1], list) and # which contains iterables (the edges)
(not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or
(isinstance(data[1], EdgesView)))):
format = "vertices_and_edges"

if format is None and isinstance(data, dict):
if not data:
format = 'dict_of_dicts'
else:
val = next(iter(data.values()))
if isinstance(val, list):
if isinstance(val, (list, EdgesView)):
format = 'dict_of_lists'
elif isinstance(val, dict):
format = 'dict_of_dicts'
Expand Down Expand Up @@ -1111,8 +1114,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
format = 'int'
data = 0

# Input is a list of edges
if format is None and isinstance(data, list):
# Input is a list of edges or an EdgesView
if format is None and isinstance(data, (list, EdgesView)):
format = "list_of_edges"
if weighted is None:
weighted = False
Expand Down Expand Up @@ -1214,9 +1217,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None,
if weighted is None: weighted = False
self.allow_loops(loops, check=False)
self.allow_multiple_edges(True if multiedges else False, check=False)
from itertools import combinations
self.add_vertices(verts)
self.add_edges(e for e in combinations(verts,2) if f(*e))
self.add_edges(e for e in itertools.combinations(verts,2) if f(*e))
if loops:
self.add_edges((v,v) for v in verts if f(v,v))

Expand Down Expand Up @@ -2846,8 +2848,8 @@ def treewidth(self, k=None, certificate=False, algorithm=None):
return all(cc.treewidth(k) for cc in g.connected_components_subgraphs())
else:
T = [cc.treewidth(certificate=True) for cc in g.connected_components_subgraphs()]
tree = Graph([sum([list(t) for t in T], []),
sum([t.edges(labels=False, sort=False) for t in T], [])],
tree = Graph([list(itertools.chain(*T)),
list(itertools.chain(*[t.edges(labels=False, sort=False) for t in T]))],
format='vertices_and_edges', name="Tree decomposition")
v = next(T[0].vertex_iterator())
for t in T[1:]:
Expand Down Expand Up @@ -3883,11 +3885,10 @@ def orientations(self, data_structure=None, sparse=None):
yield D
return

from itertools import product
E = [[(u,v,label), (v,u,label)] if u != v else [(u,v,label)]
for u,v,label in self.edge_iterator()]
verts = self.vertices()
for edges in product(*E):
for edges in itertools.product(*E):
D = DiGraph(data=[verts, edges],
format='vertices_and_edges',
name=name,
Expand Down Expand Up @@ -5544,10 +5545,9 @@ def seidel_switching(self, s, inplace=True):
sage: G == H
True
"""
from itertools import product
G = self if inplace else copy(self)
boundary = self.edge_boundary(s)
G.add_edges(product(s, set(self).difference(s)))
G.add_edges(itertools.product(s, set(self).difference(s)))
G.delete_edges(boundary)
if not inplace:
return G
Expand Down Expand Up @@ -7869,7 +7869,8 @@ def kirchhoff_symanzik_polynomial(self, name='t'):
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

edges = self.edges()
# The order of the vertices in each tuple matters, so use a list
edges = list(self.edges(sort=False))
cycles = self.cycle_basis(output='edge')

edge2int = {e: j for j, e in enumerate(edges)}
Expand Down Expand Up @@ -8028,7 +8029,7 @@ def ihara_zeta_function_inverse(self):
from sage.matrix.constructor import matrix

H = self.subgraph(vertices=self.cores(k=2)[1])
E = H.edges()
E = list(H.edges(sort=False))
m = len(E)
# compute (Hashimoto) edge matrix T
T = matrix(ZZ, 2 * m, 2 * m, 0)
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/graph_decompositions/graph_products.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def is_cartesian_product(g, certificate=False, relabeling=False):
# Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also
# equivalent

cdef list edges = g_int.edges(labels=False, sort=False)
cdef list edges = list(g_int.edges(labels=False, sort=False))
cdef dict d = g_int.distance_all_pairs()
cdef int uu, vv
for i, (u, v) in enumerate(edges):
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/orientations.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E):
sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph
sage: g = graphs.CycleGraph(5)
sage: Dg = DiGraph(g) # all edges of g will be doubly oriented
sage: it = _strong_orientations_of_a_mixed_graph(Dg, g.vertices(), g.edges(labels=False))
sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edges(labels=False, sort=False)))
sage: len(list(it)) # there are two orientations of this multigraph
2
"""
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/spanning_tree.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ cpdef boruvka(G, wfunction=None, bint check=False, bint by_weight=True):
If the input graph is a tree, then return its edges::
sage: T = graphs.RandomTree(randint(1, 10))
sage: T.edges() == sorted(boruvka(T, check=True))
sage: list(T.edges(sort=True)) == sorted(boruvka(T, check=True))
True
Check if the weight of MST returned by Prim's and Boruvka's is the same::
Expand Down
17 changes: 8 additions & 9 deletions src/sage/graphs/tutte_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,9 @@ def __call__(self, graph):
(0, 1, None)
"""
degrees = dict(graph.degree_iterator(labels=True))
edges = graph.edges(labels=True)
edges.sort(key=lambda x: degrees[x[0]]+degrees[x[1]]) # Sort by degree
for e in edges:
return e
edges = graph.edges(labels=True, sort=False)
if edges:
return min(edges, key=lambda x: degrees[x[0]] + degrees[x[1]])
raise RuntimeError("no edges left to select")


Expand All @@ -463,15 +462,15 @@ def __call__(self, graph):
sage: from sage.graphs.tutte_polynomial import MaximizeDegree
sage: G = graphs.PathGraph(6)
sage: MaximizeDegree()(G)
(3, 4, None)
(1, 2, None)
"""
degrees = dict(graph.degree_iterator(labels=True))
edges = graph.edges(labels=True)
edges.sort(key=lambda x: degrees[x[0]]+degrees[x[1]]) # Sort by degree
for e in reversed(edges):
return e
edges = graph.edges(labels=True, sort=False)
if edges:
return max(edges, key=lambda x: degrees[x[0]] + degrees[x[1]])
raise RuntimeError("no edges left to select")


###########
# Caching #
###########
Expand Down
Loading

0 comments on commit 5cd8c5e

Please sign in to comment.