Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a few details in combinat (designs) #36359

Merged
merged 2 commits into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 42 additions & 44 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 @@
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)

Check warning on line 98 in src/sage/combinat/designs/group_divisible_designs.py

View check run for this annotation

Codecov / codecov/patch

src/sage/combinat/designs/group_divisible_designs.py#L98

Added line #L98 was not covered by tests
fchapoton marked this conversation as resolved.
Show resolved Hide resolved
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):

Check warning on line 116 in src/sage/combinat/designs/group_divisible_designs.py

View check run for this annotation

Codecov / codecov/patch

src/sage/combinat/designs/group_divisible_designs.py#L116

Added line #L116 was not covered by tests
fchapoton marked this conversation as resolved.
Show resolved Hide resolved
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)

Check warning on line 118 in src/sage/combinat/designs/group_divisible_designs.py

View check run for this annotation

Codecov / codecov/patch

src/sage/combinat/designs/group_divisible_designs.py#L118

Added line #L118 was not covered by tests

if blocks:
return GroupDivisibleDesign(v,
Expand All @@ -134,7 +130,8 @@
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 @@ -180,26 +177,27 @@
return True

from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
G = GF(q,'x')
G = GF(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 @@ -261,9 +259,9 @@
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 @@ -286,16 +284,17 @@
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)):
fchapoton marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -337,7 +336,7 @@

def __repr__(self):
r"""
Returns a string that describes self
Return a string that describes ``self``.

EXAMPLES::

Expand All @@ -347,16 +346,15 @@
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
Loading