Skip to content

Commit

Permalink
Merge pull request #175 from PermutaTriangle/develop
Browse files Browse the repository at this point in the history
Version 2.1.0
  • Loading branch information
enadeau authored Jun 14, 2021
2 parents e840107 + c43e5e1 commit 6411ca8
Show file tree
Hide file tree
Showing 12 changed files with 2,366 additions and 516 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
repos:
- repo: https://github.com/psf/black
rev: 20.8b0
rev: 21.6b0
hooks:
- id: black
6 changes: 5 additions & 1 deletion .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
},
{
"name": "Arnar Bjarni Arnarson"
},
{
"affiliation": "Reykjavik University",
"name": "Sigurjón Ingi Jónsson"
}
]
}
}
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## Unreleased

## 2.1.0 - 2021-06-14
### Added
- Statistic: bounce of a permutation.
- Statistic: maximum drop size.
- Statistic: number of primes in the column sums.
- Statistic: holeyness of a permutation.
- Algorithm: `pop stack sort`.
- Statistic: count stack sorts.
- Statistic: count pop stack sorts.
- Statistic: Pinnacle set and number of pinnacles.

### Changed
- Functions for ascents and descents now take an optional argument to specify what step size to calculate.
- Moved sorting functions from `permuta/bisc/perm_properties.py` to `permuta/patterns/perm.py`.

## 2.0.3 - 2021-04-28
### Added
- using Github Actions for testing and deployment
Expand Down
63 changes: 46 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ permuta
:alt: Travis
:target: https://travis-ci.org/PermutaTriangle/Permuta
.. image:: https://requires.io/github/PermutaTriangle/Permuta/requirements.svg?branch=master
:target: https://requires.io/github/PermutaTriangle/Permuta/requirements/?branch=master
:alt: Requirements Status
:target: https://requires.io/github/PermutaTriangle/Permuta/requirements/?branch=master
:alt: Requirements Status
.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4725759.svg
:target: https://doi.org/10.5281/zenodo.4725759

Permuta is a Python library for working with perms (short for permutations),
patterns, and mesh patterns.
Expand Down Expand Up @@ -235,6 +237,22 @@ and a class (no class will use the set of all permutations).
[14] Longest increasing subsequence
[15] Longest decreasing subsequence
[16] Depth
[17] Number of bounces
[18] Maximum drop size
[19] Number of primes in the column sums
[20] Holeyness of a permutation
[21] Number of stack-sorts needed
[22] Number of pop-stack-sorts needed
[23] Number of pinnacles
[24] Number of cyclic peaks
[25] Number of cyclic valleys
[26] Number of double excedance
[27] Number of double drops
[28] Number of foremaxima
[29] Number of afterminima
[30] Number of aftermaxima
[31] Number of foreminima
>>> depth = PermutationStatistic.get_by_index(16)
>>> depth.distribution_for_length(5)
[1, 4, 12, 24, 35, 24, 20]
Expand All @@ -251,6 +269,8 @@ Given a bijection as a dictionary, we can check which statistics are preserved w
... print(stat)
Number of peaks
Number of valleys
Holeyness of a permutation
Number of pinnacles
We can find all (predefined) statistics equally distributed over two permutation
classes with ``equally_distributed``. We also support checks for joint distribution
Expand All @@ -272,6 +292,7 @@ of jointly distributed stats with ``jointly_transformed_equally_distributed``.
Number of right-to-left maximas
Longest increasing subsequence
Longest decreasing subsequence
Number of pinnacles
The BiSC algorithm
==================
Expand All @@ -287,20 +308,19 @@ To use the algorithm we first need to import it.
>>> from permuta.bisc import *
A classic example of a set of permutations described by pattern avoidance are
the permutations sortable in one pass through a stack. We start by loading a
function ``stack_sortable`` which returns ``True`` for permutations that
satisfy this property. The user now has two choices: Run
``auto_bisc(stack_sortable)`` and let the algorithm run without any more user
input. It will try to use sensible values, starting by learning small patterns
from small permutations, and only considering longer patterns when that fails.
If the user wants to have more control over what happens that is also possible
and we now walk through that: We input the property into ``bisc`` and ask it to
search for patterns of length 3.
the permutations sortable in one pass through a stack. We use the function
``stack_sortable`` which returns ``True`` for permutations that satisfy this
property. The user now has two choices: Run
``auto_bisc(Perm.stack_sortable)`` and let the algorithm run
without any more user input. It will try to use sensible values, starting by
learning small patterns from small permutations, and only considering longer
patterns when that fails. If the user wants to have more control over what
happens that is also possible and we now walk through that: We input the
property into ``bisc`` and ask it to search for patterns of length 3.

