Skip to content

Commit 8fb5c00

Browse files
committed
First version of k-shift
some more improvement on shift changed method for shifting First draft of exterior shifting Repaired counter and added references
1 parent 766c7a0 commit 8fb5c00

File tree

2 files changed

+243
-1
lines changed

2 files changed

+243
-1
lines changed

src/doc/en/reference/references/index.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3330,6 +3330,8 @@ REFERENCES:
33303330
International Algorithmic Number Theory Symposium (pp. 357-371).
33313331
Springer Berlin Heidelberg, 2002.
33323332
3333+
.. [HH2011] Jürgen Herzog, Takayuki Hibi, *Monomial Ideals*. Springer GTM 260, 2011.
3334+
33333335
.. [HH2012] Victoria Horan and Glenn Hurlbert,
33343336
*Overlap Cycles for Steiner Quadruple Systems*,
33353337
2012, :arxiv:`1204.3215`
@@ -3824,7 +3826,10 @@ REFERENCES:
38243826
*The MD2 message-digest algorithm*; in
38253827
RFS 1319, (1992).
38263828
3827-
.. [Ka1993] Masaki Kashiwara, The crystal base and Littelmann's
3829+
.. [Kal2001] Gil Kalai. *Algebraic Shifting*. Computational Commutative
3830+
Algebra and Combinatorics. (2001). 121--163.
3831+
3832+
.. [Kas1993] Masaki Kashiwara, The crystal base and Littelmann's
38283833
refined Demazure character formula, Duke Math. J. 71
38293834
(1993), no. 3, 839--858.
38303835

src/sage/topology/simplicial_complex.py

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3577,6 +3577,243 @@ def stanley_reisner_ring(self, base_ring=ZZ):
35773577
products.append(prod)
35783578
return R.quotient(products)
35793579

