Skip to content

Commit c06e028

Browse files
committed
some care in sage/graphs/domination.py
1 parent 543f8d6 commit c06e028

File tree

1 file changed

+44
-19
lines changed

1 file changed

+44
-19
lines changed

src/sage/graphs/domination.py

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def is_redundant(G, dom, focus=None):
137137
False
138138
"""
139139
dom = list(dom)
140-
focus = list(G) if focus is None else list(focus)
140+
focus = G if focus is None else set(focus)
141141

142142
# dominator[v] (for v in focus) will be equal to:
143143
# - (0, None) if v has no neighbor in dom
@@ -343,6 +343,13 @@ def dominating_sets(g, k=1, independent=False, total=False,
343343
Traceback (most recent call last):
344344
...
345345
ValueError: the domination distance must be a non-negative integer
346+
347+
The method is robust to vertices with incomparable labels::
348+
349+
sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)])
350+
sage: L = list(G.dominating_sets())
351+
sage: len(L)
352+
6
346353
"""
347354
g._scream_if_not_simple(allow_multiple_edges=True, allow_loops=not total)
348355

@@ -719,8 +726,8 @@ def _aux_with_rep(H, to_dom, u_next):
719726

720727
# Here we use aux_with_rep twice to enumerate the minimal
721728
# dominating sets while avoiding repeated outputs
722-
for (X, i) in _aux_with_rep(G, to_dom, u_next):
723-
for (Y, j) in _aux_with_rep(G, to_dom, u_next):
729+
for X, i in _aux_with_rep(G, to_dom, u_next):
730+
for Y, j in _aux_with_rep(G, to_dom, u_next):
724731
if j >= i:
725732
# This is the first time we meet X: we output it
726733
yield X
@@ -730,7 +737,7 @@ def _aux_with_rep(H, to_dom, u_next):
730737
break
731738

732739

733-
def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1):
740+
def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True, k=1):
734741
r"""
735742
Return an iterator over the minimal dominating sets of a graph.
736743
@@ -741,7 +748,7 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1):
741748
- ``to_dominate`` -- vertex iterable or ``None`` (default: ``None``);
742749
the set of vertices to be dominated.
743750
744-
- ``work_on_copy`` -- boolean (default: ``False``); whether or not to work on
751+
- ``work_on_copy`` -- boolean (default: ``True``); whether or not to work on
745752
a copy of the input graph; if set to ``False``, the input graph will be
746753
modified (relabeled).
747754
@@ -889,6 +896,15 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1):
889896
Traceback (most recent call last):
890897
...
891898
ValueError: vertex (foo) is not a vertex of the graph
899+
900+
The method is robust to vertices with incomparable labels::
901+
902+
sage: G = Graph([(1, 'A'), ('A', 2), (2, 3), (3, 1)])
903+
sage: L = list(G.minimal_dominating_sets())
904+
sage: len(L)
905+
6
906+
sage: {3, 'A'} in L
907+
True
892908
"""
893909
def tree_search(H, plng, dom, i):
894910
r"""
@@ -942,7 +958,8 @@ def tree_search(H, plng, dom, i):
942958
# We complete dom with can_ext -> canD
943959
canD = set().union(can_ext, dom)
944960

945-
if (not H.is_redundant(canD, V_next)) and set(dom) == set(_parent(H, canD, plng[i][1])):
961+
if (not H.is_redundant(canD, V_next)
962+
and set(dom) == set(_parent(H, canD, plng[i][1]))):
946963
# By construction, can_ext is a dominating set of
947964
# `V_next - N[dom]`, so canD dominates V_next.
948965
# If canD is a legitimate child of dom and is not redundant, we
@@ -952,6 +969,12 @@ def tree_search(H, plng, dom, i):
952969
##
953970
# end of tree-search routine
954971

972+
if k < 0:
973+
raise ValueError("the domination distance must be a non-negative integer")
974+
if not k:
975+
yield set(G) if to_dominate is None else set(to_dominate)
976+
return
977+
955978
int_to_vertex = list(G)
956979
vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)}
957980

@@ -963,28 +986,24 @@ def tree_search(H, plng, dom, i):
963986
raise ValueError(f"vertex ({u}) is not a vertex of the graph")
964987
vertices_to_dominate = {vertex_to_int[u] for u in to_dominate}
965988

966-
if k < 0:
967-
raise ValueError("the domination distance must be a non-negative integer")
968-
elif not k:
969-
yield set(int_to_vertex) if to_dominate is None else set(to_dominate)
989+
if not vertices_to_dominate:
990+
# base case: vertices_to_dominate is empty
991+
# the empty set/list is the only minimal DS of the empty set
992+
yield set()
970993
return
971994
elif k > 1:
972995
# We build a graph H with an edge between u and v if these vertices are
973996
# at distance at most k in G
974997
H = G.__class__(G.order())
975998
for u, ui in vertex_to_int.items():
976-
H.add_edges((ui, vertex_to_int[v]) for v in G.breadth_first_search(u, distance=k) if u != v)
999+
H.add_edges((ui, vertex_to_int[v])
1000+
for v in G.breadth_first_search(u, distance=k) if u != v)
9771001
G = H
9781002
elif work_on_copy:
979-
G.relabel(perm=vertex_to_int)
980-
else:
9811003
G = G.relabel(perm=vertex_to_int, inplace=False)
982-
983-
if not vertices_to_dominate:
984-
# base case: vertices_to_dominate is empty
985-
# the empty set/list is the only minimal DS of the empty set
986-
yield set()
987-
return
1004+
else:
1005+
# The input graph is modified
1006+
G.relabel(perm=vertex_to_int, inplace=True)
9881007

9891008
peeling = _peel(G, vertices_to_dominate)
9901009

@@ -1117,6 +1136,12 @@ def greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=Fals
11171136
sage: G = graphs.PathGraph(5)
11181137
sage: dom = greedy_dominating_set(G, vertices=[0, 1, 3, 4])
11191138
1139+
The method is robust to vertices with incomparable labels::
1140+
1141+
sage: G = Graph([(1, 'A')])
1142+
sage: len(greedy_dominating_set(G))
1143+
1
1144+
11201145
Check parameters::
11211146
11221147
sage: greedy_dominating_set(G, ordering="foo")

0 commit comments

Comments
 (0)