.. code-block:: python
>>> from permuta.bisc.perm_properties import stack_sortable
>>> bisc(stack_sortable, 3)
>>> bisc(Perm.stack_sortable, 3)
I will use permutations up to length 7
{3: {Perm((1, 2, 0)): [set()]}}
Expand All @@ -315,7 +335,7 @@ be considered.

.. code-block:: python
>>> SG = bisc(stack_sortable, 3, 5)
>>> SG = bisc(Perm.stack_sortable, 3, 5)
>>> show_me(SG)
There are 1 underlying classical patterns of length 3
There are 1 different shadings on 120
Expand All @@ -341,8 +361,7 @@ patterns, such as the West-2-stack-sortable permutations

.. code-block:: python
>>> from permuta.bisc.perm_properties import west_2_stack_sortable
>>> SG = bisc(west_2_stack_sortable, 5, 7)
>>> SG = bisc(Perm.west_2_stack_sortable, 5, 7)
>>> show_me(SG)
There are 2 underlying classical patterns of length 4
There are 1 different shadings on 1230
Expand Down Expand Up @@ -394,7 +413,7 @@ which keeps them separated by length.

.. code-block:: python
>>> A, B = create_bisc_input(7, west_2_stack_sortable)
>>> A, B = create_bisc_input(7, Perm.west_2_stack_sortable)
This creates two dictionaries with keys 1, 2, ..., 7 such that ``A[i]`` points
to the list of permutations of length ``i`` that are West-2-stack-sortable, and
Expand Down Expand Up @@ -476,3 +495,13 @@ License
#######

BSD-3: see the `LICENSE <https://github.com/PermutaTriangle/Permuta/blob/master/LICENSE>`_ file.

Citing
######

If you found this library helpful with your research and would like to cite us,
you can use the following `BibTeX`_ or go to `Zenodo`_ for alternative formats.

.. _BibTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk

.. _Zenodo: https://doi.org/10.5281/zenodo.4725759
2 changes: 1 addition & 1 deletion permuta/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .patterns import BivincularPatt, CovincularPatt, MeshPatt, Perm, VincularPatt
from .perm_sets.permset import Av, Basis, MeshBasis

__version__ = "2.0.4"
__version__ = "2.1.0"