3580+
def algebraic_shift(self, form="exterior", iterations=5, certificate=False, check_shift=False, **random_mat_options):
3581+
r"""
3582+
Returns the algebraically shifted complex of this simplicial complex.
3583+
3584+
Given a total order on the vertices of ``self``, define the partial
3585+
order on `k`-faces as `f\leq g` if and only if `f_1\leq g_1, \dots, f_k\leq
3586+
g_k`. A `k`-family is called `\emph{shifted}` if it is a lower ideal of
3587+
this partially ordered set. There the ``exterior`` and ``symmetric``
3588+
shifting are two operations giving shifted complex from the original
3589+
simplicial complex.
3590+
3591+
INPUT:
3592+
3593+
- ``form`` -- string (default: ``'exterior'``); the type of shifting to
3594+
do. Can be either ``'exterior'`` or ``'symmetric'``.
3595+
3596+
- ``iterations`` -- integer (default: `5`); the number of iterations to be
3597+
used to certify the output.
3598+
3599+
- ``certificate`` - boolean: whether to return the number of occurences
3600+
of the different candidates.
3601+
3602+
- ``check_shift`` - boolean: whether to check if the output is a
3603+
shifted complex.
3604+
3605+
- ``random_mat_options`` - a dictionary; the options to create the
3606+
random matrix used. If set to ``None``, the algorithm uses the
3607+
default options of ``random_matrix``.
3608+
3609+
OUTPUT:
3610+
3611+
A shifted simplicial complex.
3612+
3613+
EXAMPLES::
3614+
3615+
sage: G = graphs.CompleteBipartiteGraph(3,3)
3616+
sage: K33 = SimplicialComplex([e[:2] for e in G.edges()])
3617+
sage: shifted_K33 = K33.algebraic_shift()
3618+
sage: sorted(shifted_K33.facets())
3619+
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (2, 3)]
3620+
3621+
sage: octahedron = SimplicialComplex([[0,1,2],[0,1,5],[0,2,4],[0,4,5],[1,2,3],[1,3,5],[2,3,4],[3,4,5]])
3622+
sage: shifted_octahedron = octahedron.algebraic_shift()
3623+
sage: shifted_octahedron.f_vector()
3624+
[1, 6, 12, 8]
3625+
sage: shifted_octahedron.homology()
3626+
{0: 0, 1: 0, 2: Z}
3627+
sage: print(sorted(shifted_octahedron.facets()))
3628+
[(0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 1, 5), (0, 2, 3), (0, 2, 4), (0, 2, 5), (1, 2, 3)]
3629+
3630+
sage: K4 = graphs.CompleteGraph(4)
3631+
sage: complement_K44 = SimplicialComplex([e[:2] for e in K4.disjoint_union(K4).edges()])
3632+
sage: shifted_complement_K44 = complement_K44.algebraic_shift()
3633+
sage: shifted_complement_K44.f_vector()
3634+
[1, 8, 12]
3635+
sage: shifted_complement_K44.homology()
3636+
{0: Z, 1: Z^6}
3637+
sage: print(sorted(shifted_complement_K44.facets())[-4:])
3638+
[((0, 1), (1, 1)), ((0, 2), (0, 3)), ((0, 2), (1, 0)), ((1, 3),)]
3639+
3640+
sage: cp = polytopes.cyclic_polytope(4,10)
3641+
sage: sc_cp = SimplicialComplex([tuple([cp.vertices().index(v) for v in f.vertices()]) for f in cp.faces(3)])
3642+
sage: shifted_sc_cp = sc_cp.algebraic_shift()
3643+
sage: shifted_sc_cp.f_vector()
3644+
[1, 10, 45, 70, 35]
3645+
sage: shifted_sc_cp.homology()
3646+
{0: 0, 1: 0, 2: 0, 3: Z}
3647+
sage: sorted(shifted_sc_cp.facets())[-5:]
3648+
[(0, 2, 3, 6), (0, 2, 3, 7), (0, 2, 3, 8), (0, 2, 3, 9), (1, 2, 3, 4)]
3649+
3650+
.. WARNING::
3651+
3652+
This method uses random matrices and is not guaranteed to give
3653+
the correct output. The higher the parameter `iterations` is, the
3654+
higher the probability of the output to be correct.
3655+
3656+
.. SEEALSO::
3657+
3658+
:meth:`sage.homology.examples.ShiftedComplex`
3659+
3660+
.. REFERENCES:
3661+
3662+
- [HH2011]_
3663+
- [Kal2001]_
3664+
3665+
TODO:
3666+
3667+
- implement symmetric shift
3668+
- put more example with certificate and different random matrices and
3669+
check shift
3670+
"""
3671+
if form == "exterior":
3672+
outputs = [ self._ksets_exterior_shift(size, iterations, certificate,
3673+
check_shift, **random_mat_options)
3674+
for size in range(1,self.dimension()+2) ]
3675+
if certificate:
3676+
shifted_sets, certifs = zip(*outputs)
3677+
faces = reduce(lambda x,y: x + y, shifted_sets)
3678+
shifted_complex = SimplicialComplex(faces)
3679+
return shifted_complex, certifs
3680+
else:
3681+
shifted_sets = outputs
3682+
faces = reduce(lambda x,y: x + y, shifted_sets)
3683+
shifted_complex = SimplicialComplex(faces)
3684+
return shifted_complex
3685+
3686+
def _ksets_exterior_shift(self, k, iterations, certificate, check_shift, **random_mat_options):
3687+
"""
3688+
Returns a shifted `k`-set family obtained from the `k-1`-dim. faces of the
3689+
simplicial complex.
3690+
3691+
INPUT:
3692+
3693+
- ``k`` - positive integer; the size of the faces of ``self`` to shift.
3694+
3695+
- ``iterations`` - positive integer; the required number of iterations
3696+
giving the same result before giving the output.
3697+
3698+
- ``certificate`` - boolean: whether to return the
3699+
number of occurences of the different candidates.
3700+
3701+
- ``check_shift`` - boolean: whether to check if
3702+
the output is a shifted complex.
3703+
3704+
- ``random_mat_options`` - a dictionary; the options to create the
3705+
random matrix used. If set to ``None``, the algorithm uses the
3706+
default options of ``random_matrix``.
3707+
3708+
OUTPUT:
3709+
3710+
If ``certificate`` is true, returns a tuple containing:
3711+
3712+
1. A shifted `k`-set family.
3713+
2. A tuple giving the number of appearances of candidates, ordered
3714+
lexicographically.
3715+
3716+
If ``certificate`` is false:
3717+
3718+
- A shifted `k`-set family.
3719+
3720+
EXAMPLES:
3721+
3722+
.. WARNING::
3723+
3724+
This function is using a probabilistic algorithm. There is a (very)
3725+
small probability of returning a wrong output.
3726+
3727+
.. SEEALSO::
3728+
3729+
:meth:`algebraic_shift`
3730+
:meth:`sage.homology.examples.ShiftedComplex`
3731+
"""
3732+
from sage.matrix.special import random_matrix
3733+
from sage.misc.flatten import flatten
3734+
from sage.homology.examples import ShiftedComplex
3735+
3736+
def is_shifted(kset_fam):
3737+
if 0 in Set(flatten(kset_fam)): # Shifting operation does not like 0's
3738+
kset_fam = Set([tuple([i+1 for i in kset]) for kset in kset_fam])
3739+
shifted_sc = SimplicialComplex(kset_fam)
3740+
new_shifted = ShiftedComplex(kset_fam)
3741+
if new_shifted != shifted_sc:
3742+
return False
3743+
else:
3744+
return True
3745+
3746+
kset_family = sorted(self.faces()[k-1])
3747+
size = len(kset_family)
3748+
vertices = self.vertices()
3749+
n_vertices = len(vertices)
3750+
kset_as_indices = [tuple(vertices.index(i) for i in kset) for kset in kset_family]
3751+
3752+
try:
3753+
ring = random_mat_options.pop("ring")
3754+
except KeyError:
3755+
ring = ZZ
3756+
3757+
found_candidate = False
3758+
candidates = {}
3759+
candidate = None
3760+
sorted_candidate = None
3761+
value_candidate = 0
3762+
3763+
while not found_candidate:
3764+
M = random_matrix(ring=ring, nrows=n_vertices, **random_mat_options)
3765+
3766+
found_rank = 0
3767+
compound_matrix = matrix(size, 0)
3768+
iter_cols = combinations(range(n_vertices), k)
3769+
shifted_ksets = Set()
3770+
while found_rank < size:
3771+
index_cols = iter_cols.next()
3772+
new_column = matrix(size, 1, [M.matrix_from_rows_and_columns(row_indices, index_cols).det()
3773+
for row_indices in kset_as_indices])
3774+
compound_matrix = compound_matrix.augment(new_column)
3775+
new_rank = compound_matrix.rank()
3776+
if new_rank > found_rank:
3777+
shifted_ksets += Set([tuple(vertices[i] for i in index_cols)])
3778+
found_rank = new_rank
3779+
3780+
if candidate is not None:
3781+
shifted = True
3782+
if check_shift:
3783+
shifted = is_shifted(shifted_ksets)
3784+
if shifted:
3785+
sorted_ksets = sorted(shifted_ksets)
3786+
if sorted_ksets < sorted_candidate: # Found a new candidate
3787+
candidate = shifted_ksets
3788+
sorted_candidate = sorted_ksets
3789+
candidates[candidate] = 1
3790+
value_candidate = 1
3791+
elif sorted_ksets == sorted_candidate: # found the same candidate
3792+
candidates[candidate] += 1
3793+
value_candidate = candidates[candidate]
3794+
else: # is a bad candidate
3795+
if shifted_ksets in candidates.keys():
3796+
candidates[shifted_ksets] += 1
3797+
else:
3798+
candidates[shifted_ksets] = 1
3799+
else:
3800+
shifted = True
3801+
if check_shift:
3802+
shifted = is_shifted(shifted_ksets)
3803+
if shifted:
3804+
candidate = shifted_ksets
3805+
sorted_candidate = sorted(shifted_ksets)
3806+
candidates[candidate] = 1
3807+
value_candidate = 1
3808+
3809+
if value_candidate == iterations:
3810+
found_candidate = True
3811+
3812+
if certificate:
3813+
return candidate, sorted(candidates.values(), reverse=True)
3814+
else:
3815+
return candidate
3816+
35803817
def alexander_dual(self, is_mutable=True):
35813818
"""
35823819
The Alexander dual of this simplicial complex: according to

0 commit comments

Comments
 (0)