Skip to content

Commit

Permalink
gh-36359: a few details in combinat (designs)
Browse files Browse the repository at this point in the history
    
Cleaning up a few files in combinat/designs, in particular about missing
empty lines.

### 📝 Checklist

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
    
URL: #36359
Reported by: Frédéric Chapoton
Reviewer(s): David Coudert, Frédéric Chapoton
  • Loading branch information
Release Manager committed Oct 4, 2023
2 parents afd8d0e + be29cd1 commit e33c041
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 57 deletions.
88 changes: 43 additions & 45 deletions src/sage/combinat/designs/group_divisible_designs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@
---------
"""

#*****************************************************************************
# ****************************************************************************
# 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 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
# https://www.gnu.org/licenses/
# ****************************************************************************

from sage.arith.misc import is_prime_power
from sage.misc.unknown import Unknown
from sage.misc.unknown import Unknown
from .incidence_structures import IncidenceStructure

def group_divisible_design(v,K,G,existence=False,check=False):

def group_divisible_design(v, K, G, existence=False, check=False):
r"""
Return a `(v,K,G)`-Group Divisible Design.
Expand Down Expand Up @@ -90,36 +91,31 @@ def group_divisible_design(v,K,G,existence=False,check=False):
blocks = None

# from a (v+1,k,1)-BIBD
if (len(G) == 1 and
len(K) == 1 and
G[0]+1 in K):
if len(G) == 1 == len(K) and G[0] + 1 in K:
from .bibd import balanced_incomplete_block_design
k = K[0]
if existence:
return balanced_incomplete_block_design(v+1,k,existence=True)
BIBD = balanced_incomplete_block_design(v+1,k)
return balanced_incomplete_block_design(v + 1, k, existence=True)
BIBD = balanced_incomplete_block_design(v + 1, k)
groups = [[x for x in S if x != v] for S in BIBD if v in S]
d = {p:i for i,p in enumerate(sum(groups,[]))}
d = {p: i for i, p in enumerate(sum(groups, []))}
d[v] = v
BIBD.relabel(d)
groups = [list(range((k-1)*i,(k-1)*(i+1))) for i in range(v//(k-1))]
groups = [list(range((k - 1) * i, (k - 1) * (i + 1)))
for i in range(v // (k - 1))]
blocks = [S for S in BIBD if v not in S]

# (v,{4},{2})-GDD
elif (v % 2 == 0 and
K == [4] and
G == [2] and
GDD_4_2(v//2,existence=True)):
elif (v % 2 == 0 and K == [4] and
G == [2] and GDD_4_2(v // 2, existence=True)):
if existence:
return True
return GDD_4_2(v//2,check=check)
return GDD_4_2(v // 2, check=check)

# From a TD(k,g)
elif (len(G) == 1 and
len(K) == 1 and
K[0]*G[0] == v):
elif len(G) == 1 == len(K) and K[0] * G[0] == v:
from .orthogonal_arrays import transversal_design
return transversal_design(k=K[0],n=G[0],existence=existence)
return transversal_design(k=K[0], n=G[0], existence=existence)

if blocks:
return GroupDivisibleDesign(v,
Expand All @@ -134,7 +130,8 @@ def group_divisible_design(v,K,G,existence=False,check=False):
return Unknown
raise NotImplementedError

def GDD_4_2(q,existence=False,check=True):

def GDD_4_2(q, existence=False, check=True):
r"""
Return a `(2q,\{4\},\{2\})`-GDD for `q` a prime power with `q\equiv 1\pmod{6}`.
Expand Down Expand Up @@ -179,27 +176,28 @@ def GDD_4_2(q,existence=False,check=True):
if existence:
return True

from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
G = GF(q,'x')
from sage.rings.finite_rings.finite_field_constructor import FiniteField
G = FiniteField(q, 'x')
w = G.primitive_element()
e = w**((q - 1) // 3)

# A first parallel class is defined. G acts on it, which yields all others.
first_class = [[(0,0),(1,w**i),(1,e*w**i),(1,e*e*w**i)]
first_class = [[(0, 0), (1, w**i), (1, e * w**i), (1, e * e * w**i)]
for i in range((q - 1) // 6)]

label = {p:i for i,p in enumerate(G)}
classes = [[[2*label[x[1]+g]+(x[0]+j) % 2 for x in S]
label = {p: i for i, p in enumerate(G)}
classes = [[[2 * label[x[1] + g] + (x[0] + j) % 2 for x in S]
for S in first_class]
for g in G for j in range(2)]

return GroupDivisibleDesign(2*q,
groups=[[i,i+1] for i in range(0,2*q,2)],
blocks=sum(classes,[]),
K=[4],
G=[2],
check=check,
copy=False)
return GroupDivisibleDesign(2 * q,
groups=[[i, i + 1] for i in range(0, 2 * q, 2)],
blocks=sum(classes, []),
K=[4],
G=[2],
check=check,
copy=False)


class GroupDivisibleDesign(IncidenceStructure):
r"""
Expand Down Expand Up @@ -262,9 +260,9 @@ class GroupDivisibleDesign(IncidenceStructure):
sage: GDD = GroupDivisibleDesign('abcdefghiklm',None,D)
sage: sorted(GDD.groups())
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['k', 'l', 'm']]
"""
def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, check=True, copy=True,**kwds):
def __init__(self, points, groups, blocks, G=None, K=None, lambd=1,
check=True, copy=True, **kwds):
r"""
Constructor function
Expand All @@ -287,16 +285,17 @@ def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, check=True,
check=False,
**kwds)

if (groups is None or
(copy is False and self._point_to_index is None)):
if groups is None or (copy is False and self._point_to_index is None):
self._groups = groups
elif self._point_to_index is None:
self._groups = [g[:] for g in groups]
else:
self._groups = [[self._point_to_index[x] for x in g] for g in groups]

if check or groups is None:
is_gdd = is_group_divisible_design(self._groups,self._blocks,self.num_points(),G,K,lambd,verbose=1)
is_gdd = is_group_divisible_design(self._groups, self._blocks,
self.num_points(), G, K,
lambd, verbose=1)
assert is_gdd
if groups is None:
self._groups = is_gdd[1]
Expand Down Expand Up @@ -339,7 +338,7 @@ def groups(self):

def __repr__(self):
r"""
Returns a string that describes self
Return a string that describes ``self``.
EXAMPLES::
Expand All @@ -349,16 +348,15 @@ def __repr__(self):
sage: GDD = GroupDivisibleDesign(40,groups,TD); GDD
Group Divisible Design on 40 points of type 10^4
"""
group_sizes = [len(g) for g in self._groups]

group_sizes = [len(_) for _ in self._groups]

gdd_type = ["{}^{}".format(s,group_sizes.count(s))
for s in sorted(set(group_sizes))]
gdd_type = ("{}^{}".format(s, group_sizes.count(s))
for s in sorted(set(group_sizes)))
gdd_type = ".".join(gdd_type)

if not gdd_type:
gdd_type = "1^0"

v = self.num_points()

return "Group Divisible Design on {} points of type {}".format(v,gdd_type)
return "Group Divisible Design on {} points of type {}".format(v, gdd_type)
3 changes: 3 additions & 0 deletions src/sage/combinat/designs/resolvable_bibd.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def resolvable_balanced_incomplete_block_design(v,k,existence=False):
return Unknown
raise NotImplementedError("I don't know how to build a ({},{},1)-RBIBD!".format(v,3))


def kirkman_triple_system(v,existence=False):
r"""
Return a Kirkman Triple System on `v` points.
Expand Down Expand Up @@ -437,6 +438,7 @@ def v_4_1_rbibd(v,existence=False):
assert BIBD.is_resolvable()
return BIBD


def PBD_4_7(v,check=True, existence=False):
r"""
Return a `(v,\{4,7\})`-PBD
Expand Down Expand Up @@ -683,6 +685,7 @@ def PBD_4_7(v,check=True, existence=False):
check=check,
copy=False)


def PBD_4_7_from_Y(gdd,check=True):
r"""
Return a `(3v+1,\{4,7\})`-PBD from a `(v,\{4,5,7\},\NN-\{3,6,10\})`-GDD.
Expand Down
16 changes: 9 additions & 7 deletions src/sage/combinat/designs/twographs.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
from sage.combinat.designs.incidence_structures import IncidenceStructure
from itertools import combinations


class TwoGraph(IncidenceStructure):
r"""
Two-graphs class.
Expand Down Expand Up @@ -199,9 +200,10 @@ def taylor_twograph(q):
from sage.graphs.generators.classical_geometries import TaylorTwographSRG
return TaylorTwographSRG(q).twograph()

def is_twograph(T):

def is_twograph(T) -> bool:
r"""
Checks that the incidence system `T` is a two-graph
Check whether the incidence system `T` is a two-graph.
INPUT:
Expand Down Expand Up @@ -237,7 +239,7 @@ def is_twograph(T):
return False

# A structure for a fast triple existence check
v_to_blocks = {v:set() for v in range(T.num_points())}
v_to_blocks = {v: set() for v in range(T.num_points())}
for B in T._blocks:
B = frozenset(B)
for x in B:
Expand All @@ -248,8 +250,8 @@ def has_triple(x_y_z):
return bool(v_to_blocks[x] & v_to_blocks[y] & v_to_blocks[z])

# Check that every quadruple contains an even number of triples
for quad in combinations(range(T.num_points()),4):
if sum(map(has_triple,combinations(quad,3))) % 2 == 1:
for quad in combinations(range(T.num_points()), 4):
if sum(map(has_triple, combinations(quad, 3))) % 2 == 1:
return False

return True
Expand Down Expand Up @@ -296,10 +298,10 @@ def twograph_descendant(G, v, name=None):
sage: twograph_descendant(p, 5, name=True)
descendant of Petersen graph at 5: Graph on 9 vertices
"""
G = G.seidel_switching(G.neighbors(v),inplace=False)
G = G.seidel_switching(G.neighbors(v), inplace=False)
G.delete_vertex(v)
if name:
G.name('descendant of '+G.name()+' at '+str(v))
G.name('descendant of ' + G.name() + ' at ' + str(v))
else:
G.name('')
return G
9 changes: 6 additions & 3 deletions src/sage/combinat/matrices/dlxcpp.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Dancing links C++ wrapper
"""
#*****************************************************************************
# ****************************************************************************
# Copyright (C) 2008 Carlo Hamalainen <[email protected]>,
#
# Distributed under the terms of the GNU General Public License (GPL)
Expand All @@ -13,14 +13,15 @@
#
# The full text of the GPL is available at:
#
# http://www.gnu.org/licenses/
#*****************************************************************************
# https://www.gnu.org/licenses/
# ****************************************************************************

# OneExactCover and AllExactCovers are almost exact copies of the
# functions with the same name in sage/combinat/dlx.py by Tom Boothby.

from .dancing_links import dlx_solver


def DLXCPP(rows):
"""
Solves the Exact Cover problem by using the Dancing Links algorithm
Expand Down Expand Up @@ -85,6 +86,7 @@ def DLXCPP(rows):
while x.search():
yield x.get_solution()


def AllExactCovers(M):
"""
Solves the exact cover problem on the matrix M (treated as a dense
Expand Down Expand Up @@ -112,6 +114,7 @@ def AllExactCovers(M):
for s in DLXCPP(rows):
yield [M.row(i) for i in s]


def OneExactCover(M):
"""
Solves the exact cover problem on the matrix M (treated as a dense
Expand Down
5 changes: 3 additions & 2 deletions src/sage/combinat/tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
#
# https://www.gnu.org/licenses/
# ****************************************************************************
from itertools import product, combinations_with_replacement

from sage.arith.misc import binomial
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
from sage.rings.integer_ring import ZZ
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
from itertools import product, combinations_with_replacement


class Tuples(Parent, UniqueRepresentation):
"""
Expand Down

0 comments on commit e33c041

Please sign in to comment.