__all__ = [
"Perm",
Expand Down
137 changes: 1 addition & 136 deletions permuta/bisc/perm_properties.py
Original file line number Diff line number Diff line change
@@ -1,145 +1,10 @@
from collections import deque
from itertools import islice
from typing import Deque, List, Tuple
from typing import List

from permuta.patterns.meshpatt import MeshPatt
from permuta.patterns.patt import Patt
from permuta.patterns.perm import Perm
from permuta.permutils.groups import dihedral_group


def _is_sorted(lis: List[int]) -> bool:
# Return true if w is increasing, i.e., sorted.
return all(elem == i for elem, i in zip(lis, range(len(lis))))


def _stack_sort(perm_slice: List[int]) -> List[int]:
n = len(perm_slice)
if n in (0, 1):
return perm_slice
max_i, max_v = max(enumerate(perm_slice), key=lambda pos_elem: pos_elem[1])
# Recursively solve without largest
if max_i == 0:
n_lis = _stack_sort(perm_slice[1:n])
elif max_i == n - 1:
n_lis = _stack_sort(perm_slice[0 : n - 1])
else:
n_lis = _stack_sort(perm_slice[0:max_i])
n_lis.extend(_stack_sort(perm_slice[max_i + 1 : n]))
n_lis.append(max_v)
return n_lis


def stack_sortable(perm: Perm) -> bool:
"""Returns true if perm is stack sortable."""
return _is_sorted(_stack_sort(list(perm)))


def _bubble_sort(perm_slice: List[int]) -> List[int]:
n = len(perm_slice)
if n in (0, 1):
return perm_slice
max_i, max_v = max(enumerate(perm_slice), key=lambda pos_elem: pos_elem[1])
# Recursively solve without largest
if max_i == 0:
n_lis = perm_slice[1:n]
elif max_i == n - 1:
n_lis = _bubble_sort(perm_slice[0 : n - 1])
else:
n_lis = _bubble_sort(perm_slice[0:max_i])
n_lis.extend(perm_slice[max_i + 1 : n])
n_lis.append(max_v)
return n_lis


def bubble_sortable(perm: Perm) -> bool:
"""Returns true if perm is stack sortable."""
return _is_sorted(_bubble_sort(list(perm)))


def _quick_sort(perm_slice: List[int]) -> List[int]:
assert not perm_slice or set(perm_slice) == set(
range(min(perm_slice), max(perm_slice) + 1)
)
n = len(perm_slice)
if n == 0:
return perm_slice
maxind = -1
# Note that perm does not need standardizing as sfp uses left to right maxima.
for maxind in Perm(perm_slice).strong_fixed_points():
pass
if maxind != -1:
lis: List[int] = (
_quick_sort(perm_slice[:maxind])
+ [perm_slice[maxind]]
+ _quick_sort(perm_slice[maxind + 1 :])
)
else:
firstval = perm_slice[0]
lis = (
list(filter(lambda x: x < firstval, perm_slice))
+ [perm_slice[0]]
+ list(filter(lambda x: x > firstval, perm_slice))
)
return lis


def quick_sortable(perm: Perm) -> bool:
"""Returns true if perm is quicksort sortable."""
return _is_sorted(_quick_sort(list(perm)))


_BKV_PATT = Perm((1, 0))


def bkv_sortable(perm: Perm, patterns: Tuple[Patt, ...] = ()) -> bool:
"""Check if a permutation is BKV sortable.
See:
https://arxiv.org/pdf/1907.08142.pdf
https://arxiv.org/pdf/2004.01812.pdf
"""
# See
n = len(perm)
inp = deque(perm)
# the right stack read from top to bottom
# the left stack read from top to bottom
right_stack: Deque[int] = deque([])
left_stack: Deque[int] = deque([])
expected = 0
while expected < n:
if inp:
right_stack.appendleft(inp[0])
if Perm.to_standard(right_stack).avoids(*patterns):
inp.popleft()
continue
right_stack.popleft()

if right_stack:
left_stack.appendleft(right_stack[0])
if Perm.to_standard(left_stack).avoids(_BKV_PATT):
right_stack.popleft()
continue
left_stack.popleft()

assert left_stack
# Normally, we would gather elements from left stack but since we only care
# about wether it sorts the permutation, we just compare it against expected.
if expected != left_stack.popleft():
return False
expected += 1
return True


def west_2_stack_sortable(perm: Perm) -> bool:
"""Returns true if perm can be sorted by two passes through a stack"""
return _is_sorted(_stack_sort(_stack_sort(list(perm))))


def west_3_stack_sortable(perm: Perm) -> bool:
"""Returns true if perm can be sorted by three passes through a stack"""
return _is_sorted(_stack_sort(_stack_sort(_stack_sort(list(perm)))))


_SMOOTH_PATT = (Perm((0, 2, 1, 3)), Perm((1, 0, 3, 2)))


Expand Down
12 changes: 12 additions & 0 deletions permuta/misc/math.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def is_prime(n: int) -> bool:
"""Primality test using 6k+-1 optimization."""
if n <= 3:
return n > 1
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i ** 2 <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
Loading

0 comments on commit 6411ca8

Please sign in to comment.