From 28613d860da775abb86f7b4b14bfdc00fc99991b Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 28 Apr 2021 16:55:07 +0000 Subject: [PATCH 01/41] zenodo branch --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 8ae11a4..6498d9d 100644 --- a/README.rst +++ b/README.rst @@ -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. From dd9a8f69c453361abcdc154a6e5304e7fdc8d782 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 28 Apr 2021 16:57:02 +0000 Subject: [PATCH 02/41] formatting --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6498d9d..0b9e6e9 100644 --- a/README.rst +++ b/README.rst @@ -19,7 +19,7 @@ permuta :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 + :target: https://doi.org/10.5281/zenodo.4725759 Permuta is a Python library for working with perms (short for permutations), patterns, and mesh patterns. From 17e768ab007408e9aa31fa7f0e04ad32cb795514 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 28 Apr 2021 17:09:56 +0000 Subject: [PATCH 03/41] add direct link to bibtex --- README.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0b9e6e9..17090de 100644 --- a/README.rst +++ b/README.rst @@ -19,7 +19,7 @@ permuta :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 + :target: https://doi.org/10.5281/zenodo.4725759 Permuta is a Python library for working with perms (short for permutations), patterns, and mesh patterns. @@ -28,6 +28,13 @@ If you need support, you can join us in our `Discord support server`_. .. _Discord support server: https://discord.gg/ngPZVT5 +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. + +.. _BitTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk + +.. _Zenodo: https://doi.org/10.5281/zenodo.4725759 + Installing ========== From bd4be26e2286767dbf2319e63e74aab025dba3cd Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 28 Apr 2021 17:11:58 +0000 Subject: [PATCH 04/41] fix links! --- README.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 17090de..7b3d219 100644 --- a/README.rst +++ b/README.rst @@ -28,13 +28,6 @@ If you need support, you can join us in our `Discord support server`_. .. _Discord support server: https://discord.gg/ngPZVT5 -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. - -.. _BitTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk - -.. _Zenodo: https://doi.org/10.5281/zenodo.4725759 - Installing ========== @@ -485,3 +478,13 @@ License ####### BSD-3: see the `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. + +.. _BitTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk + +.. _Zenodo: https://doi.org/10.5281/zenodo.4725759 \ No newline at end of file From cfe1b1c7d66cd984ed3d30c0b3ac2a71bd29e978 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 28 Apr 2021 17:13:11 +0000 Subject: [PATCH 05/41] typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7b3d219..501001d 100644 --- a/README.rst +++ b/README.rst @@ -485,6 +485,6 @@ 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. -.. _BitTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk +.. _BibTex: https://zenodo.org/record/4725759/export/hx#.YImTibX7SUk .. _Zenodo: https://doi.org/10.5281/zenodo.4725759 \ No newline at end of file From 2566e1e8116db7378abb73d53f55cf6bbefecce4 Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 11:00:59 +0000 Subject: [PATCH 06/41] implemented bounce --- permuta/patterns/perm.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 8809381..1befabb 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1120,6 +1120,15 @@ def count_inversions(self) -> int: bit_index += bit_index & -bit_index return bit[0] + def bounces(self): + """The "bounce" of a permutation.""" + n = len(self) + v = self.inverse() + bounce_arr = [v[0] + 1] + while bounce_arr[-1] < n - 1: + bounce_arr.append(max(v[: bounce_arr[-1] + 1]) + 1) + return sum([n - i for i in bounce_arr]) + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). From 94ea12f8114aa3bfc6ccbb91ad6cb2a8107e070a Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 11:11:22 +0000 Subject: [PATCH 07/41] Added test cases to bounces --- permuta/patterns/perm.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 1befabb..42229f7 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1121,13 +1121,21 @@ def count_inversions(self) -> int: return bit[0] def bounces(self): - """The "bounce" of a permutation.""" + """The "bounce" of a permutation. + + Examples: + >>> Perm((0,)).bounces() + 0 + >>> Perm((0, 1)).bounces() + 1 + >>> Perm((1, 0)).bounces() + 0""" n = len(self) v = self.inverse() bounce_arr = [v[0] + 1] while bounce_arr[-1] < n - 1: bounce_arr.append(max(v[: bounce_arr[-1] + 1]) + 1) - return sum([n - i for i in bounce_arr]) + return sum(n - i for i in bounce_arr) def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j From 88f49bbe743cb98c12fabfce6f2dc2f10c2bc8b4 Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 12:10:36 +0000 Subject: [PATCH 08/41] Fixed the readme, renamed the bounce stat and added it to statistics.py --- README.rst | 1 + permuta/patterns/perm.py | 10 ++-- permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 99 +++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 501001d..a1a5590 100644 --- a/README.rst +++ b/README.rst @@ -237,6 +237,7 @@ and a class (no class will use the set of all permutations). [14] Longest increasing subsequence [15] Longest decreasing subsequence [16] Depth + [17] Bounce >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 42229f7..16acca0 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1120,17 +1120,19 @@ def count_inversions(self) -> int: bit_index += bit_index & -bit_index return bit[0] - def bounces(self): + def count_bounces(self): """The "bounce" of a permutation. Examples: - >>> Perm((0,)).bounces() + >>> Perm((0,)).count_bounces() 0 - >>> Perm((0, 1)).bounces() + >>> Perm((0, 1)).count_bounces() 1 - >>> Perm((1, 0)).bounces() + >>> Perm((1, 0)).count_bounces() 0""" n = len(self) + if n == 0: + return 0 v = self.inverse() bounce_arr = [v[0] + 1] while bounce_arr[-1] < n - 1: diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 8324633..76e252a 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -33,6 +33,7 @@ class PermutationStatistic: ("Longest increasing subsequence", Perm.length_of_longestrun_ascending), ("Longest decreasing subsequence", Perm.length_of_longestrun_descending), ("Depth", Perm.depth), + ("Bounce", Perm.count_bounces), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index ea85040..1dcf4a7 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2310,3 +2310,102 @@ def test_cycle_notation(): assert Perm((0,)).cycle_notation() == "( 0 )" assert Perm((0, 1)).cycle_notation() == "( 0 ) ( 1 )" assert Perm((7, 0, 1, 2, 5, 4, 3, 6)).cycle_notation() == "( 5 4 ) ( 7 6 3 2 1 0 )" + + +def test_count_bounces(): + assert Perm((0,)).count_bounces() == 0 + assert Perm((0, 1)).count_bounces() == 1 + assert Perm((1, 0)).count_bounces() == 0 + assert Perm((0, 1, 2)).count_bounces() == 3 + assert Perm((0, 2, 1)).count_bounces() == 2 + assert Perm((1, 0, 2)).count_bounces() == 1 + assert Perm((1, 2, 0)).count_bounces() == 0 + assert Perm((2, 0, 1)).count_bounces() == 1 + assert Perm((2, 1, 0)).count_bounces() == 0 + assert Perm((0, 3, 2, 1)).count_bounces() == 3 + assert Perm((2, 0, 1, 3)).count_bounces() == 3 + assert Perm((3, 0, 2, 1)).count_bounces() == 2 + assert Perm((0, 1, 3, 2, 4)).count_bounces() == 8 + assert Perm((0, 2, 3, 4, 1)).count_bounces() == 4 + assert Perm((0, 3, 4, 1, 2)).count_bounces() == 5 + assert Perm((0, 4, 3, 2, 1)).count_bounces() == 4 + assert Perm((1, 2, 0, 3, 4)).count_bounces() == 3 + assert Perm((1, 3, 0, 4, 2)).count_bounces() == 2 + assert Perm((1, 4, 2, 0, 3)).count_bounces() == 1 + assert Perm((2, 0, 3, 4, 1)).count_bounces() == 3 + assert Perm((2, 1, 4, 0, 3)).count_bounces() == 1 + assert Perm((4, 1, 3, 2, 0)).count_bounces() == 0 + assert Perm((4, 3, 0, 1, 2)).count_bounces() == 2 + assert Perm((0, 1, 2, 3, 5, 4)).count_bounces() == 14 + assert Perm((0, 1, 3, 4, 2, 5)).count_bounces() == 10 + assert Perm((0, 1, 4, 3, 5, 2)).count_bounces() == 9 + assert Perm((0, 1, 5, 4, 2, 3)).count_bounces() == 10 + assert Perm((0, 2, 1, 5, 4, 3)).count_bounces() == 8 + assert Perm((0, 2, 4, 1, 3, 5)).count_bounces() == 8 + assert Perm((0, 2, 5, 1, 4, 3)).count_bounces() == 7 + assert Perm((0, 3, 1, 4, 2, 5)).count_bounces() == 9 + assert Perm((0, 3, 2, 4, 5, 1)).count_bounces() == 5 + assert Perm((0, 3, 4, 5, 1, 2)).count_bounces() == 6 + assert Perm((0, 3, 5, 4, 2, 1)).count_bounces() == 5 + assert Perm((0, 4, 2, 1, 3, 5)).count_bounces() == 8 + assert Perm((0, 4, 3, 1, 5, 2)).count_bounces() == 7 + assert Perm((0, 4, 5, 2, 1, 3)).count_bounces() == 6 + assert Perm((0, 5, 1, 3, 4, 2)).count_bounces() == 8 + assert Perm((0, 5, 2, 4, 1, 3)).count_bounces() == 6 + assert Perm((0, 5, 3, 4, 2, 1)).count_bounces() == 5 + assert Perm((1, 0, 2, 3, 4, 5)).count_bounces() == 10 + assert Perm((1, 0, 3, 2, 5, 4)).count_bounces() == 6 + assert Perm((1, 0, 4, 3, 2, 5)).count_bounces() == 5 + assert Perm((1, 0, 5, 3, 4, 2)).count_bounces() == 4 + assert Perm((1, 2, 0, 5, 3, 4)).count_bounces() == 4 + assert Perm((1, 2, 3, 5, 4, 0)).count_bounces() == 0 + assert Perm((1, 2, 5, 0, 3, 4)).count_bounces() == 2 + assert Perm((1, 3, 0, 2, 5, 4)).count_bounces() == 5 + assert Perm((1, 3, 2, 4, 0, 5)).count_bounces() == 1 + assert Perm((1, 3, 4, 2, 5, 0)).count_bounces() == 0 + assert Perm((1, 3, 5, 4, 0, 2)).count_bounces() == 1 + assert Perm((1, 4, 0, 5, 3, 2)).count_bounces() == 3 + assert Perm((1, 4, 3, 0, 2, 5)).count_bounces() == 3 + assert Perm((1, 4, 5, 0, 3, 2)).count_bounces() == 2 + assert Perm((1, 5, 0, 3, 2, 4)).count_bounces() == 4 + assert Perm((1, 5, 2, 3, 4, 0)).count_bounces() == 0 + assert Perm((1, 5, 3, 4, 0, 2)).count_bounces() == 1 + assert Perm((1, 5, 4, 3, 2, 0)).count_bounces() == 0 + assert Perm((2, 0, 3, 1, 4, 5)).count_bounces() == 7 + assert Perm((2, 0, 4, 1, 5, 3)).count_bounces() == 6 + assert Perm((2, 0, 5, 3, 1, 4)).count_bounces() == 5 + assert Perm((2, 1, 0, 4, 5, 3)).count_bounces() == 3 + assert Perm((2, 1, 3, 5, 0, 4)).count_bounces() == 1 + assert Perm((2, 1, 4, 5, 3, 0)).count_bounces() == 0 + assert Perm((2, 3, 0, 1, 4, 5)).count_bounces() == 6 + assert Perm((2, 3, 1, 0, 5, 4)).count_bounces() == 2 + assert Perm((2, 3, 4, 1, 0, 5)).count_bounces() == 1 + assert Perm((2, 3, 5, 1, 4, 0)).count_bounces() == 0 + assert Perm((2, 4, 0, 5, 1, 3)).count_bounces() == 3 + assert Perm((2, 4, 1, 5, 3, 0)).count_bounces() == 0 + assert Perm((2, 4, 5, 0, 1, 3)).count_bounces() == 2 + assert Perm((2, 5, 0, 1, 4, 3)).count_bounces() == 3 + assert Perm((2, 5, 1, 3, 0, 4)).count_bounces() == 1 + assert Perm((2, 5, 3, 1, 4, 0)).count_bounces() == 0 + assert Perm((2, 5, 4, 3, 0, 1)).count_bounces() == 1 + assert Perm((3, 2, 5, 1, 0, 4)).count_bounces() == 1 + assert Perm((3, 4, 0, 2, 5, 1)).count_bounces() == 3 + assert Perm((3, 4, 1, 5, 0, 2)).count_bounces() == 1 + assert Perm((3, 4, 2, 5, 1, 0)).count_bounces() == 0 + assert Perm((3, 5, 0, 1, 2, 4)).count_bounces() == 4 + assert Perm((3, 5, 1, 0, 4, 2)).count_bounces() == 2 + assert Perm((3, 5, 2, 1, 0, 4)).count_bounces() == 1 + assert Perm((3, 5, 4, 1, 2, 0)).count_bounces() == 0 + assert Perm((4, 0, 1, 5, 2, 3)).count_bounces() == 5 + assert Perm((4, 0, 2, 5, 3, 1)).count_bounces() == 4 + assert Perm((4, 0, 5, 1, 2, 3)).count_bounces() == 5 + assert Perm((4, 1, 0, 2, 5, 3)).count_bounces() == 3 + assert Perm((4, 1, 2, 3, 0, 5)).count_bounces() == 1 + assert Perm((4, 1, 3, 2, 5, 0)).count_bounces() == 0 + assert Perm((4, 1, 5, 3, 0, 2)).count_bounces() == 1 + assert Perm((4, 3, 2, 5, 0, 1)).count_bounces() == 1 + assert Perm((4, 3, 5, 2, 1, 0)).count_bounces() == 0 + assert Perm((4, 5, 1, 0, 2, 3)).count_bounces() == 2 + assert Perm((4, 5, 2, 0, 3, 1)).count_bounces() == 2 + assert Perm((4, 5, 3, 1, 0, 2)).count_bounces() == 1 + assert Perm((5, 0, 1, 3, 4, 2)).count_bounces() == 4 From 0335f025fe3b39ff00a18d65f00de4a08ac5168f Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 13:30:01 +0000 Subject: [PATCH 09/41] Implemented maximum drop size --- README.rst | 1 + permuta/patterns/perm.py | 17 +++++++++ permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 65 +++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/README.rst b/README.rst index a1a5590..46fa1d5 100644 --- a/README.rst +++ b/README.rst @@ -238,6 +238,7 @@ and a class (no class will use the set of all permutations). [15] Longest decreasing subsequence [16] Depth [17] Bounce + [18] Max drop size >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 16acca0..e1d8c97 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1139,6 +1139,23 @@ def count_bounces(self): bounce_arr.append(max(v[: bounce_arr[-1] + 1]) + 1) return sum(n - i for i in bounce_arr) + def max_drop_size(self): + """The maximum drop size of a permutation. + + Examples: + >>> Perm((0,)).max_drop_size() + 0 + >>> Perm((0, 1)).max_drop_size() + 0 + >>> Perm((1, 0)).max_drop_size() + 1 + >>> Perm((2, 0, 1)).max_drop_size() + 2""" + p_size = len(self) + if not p_size: + return 0 + return max((self[i] - i for i in range(p_size))) + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 76e252a..31fc5a6 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -34,6 +34,7 @@ class PermutationStatistic: ("Longest decreasing subsequence", Perm.length_of_longestrun_descending), ("Depth", Perm.depth), ("Bounce", Perm.count_bounces), + ("Max drop size", Perm.max_drop_size), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 1dcf4a7..7fa7125 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2409,3 +2409,68 @@ def test_count_bounces(): assert Perm((4, 5, 2, 0, 3, 1)).count_bounces() == 2 assert Perm((4, 5, 3, 1, 0, 2)).count_bounces() == 1 assert Perm((5, 0, 1, 3, 4, 2)).count_bounces() == 4 + + +def test_max_drop_size(): + assert Perm((0,)).max_drop_size() == 0 + assert Perm((0, 1)).max_drop_size() == 0 + assert Perm((1, 0)).max_drop_size() == 1 + assert Perm((0, 1, 2)).max_drop_size() == 0 + assert Perm((0, 2, 1)).max_drop_size() == 1 + assert Perm((1, 0, 2)).max_drop_size() == 1 + assert Perm((1, 2, 0)).max_drop_size() == 1 + assert Perm((2, 0, 1)).max_drop_size() == 2 + assert Perm((2, 1, 0)).max_drop_size() == 2 + assert Perm((0, 3, 4, 2, 1)).max_drop_size() == 2 + assert Perm((2, 4, 0, 3, 1)).max_drop_size() == 3 + assert Perm((4, 3, 1, 2, 0)).max_drop_size() == 4 + assert Perm((0, 2, 5, 4, 3, 1)).max_drop_size() == 3 + assert Perm((0, 5, 1, 2, 4, 3)).max_drop_size() == 4 + assert Perm((1, 2, 0, 4, 5, 3)).max_drop_size() == 1 + assert Perm((1, 4, 0, 5, 3, 2)).max_drop_size() == 3 + assert Perm((2, 0, 3, 1, 5, 4)).max_drop_size() == 2 + assert Perm((2, 3, 1, 4, 5, 0)).max_drop_size() == 2 + assert Perm((2, 5, 1, 4, 3, 0)).max_drop_size() == 4 + assert Perm((3, 1, 4, 0, 5, 2)).max_drop_size() == 3 + assert Perm((3, 4, 2, 1, 5, 0)).max_drop_size() == 3 + assert Perm((4, 0, 3, 5, 2, 1)).max_drop_size() == 4 + assert Perm((4, 2, 5, 0, 3, 1)).max_drop_size() == 4 + assert Perm((4, 5, 3, 1, 2, 0)).max_drop_size() == 4 + assert Perm((5, 1, 4, 3, 2, 0)).max_drop_size() == 5 + assert Perm((5, 4, 0, 1, 3, 2)).max_drop_size() == 5 + assert Perm((0, 5, 6, 1, 2, 3, 4)).max_drop_size() == 4 + assert Perm((2, 5, 0, 1, 3, 4, 6)).max_drop_size() == 4 + assert Perm((5, 2, 3, 4, 1, 0, 6)).max_drop_size() == 5 + assert Perm((6, 7, 2, 1, 3, 4, 5, 0)).max_drop_size() == 6 + assert Perm((7, 5, 4, 3, 2, 1, 0, 6)).max_drop_size() == 7 + assert Perm((2, 1, 5, 4, 6, 3, 7, 0)).max_drop_size() == 3 + assert Perm((2, 1, 6, 5, 4, 3, 0, 7)).max_drop_size() == 4 + assert Perm((1, 0, 4, 2, 6, 3, 7, 5)).max_drop_size() == 2 + assert Perm((3, 4, 5, 0, 1, 2, 7, 6)).max_drop_size() == 3 + assert Perm((0, 5, 1, 6, 2, 3, 4, 7)).max_drop_size() == 4 + assert Perm((3, 7, 5, 0, 6, 2, 4, 1)).max_drop_size() == 6 + assert Perm((5, 3, 6, 1, 4, 0, 2, 7)).max_drop_size() == 5 + assert Perm((4, 3, 2, 7, 6, 5, 0, 1)).max_drop_size() == 4 + assert Perm((5, 3, 2, 7, 1, 0, 4, 6)).max_drop_size() == 5 + assert Perm((6, 0, 1, 7, 2, 4, 3, 5)).max_drop_size() == 6 + assert Perm((1, 6, 5, 4, 2, 3, 7, 0)).max_drop_size() == 5 + assert Perm((6, 4, 0, 2, 7, 1, 5, 3)).max_drop_size() == 6 + assert Perm((5, 0, 1, 7, 3, 2, 4, 6)).max_drop_size() == 5 + assert Perm((1, 5, 0, 2, 4, 3, 7, 6)).max_drop_size() == 4 + assert Perm((5, 4, 7, 6, 0, 1, 2, 3)).max_drop_size() == 5 + assert Perm((1, 2, 7, 0, 3, 5, 6, 4)).max_drop_size() == 5 + assert Perm((7, 5, 0, 3, 4, 2, 1, 6)).max_drop_size() == 7 + assert Perm((4, 3, 2, 7, 5, 6, 1, 0)).max_drop_size() == 4 + assert Perm((3, 0, 5, 2, 6, 1, 7, 4)).max_drop_size() == 3 + assert Perm((7, 3, 5, 0, 6, 2, 1, 4)).max_drop_size() == 7 + assert Perm((6, 7, 0, 1, 2, 3, 4, 5, 8)).max_drop_size() == 6 + assert Perm((5, 4, 3, 2, 1, 0, 6, 7, 8)).max_drop_size() == 5 + assert Perm((9, 8, 3, 2, 7, 6, 5, 4, 1, 0)).max_drop_size() == 9 + assert Perm((9, 6, 7, 2, 3, 8, 0, 1, 4, 5)).max_drop_size() == 9 + assert Perm((8, 6, 9, 2, 3, 7, 0, 1, 4, 5)).max_drop_size() == 8 + assert Perm((3, 1, 4, 0, 2, 5, 6, 7, 8, 9)).max_drop_size() == 3 + assert Perm((3, 5, 7, 8, 9, 11, 0, 1, 2, 4, 6, 10)).max_drop_size() == 6 + assert Perm((9, 2, 1, 8, 5, 4, 7, 6, 3, 0, 11, 10)).max_drop_size() == 9 + assert Perm((1, 5, 6, 7, 10, 11, 0, 2, 3, 4, 8, 9)).max_drop_size() == 6 + assert Perm((3, 6, 7, 9, 10, 11, 0, 1, 2, 4, 5, 8)).max_drop_size() == 6 + assert Perm((11, 10, 5, 4, 3, 2, 7, 6, 9, 8, 1, 0)).max_drop_size() == 11 From 8c6e1eb9848f6bb8567e5e6cfdec74811edefe1d Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 13:39:14 +0000 Subject: [PATCH 10/41] Renamed a variable in count_bounces, added a link to the stat in docstring and changed explanation of count_bounces --- README.rst | 2 +- permuta/patterns/perm.py | 8 ++++---- permuta/permutils/statistics.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index a1a5590..12c3259 100644 --- a/README.rst +++ b/README.rst @@ -237,7 +237,7 @@ and a class (no class will use the set of all permutations). [14] Longest increasing subsequence [15] Longest decreasing subsequence [16] Depth - [17] Bounce + [17] Number of bounces >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 16acca0..b3681d6 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1121,7 +1121,7 @@ def count_inversions(self) -> int: return bit[0] def count_bounces(self): - """The "bounce" of a permutation. + """The Number of "bounces" in a permutation. See https://www.findstat.org/StatisticsDatabase/St000133/# Examples: >>> Perm((0,)).count_bounces() @@ -1133,10 +1133,10 @@ def count_bounces(self): n = len(self) if n == 0: return 0 - v = self.inverse() - bounce_arr = [v[0] + 1] + inv = self.inverse() + bounce_arr = [inv[0] + 1] while bounce_arr[-1] < n - 1: - bounce_arr.append(max(v[: bounce_arr[-1] + 1]) + 1) + bounce_arr.append(max(inv[: bounce_arr[-1] + 1]) + 1) return sum(n - i for i in bounce_arr) def inversions(self) -> Iterator[Tuple[int, int]]: diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 76e252a..4b625f7 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -33,7 +33,7 @@ class PermutationStatistic: ("Longest increasing subsequence", Perm.length_of_longestrun_ascending), ("Longest decreasing subsequence", Perm.length_of_longestrun_descending), ("Depth", Perm.depth), - ("Bounce", Perm.count_bounces), + ("Number of bounces", Perm.count_bounces), ) @staticmethod From de327ebde13daa876ad35cf6eed7818acf96a28b Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 13:50:42 +0000 Subject: [PATCH 11/41] Too long line fixed --- permuta/patterns/perm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index b3681d6..8e247b2 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1121,7 +1121,8 @@ def count_inversions(self) -> int: return bit[0] def count_bounces(self): - """The Number of "bounces" in a permutation. See https://www.findstat.org/StatisticsDatabase/St000133/# + """The Number of "bounces" in a permutation. + See https://www.findstat.org/StatisticsDatabase/St000133/# Examples: >>> Perm((0,)).count_bounces() From b222933ef6622dc4a3a55e2a4851a929cde1be47 Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 14:07:02 +0000 Subject: [PATCH 12/41] fixed count_bounces algorithm --- permuta/patterns/perm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 8e247b2..7eaa853 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1136,7 +1136,7 @@ def count_bounces(self): return 0 inv = self.inverse() bounce_arr = [inv[0] + 1] - while bounce_arr[-1] < n - 1: + while bounce_arr[-1] < n: bounce_arr.append(max(inv[: bounce_arr[-1] + 1]) + 1) return sum(n - i for i in bounce_arr) From f889fefa212b173f6eb7e3aeff0ad6eab4faf30a Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 14:32:25 +0000 Subject: [PATCH 13/41] fixed pytest errors --- README.rst | 1 + permuta/permutils/statistics.py | 1 + 2 files changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 12c3259..8e04d6e 100644 --- a/README.rst +++ b/README.rst @@ -238,6 +238,7 @@ and a class (no class will use the set of all permutations). [15] Longest decreasing subsequence [16] Depth [17] Number of bounces + [18] Maximum drop size >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 4b625f7..d69da66 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -34,6 +34,7 @@ class PermutationStatistic: ("Longest decreasing subsequence", Perm.length_of_longestrun_descending), ("Depth", Perm.depth), ("Number of bounces", Perm.count_bounces), + ("Maximum drop size", Perm.max_drop_size), ) @staticmethod From 22a5acb4826f2e020e1bcc187625cb695f8a1de4 Mon Sep 17 00:00:00 2001 From: quintant Date: Wed, 2 Jun 2021 14:50:09 +0000 Subject: [PATCH 14/41] Added refrences to max_drop_size and default value to max --- permuta/patterns/perm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index b505be3..1bf18b4 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1142,6 +1142,9 @@ def count_bounces(self): def max_drop_size(self): """The maximum drop size of a permutation. + See: https://www.findstat.org/StatisticsDatabase/St000141/ + https://arxiv.org/abs/1306.5428 + https://mathscinet.ams.org/mathscinet/search/publdoc.html?pg1=MR&s1=MR2673024 Examples: >>> Perm((0,)).max_drop_size() @@ -1152,10 +1155,7 @@ def max_drop_size(self): 1 >>> Perm((2, 0, 1)).max_drop_size() 2""" - p_size = len(self) - if not p_size: - return 0 - return max((self[i] - i for i in range(p_size))) + return max((self[i] - i for i in range(len(self))), default=0) def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j From 6fed5e00c8ade9c69d5f7f774b067126fa16f987 Mon Sep 17 00:00:00 2001 From: quintant Date: Thu, 3 Jun 2021 13:59:51 +0000 Subject: [PATCH 15/41] enumerate over self instead of indexing in max_drop_size --- permuta/patterns/perm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 1bf18b4..160ba78 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1155,7 +1155,7 @@ def max_drop_size(self): 1 >>> Perm((2, 0, 1)).max_drop_size() 2""" - return max((self[i] - i for i in range(len(self))), default=0) + return max((val - idx for idx, val in enumerate(self)), default=0) def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j From c6a92c8b953ffa93e9309d30fa4129c7c84d880d Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Thu, 3 Jun 2021 14:11:51 +0000 Subject: [PATCH 16/41] Moving sorting functions --- permuta/bisc/perm_properties.py | 135 +----------- permuta/patterns/perm.py | 140 +++++++++++++ tests/bisc/test_perm_properties.py | 323 ----------------------------- tests/patterns/test_perm.py | 193 +++++++++++++++++ 4 files changed, 334 insertions(+), 457 deletions(-) diff --git a/permuta/bisc/perm_properties.py b/permuta/bisc/perm_properties.py index 6504519..08f0d66 100644 --- a/permuta/bisc/perm_properties.py +++ b/permuta/bisc/perm_properties.py @@ -1,6 +1,5 @@ -from collections import deque from itertools import islice -from typing import Deque, List, Tuple +from typing import List, Tuple from permuta.patterns.meshpatt import MeshPatt from permuta.patterns.patt import Patt @@ -8,138 +7,6 @@ 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))) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 1bf18b4..a5b2114 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -2064,6 +2064,146 @@ def apply(self, iterable: Iterable[ApplyType]) -> Tuple[ApplyType, ...]: permute = apply + @staticmethod + def _is_sorted(lis: List[int]) -> bool: + return all(val == idx for idx, val in enumerate(lis)) + + @staticmethod + def _stack_sort(perm_slice: List[int]) -> List[int]: + """Helper function for the stack sorting function on perms""" + 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._stack_sort(perm_slice[1:n]) + elif max_i == n - 1: + n_lis = Perm._stack_sort(perm_slice[0 : n - 1]) + else: + n_lis = Perm._stack_sort(perm_slice[0:max_i]) + n_lis.extend(Perm._stack_sort(perm_slice[max_i + 1 : n])) + n_lis.append(max_v) + return n_lis + + def stack_sort(self) -> "Perm": + return Perm(Perm._stack_sort(list(self))) + + def stack_sortable(self) -> bool: + """Returns true if perm is stack sortable.""" + return self.stack_sort().is_increasing() + + @staticmethod + def _bubble_sort(perm_slice: List[int]) -> List[int]: + """Helper function for the bubble sorting function on perms""" + 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 = Perm._bubble_sort(perm_slice[0 : n - 1]) + else: + n_lis = Perm._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_sort(self) -> "Perm": + return Perm(Perm._bubble_sort(list(self))) + + def bubble_sortable(self) -> bool: + """Returns true if perm is stack sortable.""" + return self.bubble_sort().is_increasing() + + @staticmethod + def _quick_sort(perm_slice: List[int]) -> List[int]: + """Helper function for the quick sorting function on perms""" + 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] = ( + Perm._quick_sort(perm_slice[:maxind]) + + [perm_slice[maxind]] + + Perm._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_sort(self) -> "Perm": + return Perm(Perm._quick_sort(list(self))) + + def quick_sortable(self) -> bool: + """Returns true if perm is quicksort sortable.""" + return self.quick_sort().is_increasing() + + def bkv_sortable(self, 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(self) + inp = collections.deque(self) + # the right stack read from top to bottom + # the left stack read from top to bottom + right_stack: Deque[int] = collections.deque([]) + left_stack: Deque[int] = collections.deque([]) + expected = 0 + print(self) + while expected < n: + print("inp", inp) + print("left_stack", left_stack) + print("right_stack", right_stack) + print("------------------------------") + 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._is_sorted(left_stack): + 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(self) -> bool: + """Returns true if perm can be sorted by two passes through a stack""" + return self.stack_sort().stack_sort().is_increasing() + + def west_3_stack_sortable(self) -> bool: + """Returns true if perm can be sorted by three passes through a stack""" + return self.stack_sort().stack_sort().stack_sort().is_increasing() + def ascii_plot(self, cell_size: int = 1) -> str: """Return an ascii plot of the given Permutation. diff --git a/tests/bisc/test_perm_properties.py b/tests/bisc/test_perm_properties.py index 414522a..4d435d0 100644 --- a/tests/bisc/test_perm_properties.py +++ b/tests/bisc/test_perm_properties.py @@ -3,343 +3,20 @@ from permuta import MeshPatt, Perm from permuta.bisc.perm_properties import ( - _bubble_sort, - _is_sorted, _perm_to_yt, - _quick_sort, - _stack_sort, av_231_and_mesh, baxter, - bkv_sortable, - bubble_sortable, dihedral, forest_like, hard_mesh, in_alternating_group, - quick_sortable, simsun, smooth, - stack_sortable, - west_2_stack_sortable, - west_3_stack_sortable, yt_perm_avoids_22, yt_perm_avoids_32, ) -def test__is_sorted(): - assert _is_sorted([]) - assert _is_sorted([0]) - assert _is_sorted([0, 1]) - assert not _is_sorted([1, 0]) - assert _is_sorted([0, 1, 2]) - assert not _is_sorted([0, 2, 1]) - assert not _is_sorted([1, 0, 2]) - assert not _is_sorted([1, 2, 0]) - assert not _is_sorted([2, 0, 1]) - assert not _is_sorted([2, 1, 0]) - - -def test__stack_sort(): - assert _stack_sort([]) == [] - assert _stack_sort([0]) == [0] - assert _stack_sort([0, 1]) == [0, 1] - assert _stack_sort([1, 0]) == [0, 1] - assert _stack_sort([0, 1, 2]) == [0, 1, 2] - assert _stack_sort([0, 2, 1]) == [0, 1, 2] - assert _stack_sort([1, 0, 2]) == [0, 1, 2] - assert _stack_sort([1, 2, 0]) == [1, 0, 2] - assert _stack_sort([2, 0, 1]) == [0, 1, 2] - assert _stack_sort([2, 1, 0]) == [0, 1, 2] - assert _stack_sort([0, 1, 2, 3]) == [0, 1, 2, 3] - assert _stack_sort([0, 1, 3, 2]) == [0, 1, 2, 3] - assert _stack_sort([0, 2, 1, 3]) == [0, 1, 2, 3] - assert _stack_sort([0, 2, 3, 1]) == [0, 2, 1, 3] - assert _stack_sort([0, 3, 1, 2]) == [0, 1, 2, 3] - assert _stack_sort([0, 3, 2, 1]) == [0, 1, 2, 3] - assert _stack_sort([1, 0, 2, 3]) == [0, 1, 2, 3] - assert _stack_sort([1, 0, 3, 2]) == [0, 1, 2, 3] - assert _stack_sort([1, 2, 0, 3]) == [1, 0, 2, 3] - assert _stack_sort([1, 2, 3, 0]) == [1, 2, 0, 3] - assert _stack_sort([1, 3, 0, 2]) == [1, 0, 2, 3] - assert _stack_sort([1, 3, 2, 0]) == [1, 0, 2, 3] - assert _stack_sort([2, 0, 1, 3]) == [0, 1, 2, 3] - assert _stack_sort([2, 0, 3, 1]) == [0, 2, 1, 3] - assert _stack_sort([2, 1, 0, 3]) == [0, 1, 2, 3] - assert _stack_sort([2, 1, 3, 0]) == [1, 2, 0, 3] - assert _stack_sort([2, 3, 0, 1]) == [2, 0, 1, 3] - assert _stack_sort([2, 3, 1, 0]) == [2, 0, 1, 3] - assert _stack_sort([3, 0, 1, 2]) == [0, 1, 2, 3] - assert _stack_sort([3, 0, 2, 1]) == [0, 1, 2, 3] - assert _stack_sort([3, 1, 0, 2]) == [0, 1, 2, 3] - assert _stack_sort([3, 1, 2, 0]) == [1, 0, 2, 3] - assert _stack_sort([3, 2, 0, 1]) == [0, 1, 2, 3] - assert _stack_sort([3, 2, 1, 0]) == [0, 1, 2, 3] - patt231 = Perm((1, 2, 0)) - for _ in range(100): - p = Perm.random(randint(5, 20)) - if p.avoids(patt231): - assert list(_stack_sort(list(p))) == sorted(range(len(p))) - else: - assert not list(_stack_sort(list(p))) == sorted(range(len(p))) - - -def test_stack_sortable(): - assert stack_sortable(Perm(())) - assert stack_sortable(Perm((0,))) - assert stack_sortable(Perm((0, 1))) - assert stack_sortable(Perm((1, 0))) - assert stack_sortable(Perm((0, 1, 2))) - assert stack_sortable(Perm((0, 2, 1))) - assert stack_sortable(Perm((1, 0, 2))) - assert not stack_sortable(Perm((1, 2, 0))) - assert stack_sortable(Perm((2, 0, 1))) - assert stack_sortable(Perm((2, 1, 0))) - assert stack_sortable(Perm((2, 1, 0, 4, 3))) - assert not stack_sortable(Perm((1, 4, 3, 0, 8, 5, 2, 9, 7, 6))) - assert not stack_sortable(Perm((1, 3, 0, 2))) - assert stack_sortable(Perm((3, 0, 1, 2))) - assert not stack_sortable(Perm((6, 2, 4, 3, 7, 1, 5, 0))) - assert not stack_sortable(Perm((4, 8, 5, 0, 6, 1, 7, 3, 2))) - assert stack_sortable(Perm((0, 1, 3, 2))) - assert stack_sortable(Perm((3, 0, 2, 1))) - assert not stack_sortable(Perm((1, 0, 7, 2, 5, 4, 3, 8, 9, 6))) - assert not stack_sortable(Perm((4, 1, 5, 2, 6, 0, 3, 8, 7, 9))) - assert stack_sortable(Perm((0, 12, 11, 10, 9, 1, 5, 4, 2, 3, 6, 7, 8, 14, 13))) - - -def test__bubble_sort(): - assert _bubble_sort([]) == [] - assert _bubble_sort([0]) == [0] - assert _bubble_sort([0, 1]) == [0, 1] - assert _bubble_sort([1, 0]) == [0, 1] - assert _bubble_sort([0, 1, 2]) == [0, 1, 2] - assert _bubble_sort([0, 2, 1]) == [0, 1, 2] - assert _bubble_sort([1, 0, 2]) == [0, 1, 2] - assert _bubble_sort([1, 2, 0]) == [1, 0, 2] - assert _bubble_sort([2, 0, 1]) == [0, 1, 2] - assert _bubble_sort([2, 1, 0]) == [1, 0, 2] - assert _bubble_sort([0, 3, 2, 4, 1]) == [0, 2, 3, 1, 4] - assert _bubble_sort([1, 4, 2, 5, 0, 3]) == [1, 2, 4, 0, 3, 5] - assert _bubble_sort([3, 6, 7, 2, 5, 4, 1, 0]) == [3, 6, 2, 5, 4, 1, 0, 7] - assert _bubble_sort([2, 6, 7, 8, 5, 1, 9, 4, 3, 0]) == [ - 2, - 6, - 7, - 5, - 1, - 8, - 4, - 3, - 0, - 9, - ] - assert _bubble_sort([5, 4, 7, 9, 1, 6, 3, 2, 8, 0]) == [ - 4, - 5, - 7, - 1, - 6, - 3, - 2, - 8, - 0, - 9, - ] - - -def test_bubble_sortable(): - enumeration = [1] - enumeration.extend([2 ** i for i in range(10)]) - assert bubble_sortable(Perm(())) - assert bubble_sortable(Perm((0,))) - assert bubble_sortable(Perm((0, 1))) - assert bubble_sortable(Perm((1, 0))) - assert bubble_sortable(Perm((0, 1, 2))) - assert bubble_sortable(Perm((0, 2, 1))) - assert bubble_sortable(Perm((1, 0, 2))) - assert not bubble_sortable(Perm((1, 2, 0))) - assert bubble_sortable(Perm((2, 0, 1))) - assert not bubble_sortable(Perm((2, 1, 0))) - assert bubble_sortable(Perm((2, 0, 1, 3))) - assert not bubble_sortable(Perm((1, 4, 3, 2, 0))) - assert not bubble_sortable(Perm((0, 1, 5, 4, 2, 3))) - assert not bubble_sortable(Perm((1, 3, 4, 0, 6, 2, 5, 7))) - assert not bubble_sortable(Perm((1, 5, 6, 7, 0, 3, 2, 4))) - assert not bubble_sortable(Perm((2, 3, 1, 6, 4, 7, 5, 0))) - assert not bubble_sortable(Perm((2, 5, 1, 4, 7, 0, 6, 3))) - assert not bubble_sortable(Perm((3, 0, 4, 5, 7, 6, 1, 2))) - assert not bubble_sortable(Perm((4, 0, 7, 5, 3, 6, 2, 1))) - assert not bubble_sortable(Perm((6, 5, 2, 0, 3, 7, 1, 8, 4))) - for i in range(4, 7): - assert sum(1 for p in Perm.of_length(i) if bubble_sortable(p)) == enumeration[i] - patts = (Perm((1, 2, 0)), Perm((2, 1, 0))) - for i in range(20): - p = Perm.random(randint(5, 10)) - if p.avoids(*patts): - assert bubble_sortable(p) - else: - assert not bubble_sortable(p) - - -def test__quick_sort(): - assert _quick_sort([]) == [] - assert _quick_sort([0]) == [0] - assert _quick_sort([0, 1]) == [0, 1] - assert _quick_sort([1, 0]) == [0, 1] - assert _quick_sort([0, 1, 2]) == [0, 1, 2] - assert _quick_sort([0, 2, 1]) == [0, 1, 2] - assert _quick_sort([1, 0, 2]) == [0, 1, 2] - assert _quick_sort([1, 2, 0]) == [0, 1, 2] - assert _quick_sort([2, 0, 1]) == [0, 1, 2] - assert _quick_sort([2, 1, 0]) == [1, 0, 2] - assert _quick_sort([0, 1, 2, 3]) == [0, 1, 2, 3] - assert _quick_sort([0, 1, 2, 4, 3]) == [0, 1, 2, 3, 4] - assert _quick_sort([2, 3, 5, 4, 0, 1]) == [0, 1, 2, 3, 5, 4] - assert _quick_sort([3, 4, 1, 2, 0, 5]) == [1, 2, 0, 3, 4, 5] - assert _quick_sort([3, 1, 2, 0, 6, 4, 5]) == [1, 2, 0, 3, 6, 4, 5] - assert _quick_sort([5, 6, 1, 2, 0, 3, 4]) == [1, 2, 0, 3, 4, 5, 6] - assert _quick_sort([6, 5, 3, 2, 1, 0, 4]) == [5, 3, 2, 1, 0, 4, 6] - assert _quick_sort([0, 3, 8, 5, 2, 1, 7, 6, 4]) == [0, 2, 1, 3, 8, 5, 7, 6, 4] - assert _quick_sort([4, 6, 0, 5, 7, 1, 3, 2, 8]) == [0, 1, 3, 2, 4, 6, 5, 7, 8] - assert _quick_sort([4, 0, 3, 7, 1, 8, 2, 9, 5, 6]) == [0, 3, 1, 2, 4, 7, 8, 9, 5, 6] - - -def test_quick_sortable(): - enumeration = [1, 1, 2, 5, 12, 28, 65, 151, 351, 816] - for i in range(4, 7): - assert sum(1 for p in Perm.of_length(i) if quick_sortable(p)) == enumeration[i] - assert quick_sortable(Perm(())) - assert quick_sortable(Perm((0,))) - assert quick_sortable(Perm((0, 1))) - assert quick_sortable(Perm((1, 0))) - assert quick_sortable(Perm((0, 1, 2))) - assert quick_sortable(Perm((0, 2, 1))) - assert quick_sortable(Perm((1, 0, 2))) - assert quick_sortable(Perm((1, 2, 0))) - assert quick_sortable(Perm((2, 0, 1))) - assert not quick_sortable(Perm((2, 1, 0))) - assert not quick_sortable(Perm((2, 1, 0, 3))) - assert not quick_sortable(Perm((2, 3, 1, 0))) - assert not quick_sortable(Perm((3, 4, 2, 1, 0))) - assert not quick_sortable(Perm((4, 3, 2, 0, 1))) - assert quick_sortable(Perm((0, 2, 1, 3, 4, 5))) - assert quick_sortable(Perm((0, 2, 3, 4, 5, 1))) - assert not quick_sortable(Perm((5, 0, 1, 4, 3, 2, 6))) - assert not quick_sortable(Perm((3, 6, 5, 4, 7, 2, 0, 1))) - assert not quick_sortable(Perm((6, 9, 7, 2, 3, 0, 5, 4, 1, 8))) - assert not quick_sortable(Perm((7, 5, 0, 4, 3, 1, 9, 2, 6, 8))) - - -def test_bkv_sortable(): - patts_to_enumeration = { - (Perm((0, 1, 2)), Perm((0, 2, 1))): [1, 1, 2, 5, 14, 42, 132, 429], - (Perm((1, 2, 0)), Perm((0, 2, 1))): [1, 1, 2, 6, 22, 90, 394, 1806], - (): [1, 1, 2, 5, 14, 42, 132, 429], - (Perm((2, 1, 0)),): [1, 1, 2, 4, 8, 16, 32, 64], - (Perm((2, 1, 0, 3)),): [1, 1, 2, 5, 13, 34, 89, 233], - (Perm((3, 1, 0, 2)),): [1, 1, 2, 5, 13, 34, 89, 233], - (Perm((3, 2, 0, 1)),): [1, 1, 2, 5, 13, 34, 89, 233], - (Perm((3, 2, 1, 0)),): [1, 1, 2, 5, 13, 34, 89, 233], - (Perm((2, 1, 0, 3, 4)),): [1, 1, 2, 5, 14, 41, 121, 355], - (Perm((4, 1, 0, 2, 3)),): [1, 1, 2, 5, 14, 41, 121, 355], - (Perm((4, 3, 0, 1, 2)),): [1, 1, 2, 5, 14, 41, 121, 356], - (Perm((2, 1, 0, 4, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((3, 1, 0, 2, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((3, 2, 0, 1, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((3, 2, 1, 0, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 1, 0, 3, 2)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 2, 0, 1, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 2, 1, 0, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 3, 0, 2, 1)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 3, 1, 0, 2)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 3, 2, 0, 1)),): [1, 1, 2, 5, 14, 41, 122, 365], - (Perm((4, 3, 2, 1, 0)),): [1, 1, 2, 5, 14, 41, 122, 365], - } - - all_patts = patts_to_enumeration.keys() - compares = 7 # can be increased to 8 at most but slow - res = {k: [0] * compares for k in all_patts} - for i in range(compares): - for perm in Perm.of_length(i): - for k in all_patts: - if bkv_sortable(perm, k): - res[k][i] += 1 - slicer = compares - 8 - if slicer == 0: - slicer = 8 - assert all(res[pat] == patts_to_enumeration[pat][:slicer] for pat in all_patts) - assert bkv_sortable(Perm((0, 1)), ()) - assert not bkv_sortable(Perm((7, 6, 9, 2, 0, 3, 8, 1, 5, 4)), (Perm((0, 2, 1)),)) - assert not bkv_sortable(Perm((4, 5, 2, 6, 7, 8, 1, 0, 3)), (Perm((0, 1)),)) - assert bkv_sortable(Perm((2, 0, 1, 3, 4, 5, 6)), (Perm((2, 0, 1, 3)),)) - assert not bkv_sortable( - Perm((5, 2, 1, 0, 3, 4)), (Perm((2, 1, 0)), Perm((0, 2, 1))) - ) - assert bkv_sortable(Perm((3, 2, 1, 0, 4)), ()) - assert not bkv_sortable(Perm((4, 1, 2, 3, 0, 5)), (Perm((0, 2, 1)),)) - assert bkv_sortable(Perm((2, 0, 1)), (Perm((0, 1)),)) - assert bkv_sortable(Perm((2, 1, 0)), (Perm((2, 0, 1, 3)),)) - assert bkv_sortable(Perm((5, 3, 1, 0, 4, 2)), (Perm((2, 1, 0)), Perm((0, 2, 1)))) - assert bkv_sortable(Perm((0,)), ()) - assert bkv_sortable(Perm((2, 1, 3, 0)), (Perm((0, 2, 1)),)) - assert bkv_sortable(Perm((0,)), (Perm((0, 1)),)) - assert not bkv_sortable(Perm((6, 4, 0, 5, 8, 3, 2, 7, 1)), (Perm((2, 0, 1, 3)),)) - assert bkv_sortable(Perm(()), (Perm((2, 1, 0)), Perm((0, 2, 1)))) - assert not bkv_sortable(Perm((4, 1, 3, 2, 0)), ()) - assert not bkv_sortable(Perm((1, 2, 0, 3)), (Perm((0, 2, 1)),)) - assert bkv_sortable(Perm(()), (Perm((0, 1)),)) - assert not bkv_sortable(Perm((1, 5, 4, 2, 0, 3)), (Perm((2, 0, 1, 3)),)) - assert bkv_sortable(Perm(()), (Perm((2, 1, 0)), Perm((0, 2, 1)))) - - -def test_west_2_stack_sortable(): - eq_patt_avoidance = (Perm((1, 2, 3, 0)), MeshPatt(Perm((2, 1, 3, 0)), {(1, 4)})) - for _ in range(100): - if randint(0, 10) < 1: - p = Perm.random(randint(0, 3)) - else: - p = Perm.random(randint(4, 10)) - if p.avoids(*eq_patt_avoidance): - assert west_2_stack_sortable(p) - else: - assert not west_2_stack_sortable(p) - for n in (5, 6, 7): - assert sum( - 1 for p in Perm.of_length(n) if west_2_stack_sortable(p) - ) == 2 * factorial(3 * n) / (factorial(n + 1) * factorial(2 * n + 1)) - - -def test_west_3_stack_sortable(): - assert west_3_stack_sortable(Perm(())) - assert west_3_stack_sortable(Perm((0,))) - assert west_3_stack_sortable(Perm((0, 1))) - assert west_3_stack_sortable(Perm((1, 0))) - assert west_3_stack_sortable(Perm((0, 1, 2))) - assert west_3_stack_sortable(Perm((0, 2, 1))) - assert west_3_stack_sortable(Perm((1, 0, 2))) - assert west_3_stack_sortable(Perm((1, 2, 0))) - assert west_3_stack_sortable(Perm((2, 0, 1))) - assert west_3_stack_sortable(Perm((2, 1, 0))) - assert west_3_stack_sortable(Perm((0, 1, 2, 3))) - assert west_3_stack_sortable(Perm((0, 1, 3, 2))) - assert west_3_stack_sortable(Perm((2, 0, 5, 4, 1, 3))) - assert not west_3_stack_sortable(Perm((3, 2, 0, 4, 5, 1))) - assert west_3_stack_sortable(Perm((4, 6, 3, 2, 1, 0, 5))) - assert west_3_stack_sortable(Perm((6, 2, 3, 0, 5, 1, 4))) - assert west_3_stack_sortable(Perm((0, 3, 6, 2, 5, 1, 7, 4))) - assert west_3_stack_sortable(Perm((0, 3, 7, 8, 1, 6, 4, 2, 5))) - assert not west_3_stack_sortable(Perm((0, 2, 3, 4, 6, 5, 1))) - assert not west_3_stack_sortable(Perm((2, 3, 0, 4, 6, 1, 5))) - assert not west_3_stack_sortable(Perm((5, 4, 8, 0, 3, 6, 7, 2, 1))) - assert not west_3_stack_sortable(Perm((0, 3, 7, 5, 1, 4, 8, 6, 2, 9))) - assert not west_3_stack_sortable(Perm((5, 1, 11, 10, 9, 8, 6, 0, 4, 3, 7, 2))) - assert not west_3_stack_sortable( - Perm((4, 6, 9, 10, 13, 2, 0, 5, 8, 12, 3, 1, 11, 7)) - ) - assert 3494 == sum(1 for p in Perm.of_length(7) if west_3_stack_sortable(p)) - - def test_smooth(): assert smooth(Perm(())) assert smooth(Perm((0,))) diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 7fa7125..27cfb59 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2474,3 +2474,196 @@ def test_max_drop_size(): assert Perm((1, 5, 6, 7, 10, 11, 0, 2, 3, 4, 8, 9)).max_drop_size() == 6 assert Perm((3, 6, 7, 9, 10, 11, 0, 1, 2, 4, 5, 8)).max_drop_size() == 6 assert Perm((11, 10, 5, 4, 3, 2, 7, 6, 9, 8, 1, 0)).max_drop_size() == 11 + + +def test_stack_sortable(): + assert Perm(()).stack_sortable() + assert Perm((0,)).stack_sortable() + assert Perm((0, 1)).stack_sortable() + assert Perm((1, 0)).stack_sortable() + assert Perm((0, 1, 2)).stack_sortable() + assert Perm((0, 2, 1)).stack_sortable() + assert Perm((1, 0, 2)).stack_sortable() + assert not Perm((1, 2, 0)).stack_sortable() + assert Perm((2, 0, 1)).stack_sortable() + assert Perm((2, 1, 0)).stack_sortable() + assert Perm((2, 1, 0, 4, 3)).stack_sortable() + assert not Perm((1, 4, 3, 0, 8, 5, 2, 9, 7, 6)).stack_sortable() + assert not Perm((1, 3, 0, 2)).stack_sortable() + assert Perm((3, 0, 1, 2)).stack_sortable() + assert not Perm((6, 2, 4, 3, 7, 1, 5, 0)).stack_sortable() + assert not Perm((4, 8, 5, 0, 6, 1, 7, 3, 2)).stack_sortable() + assert Perm((0, 1, 3, 2)).stack_sortable() + assert Perm((3, 0, 2, 1)).stack_sortable() + assert not Perm((1, 0, 7, 2, 5, 4, 3, 8, 9, 6)).stack_sortable() + assert not Perm((4, 1, 5, 2, 6, 0, 3, 8, 7, 9)).stack_sortable() + assert Perm((0, 12, 11, 10, 9, 1, 5, 4, 2, 3, 6, 7, 8, 14, 13)).stack_sortable() + + +def test_bubble_sortable(): + enumeration = [1] + enumeration.extend([2 ** i for i in range(10)]) + assert Perm(()).bubble_sortable() + assert Perm((0,)).bubble_sortable() + assert Perm((0, 1)).bubble_sortable() + assert Perm((1, 0)).bubble_sortable() + assert Perm((0, 1, 2)).bubble_sortable() + assert Perm((0, 2, 1)).bubble_sortable() + assert Perm((1, 0, 2)).bubble_sortable() + assert not Perm((1, 2, 0)).bubble_sortable() + assert Perm((2, 0, 1)).bubble_sortable() + assert not Perm((2, 1, 0)).bubble_sortable() + assert Perm((2, 0, 1, 3)).bubble_sortable() + assert not Perm((1, 4, 3, 2, 0)).bubble_sortable() + assert not Perm((0, 1, 5, 4, 2, 3)).bubble_sortable() + assert not Perm((1, 3, 4, 0, 6, 2, 5, 7)).bubble_sortable() + assert not Perm((1, 5, 6, 7, 0, 3, 2, 4)).bubble_sortable() + assert not Perm((2, 3, 1, 6, 4, 7, 5, 0)).bubble_sortable() + assert not Perm((2, 5, 1, 4, 7, 0, 6, 3)).bubble_sortable() + assert not Perm((3, 0, 4, 5, 7, 6, 1, 2)).bubble_sortable() + assert not Perm((4, 0, 7, 5, 3, 6, 2, 1)).bubble_sortable() + assert not Perm((6, 5, 2, 0, 3, 7, 1, 8, 4)).bubble_sortable() + for i in range(4, 7): + assert ( + sum(1 for p in Perm.of_length(i) if p.bubble_sortable()) == enumeration[i] + ) + patts = (Perm((1, 2, 0)), Perm((2, 1, 0))) + for i in range(20): + p = Perm.random(random.randint(5, 10)) + if p.avoids(*patts): + assert p.bubble_sortable() + else: + assert not p.bubble_sortable() + + +def test_quick_sortable(): + enumeration = [1, 1, 2, 5, 12, 28, 65, 151, 351, 816] + for i in range(4, 7): + assert sum(1 for p in Perm.of_length(i) if p.quick_sortable()) == enumeration[i] + assert Perm(()).quick_sortable() + assert Perm((0,)).quick_sortable() + assert Perm((0, 1)).quick_sortable() + assert Perm((1, 0)).quick_sortable() + assert Perm((0, 1, 2)).quick_sortable() + assert Perm((0, 2, 1)).quick_sortable() + assert Perm((1, 0, 2)).quick_sortable() + assert Perm((1, 2, 0)).quick_sortable() + assert Perm((2, 0, 1)).quick_sortable() + assert not Perm((2, 1, 0)).quick_sortable() + assert not Perm((2, 1, 0, 3)).quick_sortable() + assert not Perm((2, 3, 1, 0)).quick_sortable() + assert not Perm((3, 4, 2, 1, 0)).quick_sortable() + assert not Perm((4, 3, 2, 0, 1)).quick_sortable() + assert Perm((0, 2, 1, 3, 4, 5)).quick_sortable() + assert Perm((0, 2, 3, 4, 5, 1)).quick_sortable() + assert not Perm((5, 0, 1, 4, 3, 2, 6)).quick_sortable() + assert not Perm((3, 6, 5, 4, 7, 2, 0, 1)).quick_sortable() + assert not Perm((6, 9, 7, 2, 3, 0, 5, 4, 1, 8)).quick_sortable() + assert not Perm((7, 5, 0, 4, 3, 1, 9, 2, 6, 8)).quick_sortable() + + +def test_bkv_sortable(): + patts_to_enumeration = { + (Perm((0, 1, 2)), Perm((0, 2, 1))): [1, 1, 2, 5, 14, 42, 132, 429], + (Perm((1, 2, 0)), Perm((0, 2, 1))): [1, 1, 2, 6, 22, 90, 394, 1806], + (): [1, 1, 2, 5, 14, 42, 132, 429], + (Perm((2, 1, 0)),): [1, 1, 2, 4, 8, 16, 32, 64], + (Perm((2, 1, 0, 3)),): [1, 1, 2, 5, 13, 34, 89, 233], + (Perm((3, 1, 0, 2)),): [1, 1, 2, 5, 13, 34, 89, 233], + (Perm((3, 2, 0, 1)),): [1, 1, 2, 5, 13, 34, 89, 233], + (Perm((3, 2, 1, 0)),): [1, 1, 2, 5, 13, 34, 89, 233], + (Perm((2, 1, 0, 3, 4)),): [1, 1, 2, 5, 14, 41, 121, 355], + (Perm((4, 1, 0, 2, 3)),): [1, 1, 2, 5, 14, 41, 121, 355], + (Perm((4, 3, 0, 1, 2)),): [1, 1, 2, 5, 14, 41, 121, 356], + (Perm((2, 1, 0, 4, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((3, 1, 0, 2, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((3, 2, 0, 1, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((3, 2, 1, 0, 4)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 1, 0, 3, 2)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 2, 0, 1, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 2, 1, 0, 3)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 3, 0, 2, 1)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 3, 1, 0, 2)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 3, 2, 0, 1)),): [1, 1, 2, 5, 14, 41, 122, 365], + (Perm((4, 3, 2, 1, 0)),): [1, 1, 2, 5, 14, 41, 122, 365], + } + + all_patts = patts_to_enumeration.keys() + compares = 7 # can be increased to 8 at most but slow + res = {k: [0] * compares for k in all_patts} + for i in range(compares): + for perm in Perm.of_length(i): + for k in all_patts: + if perm.bkv_sortable(k): + res[k][i] += 1 + slicer = compares - 8 + if slicer == 0: + slicer = 8 + assert all(res[pat] == patts_to_enumeration[pat][:slicer] for pat in all_patts) + assert Perm((0, 1)).bkv_sortable(()) + assert not Perm((7, 6, 9, 2, 0, 3, 8, 1, 5, 4)).bkv_sortable((Perm((0, 2, 1)),)) + assert not Perm((4, 5, 2, 6, 7, 8, 1, 0, 3)).bkv_sortable((Perm((0, 1)),)) + assert Perm((2, 0, 1, 3, 4, 5, 6)).bkv_sortable((Perm((2, 0, 1, 3)),)) + assert not Perm((5, 2, 1, 0, 3, 4)).bkv_sortable((Perm((2, 1, 0)), Perm((0, 2, 1)))) + assert Perm((3, 2, 1, 0, 4)).bkv_sortable(()) + assert not Perm((4, 1, 2, 3, 0, 5)).bkv_sortable((Perm((0, 2, 1)),)) + assert Perm((2, 0, 1)).bkv_sortable((Perm((0, 1)),)) + assert Perm((2, 1, 0)).bkv_sortable((Perm((2, 0, 1, 3)),)) + assert Perm((5, 3, 1, 0, 4, 2)).bkv_sortable((Perm((2, 1, 0)), Perm((0, 2, 1)))) + assert Perm((0,)).bkv_sortable(()) + assert Perm((2, 1, 3, 0)).bkv_sortable((Perm((0, 2, 1)),)) + assert Perm((0,)).bkv_sortable((Perm((0, 1)),)) + assert not Perm((6, 4, 0, 5, 8, 3, 2, 7, 1)).bkv_sortable((Perm((2, 0, 1, 3)),)) + assert Perm(()).bkv_sortable((Perm((2, 1, 0)), Perm((0, 2, 1)))) + assert not Perm((4, 1, 3, 2, 0)).bkv_sortable(()) + assert not Perm((1, 2, 0, 3)).bkv_sortable((Perm((0, 2, 1)),)) + assert Perm(()).bkv_sortable((Perm((0, 1)),)) + assert not Perm((1, 5, 4, 2, 0, 3)).bkv_sortable((Perm((2, 0, 1, 3)),)) + assert Perm(()).bkv_sortable((Perm((2, 1, 0)), Perm((0, 2, 1)))) + + +def test_west_2_stack_sortable(): + eq_patt_avoidance = (Perm((1, 2, 3, 0)), MeshPatt(Perm((2, 1, 3, 0)), {(1, 4)})) + for _ in range(100): + if random.randint(0, 10) < 1: + p = Perm.random(random.randint(0, 3)) + else: + p = Perm.random(random.randint(4, 10)) + if p.avoids(*eq_patt_avoidance): + assert p.west_2_stack_sortable() + else: + assert not p.west_2_stack_sortable() + for n in (5, 6, 7): + assert sum( + 1 for p in Perm.of_length(n) if p.west_2_stack_sortable() + ) == 2 * factorial(3 * n) / (factorial(n + 1) * factorial(2 * n + 1)) + + +def test_west_3_stack_sortable(): + assert Perm(()).west_3_stack_sortable() + assert Perm((0,)).west_3_stack_sortable() + assert Perm((0, 1)).west_3_stack_sortable() + assert Perm((1, 0)).west_3_stack_sortable() + assert Perm((0, 1, 2)).west_3_stack_sortable() + assert Perm((0, 2, 1)).west_3_stack_sortable() + assert Perm((1, 0, 2)).west_3_stack_sortable() + assert Perm((1, 2, 0)).west_3_stack_sortable() + assert Perm((2, 0, 1)).west_3_stack_sortable() + assert Perm((2, 1, 0)).west_3_stack_sortable() + assert Perm((0, 1, 2, 3)).west_3_stack_sortable() + assert Perm((0, 1, 3, 2)).west_3_stack_sortable() + assert Perm((2, 0, 5, 4, 1, 3)).west_3_stack_sortable() + assert not Perm((3, 2, 0, 4, 5, 1)).west_3_stack_sortable() + assert Perm((4, 6, 3, 2, 1, 0, 5)).west_3_stack_sortable() + assert Perm((6, 2, 3, 0, 5, 1, 4)).west_3_stack_sortable() + assert Perm((0, 3, 6, 2, 5, 1, 7, 4)).west_3_stack_sortable() + assert Perm((0, 3, 7, 8, 1, 6, 4, 2, 5)).west_3_stack_sortable() + assert not Perm((0, 2, 3, 4, 6, 5, 1)).west_3_stack_sortable() + assert not Perm((2, 3, 0, 4, 6, 1, 5)).west_3_stack_sortable() + assert not Perm((5, 4, 8, 0, 3, 6, 7, 2, 1)).west_3_stack_sortable() + assert not Perm((0, 3, 7, 5, 1, 4, 8, 6, 2, 9)).west_3_stack_sortable() + assert not Perm((5, 1, 11, 10, 9, 8, 6, 0, 4, 3, 7, 2)).west_3_stack_sortable() + assert not Perm( + (4, 6, 9, 10, 13, 2, 0, 5, 8, 12, 3, 1, 11, 7) + ).west_3_stack_sortable() + assert 3494 == sum(1 for p in Perm.of_length(7) if p.west_3_stack_sortable()) From c8f6610f55c7a5bde5d2913f8affb9059942f0c8 Mon Sep 17 00:00:00 2001 From: quintant Date: Thu, 3 Jun 2021 15:27:20 +0000 Subject: [PATCH 17/41] Added number of primes in the column sums of the two line notation of a permutation --- README.rst | 1 + permuta/misc/math.py | 12 ++++++++++++ permuta/patterns/perm.py | 10 ++++++++++ permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 31 +++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+) create mode 100644 permuta/misc/math.py diff --git a/README.rst b/README.rst index 12c3259..c57f185 100644 --- a/README.rst +++ b/README.rst @@ -238,6 +238,7 @@ and a class (no class will use the set of all permutations). [15] Longest decreasing subsequence [16] Depth [17] Number of bounces + [18] Number of primes in the column sums >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/misc/math.py b/permuta/misc/math.py new file mode 100644 index 0000000..50916db --- /dev/null +++ b/permuta/misc/math.py @@ -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 diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 7eaa853..e6b3cd6 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -26,6 +26,7 @@ ) from permuta.misc import HTMLViewer +from permuta.misc.math import is_prime from .patt import Patt @@ -890,6 +891,15 @@ def count_peaks(self) -> int: num_peaks = count_peaks + def count_column_sum_primes(self): + """Returns the number of primes in the column sums of the two line notation + of a permutation. + """ + return sum(1 for idx, val in enumerate(self) if is_prime(val + idx + 2)) + # + 2 because both values are 0 indexed + + num_column_sum_primes = count_column_sum_primes + def valleys(self) -> Iterator[int]: """Yield the indices of the valleys of self. The i-th element of a perm is a valley if self[i-1] > self[i] < self[i+1]. diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 4b625f7..cc0dada 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -34,6 +34,7 @@ class PermutationStatistic: ("Longest decreasing subsequence", Perm.length_of_longestrun_descending), ("Depth", Perm.depth), ("Number of bounces", Perm.count_bounces), + ("Number of primes in the column sums", Perm.count_column_sum_primes), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 1dcf4a7..8d38da8 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2409,3 +2409,34 @@ def test_count_bounces(): assert Perm((4, 5, 2, 0, 3, 1)).count_bounces() == 2 assert Perm((4, 5, 3, 1, 0, 2)).count_bounces() == 1 assert Perm((5, 0, 1, 3, 4, 2)).count_bounces() == 4 + + +def test_count_column_sum_primes(): + assert Perm((0,)).count_column_sum_primes() == 1 + assert Perm((0, 1)).count_column_sum_primes() == 1 + assert Perm((1, 0)).count_column_sum_primes() == 2 + assert Perm((0, 1, 2)).count_column_sum_primes() == 1 + assert Perm((0, 2, 1)).count_column_sum_primes() == 3 + assert Perm((1, 0, 2)).count_column_sum_primes() == 2 + assert Perm((1, 2, 0)).count_column_sum_primes() == 2 + assert Perm((2, 0, 1)).count_column_sum_primes() == 2 + assert Perm((2, 1, 0)).count_column_sum_primes() == 0 + assert Perm((1, 0, 3, 4, 2)).count_column_sum_primes() == 3 + assert Perm((3, 2, 1, 4, 0)).count_column_sum_primes() == 3 + assert Perm((0, 2, 1, 4, 5, 3)).count_column_sum_primes() == 4 + assert Perm((0, 4, 3, 2, 5, 1)).count_column_sum_primes() == 5 + assert Perm((1, 2, 0, 4, 5, 3)).count_column_sum_primes() == 3 + assert Perm((1, 4, 3, 2, 5, 0)).count_column_sum_primes() == 6 + assert Perm((2, 1, 0, 4, 5, 3)).count_column_sum_primes() == 1 + assert Perm((2, 4, 3, 1, 5, 0)).count_column_sum_primes() == 4 + assert Perm((3, 1, 0, 4, 5, 2)).count_column_sum_primes() == 2 + assert Perm((3, 4, 2, 1, 5, 0)).count_column_sum_primes() == 4 + assert Perm((4, 1, 0, 3, 5, 2)).count_column_sum_primes() == 1 + assert Perm((4, 3, 2, 1, 5, 0)).count_column_sum_primes() == 2 + assert Perm((5, 1, 0, 3, 4, 2)).count_column_sum_primes() == 1 + assert Perm((5, 3, 2, 1, 4, 0)).count_column_sum_primes() == 2 + assert Perm((0, 1, 3, 2, 5, 6, 4)).count_column_sum_primes() == 5 + assert Perm((0, 1, 5, 4, 3, 6, 2)).count_column_sum_primes() == 2 + assert Perm((0, 2, 3, 1, 5, 6, 4)).count_column_sum_primes() == 5 + assert Perm((0, 2, 5, 4, 3, 6, 1)).count_column_sum_primes() == 3 + assert Perm((0, 3, 2, 1, 5, 6, 4)).count_column_sum_primes() == 3 From a26011e8abe18dacaebeaae9ef8e0f1167d655e1 Mon Sep 17 00:00:00 2001 From: quintant Date: Thu, 3 Jun 2021 15:34:55 +0000 Subject: [PATCH 18/41] Added references --- permuta/patterns/perm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index e7b7b23..ec0651a 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -894,6 +894,8 @@ def count_peaks(self) -> int: def count_column_sum_primes(self): """Returns the number of primes in the column sums of the two line notation of a permutation. + See: https://www.findstat.org/StatisticsDatabase/St001285/ + https://arxiv.org/abs/1809.01012 """ return sum(1 for idx, val in enumerate(self) if is_prime(val + idx + 2)) # + 2 because both values are 0 indexed From 8581e17b3eb4979cb3e014817cc201bfcc3109b0 Mon Sep 17 00:00:00 2001 From: quintant Date: Thu, 3 Jun 2021 15:43:30 +0000 Subject: [PATCH 19/41] Added typehints and examples to count_column_sum_primes --- permuta/patterns/perm.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index ec0651a..7e0750b 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -891,11 +891,19 @@ def count_peaks(self) -> int: num_peaks = count_peaks - def count_column_sum_primes(self): + def count_column_sum_primes(self) -> int: """Returns the number of primes in the column sums of the two line notation of a permutation. See: https://www.findstat.org/StatisticsDatabase/St001285/ https://arxiv.org/abs/1809.01012 + + Examples: + >>> Perm((0,)).count_column_sum_primes() + 1 + >>> Perm((0, 1)).count_column_sum_primes() + 1 + >>> Perm((1, 0)).count_column_sum_primes() + 2 """ return sum(1 for idx, val in enumerate(self) if is_prime(val + idx + 2)) # + 2 because both values are 0 indexed From df1d05c84c46ec5c919af37f17acfecd354eeb10 Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Thu, 3 Jun 2021 15:47:18 +0000 Subject: [PATCH 20/41] Fixing bugs --- README.rst | 28 +++++++++++++--------------- permuta/patterns/perm.py | 2 +- tests/patterns/test_perm.py | 3 ++- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index 8e04d6e..3fbbd76 100644 --- a/README.rst +++ b/README.rst @@ -291,20 +291,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(lambda perm: 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(lambda perm: perm.stack_sortable(), 3) I will use permutations up to length 7 {3: {Perm((1, 2, 0)): [set()]}} @@ -319,7 +318,7 @@ be considered. .. code-block:: python - >>> SG = bisc(stack_sortable, 3, 5) + >>> SG = bisc(lambda perm: perm.stack_sortable(), 3, 5) >>> show_me(SG) There are 1 underlying classical patterns of length 3 There are 1 different shadings on 120 @@ -345,8 +344,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(lambda perm: 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 @@ -398,7 +396,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, lambda perm: 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 diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index a5b2114..3be9d70 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -2182,7 +2182,7 @@ def bkv_sortable(self, patterns: Tuple[Patt, ...] = ()) -> bool: if right_stack: left_stack.appendleft(right_stack[0]) - if Perm._is_sorted(left_stack): + if Perm.to_standard(left_stack).is_increasing(): right_stack.popleft() continue left_stack.popleft() diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 27cfb59..b4d3b63 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -4,7 +4,8 @@ import pytest -from permuta import Perm +from math import factorial +from permuta import MeshPatt, Perm def test_from_iterable_validated(): From 46d233562e6333bd19671f5a5dbe09fe6e872382 Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Thu, 3 Jun 2021 15:53:37 +0000 Subject: [PATCH 21/41] Making pylint and isort happy --- permuta/bisc/perm_properties.py | 3 +-- permuta/patterns/perm.py | 3 +++ tests/patterns/test_perm.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/permuta/bisc/perm_properties.py b/permuta/bisc/perm_properties.py index 08f0d66..d7ccb73 100644 --- a/permuta/bisc/perm_properties.py +++ b/permuta/bisc/perm_properties.py @@ -1,8 +1,7 @@ from itertools import islice -from typing import 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 diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 3be9d70..7e98495 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -2087,6 +2087,7 @@ def _stack_sort(perm_slice: List[int]) -> List[int]: return n_lis def stack_sort(self) -> "Perm": + """Stack sorting the permutation""" return Perm(Perm._stack_sort(list(self))) def stack_sortable(self) -> bool: @@ -2112,6 +2113,7 @@ def _bubble_sort(perm_slice: List[int]) -> List[int]: return n_lis def bubble_sort(self) -> "Perm": + """Bubble sorting the permutation""" return Perm(Perm._bubble_sort(list(self))) def bubble_sortable(self) -> bool: @@ -2147,6 +2149,7 @@ def _quick_sort(perm_slice: List[int]) -> List[int]: return lis def quick_sort(self) -> "Perm": + """Quick sorting the permutation""" return Perm(Perm._quick_sort(list(self))) def quick_sortable(self) -> bool: diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index b4d3b63..39375dd 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -1,10 +1,10 @@ import itertools import random from collections import deque +from math import factorial import pytest -from math import factorial from permuta import MeshPatt, Perm From e5fd6abbb331269037b15c22533c3a35c34acc17 Mon Sep 17 00:00:00 2001 From: quintant Date: Thu, 3 Jun 2021 16:35:04 +0000 Subject: [PATCH 22/41] Add holeyness --- permuta/patterns/perm.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 1bf18b4..3b54468 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1157,6 +1157,27 @@ def max_drop_size(self): 2""" return max((self[i] - i for i in range(len(self))), default=0) + def holeyness(self) -> int: + """The holeyness of a permutation.""" + + def delta(d_set): + return sum(1 for x in d_set if x + 1 not in d_set) + + def set_generator(num): + yield () + for y in range(1, num + 1): + for x in itertools.combinations(range(num), y): + yield x + + n = len(self) + holyness = 0 + for tmp_set in set_generator(n): + h_pi = delta([self[s] for s in tmp_set]) + h_s = delta(tmp_set) + holyness = max(holyness, h_pi - h_s) + + return holyness + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). From 35b74131918a62b991ddda80e3e7c9edfd2798c5 Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Thu, 3 Jun 2021 18:05:44 +0000 Subject: [PATCH 23/41] Removing unused imports --- tests/bisc/test_perm_properties.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/bisc/test_perm_properties.py b/tests/bisc/test_perm_properties.py index 4d435d0..4e020d3 100644 --- a/tests/bisc/test_perm_properties.py +++ b/tests/bisc/test_perm_properties.py @@ -1,7 +1,4 @@ -from math import factorial -from random import randint - -from permuta import MeshPatt, Perm +from permuta import Perm from permuta.bisc.perm_properties import ( _perm_to_yt, av_231_and_mesh, From f255e4686635ecdf359ea2c3b7786828562d710c Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Thu, 3 Jun 2021 18:15:03 +0000 Subject: [PATCH 24/41] Removing blank line --- permuta/bisc/perm_properties.py | 1 - 1 file changed, 1 deletion(-) diff --git a/permuta/bisc/perm_properties.py b/permuta/bisc/perm_properties.py index d7ccb73..92dc565 100644 --- a/permuta/bisc/perm_properties.py +++ b/permuta/bisc/perm_properties.py @@ -5,7 +5,6 @@ from permuta.patterns.perm import Perm from permuta.permutils.groups import dihedral_group - _SMOOTH_PATT = (Perm((0, 2, 1, 3)), Perm((1, 0, 3, 2))) From 118011974b5ee3c26fa119f6d2b62b9faa1b3267 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 09:00:45 +0000 Subject: [PATCH 25/41] References, examples and test for holeyness --- README.rst | 2 ++ permuta/patterns/perm.py | 21 ++++++++++++++++++--- permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index cc09fde..77feb80 100644 --- a/README.rst +++ b/README.rst @@ -240,6 +240,7 @@ and a class (no class will use the set of all permutations). [17] Number of bounces [18] Maximum drop size [19] Number of primes in the column sums + [20] Holeyness of a permutation >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] @@ -256,6 +257,7 @@ 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 We can find all (predefined) statistics equally distributed over two permutation classes with ``equally_distributed``. We also support checks for joint distribution diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index afe3160..4d0ee3f 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1150,7 +1150,8 @@ def count_bounces(self): >>> Perm((0, 1)).count_bounces() 1 >>> Perm((1, 0)).count_bounces() - 0""" + 0 + """ n = len(self) if n == 0: return 0 @@ -1174,11 +1175,25 @@ def max_drop_size(self): >>> Perm((1, 0)).max_drop_size() 1 >>> Perm((2, 0, 1)).max_drop_size() - 2""" + 2 + """ return max((val - idx for idx, val in enumerate(self)), default=0) def holeyness(self) -> int: - """The holeyness of a permutation.""" + """The holeyness of a permutation. + See: https://www.findstat.org/StatisticsDatabase/St001469/ + https://mathoverflow.net/questions/340179/how-rare-are-unholey-permutations + + Examples: + >>> Perm((1, 0)).holeyness() + 0 + >>> Perm((0, 1, 2)).holeyness() + 0 + >>> Perm((0, 2, 1)).holeyness() + 1 + >>> Perm((1, 0, 2)).holeyness() + 1 + """ def delta(d_set): return sum(1 for x in d_set if x + 1 not in d_set) diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 5cef67d..f7371ec 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -36,6 +36,7 @@ class PermutationStatistic: ("Number of bounces", Perm.count_bounces), ("Maximum drop size", Perm.max_drop_size), ("Number of primes in the column sums", Perm.count_column_sum_primes), + ("Holeyness of a permutation", Perm.holeyness), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index b53f8f1..a054aa8 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2505,3 +2505,34 @@ def test_count_column_sum_primes(): assert Perm((0, 2, 3, 1, 5, 6, 4)).count_column_sum_primes() == 5 assert Perm((0, 2, 5, 4, 3, 6, 1)).count_column_sum_primes() == 3 assert Perm((0, 3, 2, 1, 5, 6, 4)).count_column_sum_primes() == 3 + + +def test_holeyness(): + assert Perm((0,)).holeyness() == 0 + assert Perm((0, 1)).holeyness() == 0 + assert Perm((1, 0)).holeyness() == 0 + assert Perm((0, 1, 2)).holeyness() == 0 + assert Perm((0, 2, 1)).holeyness() == 1 + assert Perm((1, 0, 2)).holeyness() == 1 + assert Perm((1, 2, 0)).holeyness() == 1 + assert Perm((2, 0, 1)).holeyness() == 1 + assert Perm((2, 1, 0)).holeyness() == 0 + assert Perm((1, 0, 3, 4, 2)).holeyness() == 1 + assert Perm((3, 2, 1, 4, 0)).holeyness() == 1 + assert Perm((0, 2, 1, 4, 5, 3)).holeyness() == 1 + assert Perm((0, 4, 3, 2, 5, 1)).holeyness() == 1 + assert Perm((1, 2, 0, 4, 5, 3)).holeyness() == 2 + assert Perm((1, 4, 3, 2, 5, 0)).holeyness() == 2 + assert Perm((2, 1, 0, 4, 5, 3)).holeyness() == 1 + assert Perm((2, 4, 3, 1, 5, 0)).holeyness() == 2 + assert Perm((3, 1, 0, 4, 5, 2)).holeyness() == 2 + assert Perm((3, 4, 2, 1, 5, 0)).holeyness() == 1 + assert Perm((4, 1, 0, 3, 5, 2)).holeyness() == 2 + assert Perm((4, 3, 2, 1, 5, 0)).holeyness() == 1 + assert Perm((5, 1, 0, 3, 4, 2)).holeyness() == 2 + assert Perm((5, 3, 2, 1, 4, 0)).holeyness() == 1 + assert Perm((0, 1, 3, 2, 5, 6, 4)).holeyness() == 1 + assert Perm((0, 1, 5, 4, 3, 6, 2)).holeyness() == 1 + assert Perm((0, 2, 3, 1, 5, 6, 4)).holeyness() == 2 + assert Perm((0, 2, 5, 4, 3, 6, 1)).holeyness() == 2 + assert Perm((0, 3, 2, 1, 5, 6, 4)).holeyness() == 1 From 7b28ecea38c96339fc0679c167a9ddb9516e5651 Mon Sep 17 00:00:00 2001 From: Henning Ulfarsson Date: Fri, 4 Jun 2021 09:27:58 +0000 Subject: [PATCH 26/41] Fixing readme --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 3fbbd76..ddce22a 100644 --- a/README.rst +++ b/README.rst @@ -294,7 +294,7 @@ A classic example of a set of permutations described by pattern avoidance are 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(lambda perm: perm.stack_sortable())`` and let the algorithm 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 @@ -303,7 +303,7 @@ property into ``bisc`` and ask it to search for patterns of length 3. .. code-block:: python - >>> bisc(lambda perm: perm.stack_sortable(), 3) + >>> bisc(Perm.stack_sortable, 3) I will use permutations up to length 7 {3: {Perm((1, 2, 0)): [set()]}} @@ -318,7 +318,7 @@ be considered. .. code-block:: python - >>> SG = bisc(lambda perm: perm.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 @@ -344,7 +344,7 @@ patterns, such as the West-2-stack-sortable permutations .. code-block:: python - >>> SG = bisc(lambda perm: perm.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 @@ -396,7 +396,7 @@ which keeps them separated by length. .. code-block:: python - >>> A, B = create_bisc_input(7, lambda perm: perm.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 From 815b9c7e5a50f00379a9696fbcdb42b3a7ce3295 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 09:36:58 +0000 Subject: [PATCH 27/41] empty perm test for holeynes --- tests/patterns/test_perm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index a054aa8..292bba9 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2508,6 +2508,7 @@ def test_count_column_sum_primes(): def test_holeyness(): + assert Perm(()).holeyness() == 0 assert Perm((0,)).holeyness() == 0 assert Perm((0, 1)).holeyness() == 0 assert Perm((1, 0)).holeyness() == 0 From 12a13a15932b638ae75f32c97d80a5d3fc28de99 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 09:56:59 +0000 Subject: [PATCH 28/41] typing and small changes to holeyness --- permuta/patterns/perm.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 4d0ee3f..39e906d 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1195,23 +1195,18 @@ def holeyness(self) -> int: 1 """ - def delta(d_set): + def _delta(d_set: Set[int]) -> int: return sum(1 for x in d_set if x + 1 not in d_set) - def set_generator(num): - yield () - for y in range(1, num + 1): + def _set_generator(num: int) -> Iterator[Set[int]]: + for y in range(0, num + 1): for x in itertools.combinations(range(num), y): - yield x - - n = len(self) - holyness = 0 - for tmp_set in set_generator(n): - h_pi = delta([self[s] for s in tmp_set]) - h_s = delta(tmp_set) - holyness = max(holyness, h_pi - h_s) + yield set(x) - return holyness + return max( + _delta({self[s] for s in tmp_set}) - _delta(tmp_set) + for tmp_set in _set_generator(len(self)) + ) def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j From 597e28922a3369bb9a1de9c815fa4ec9f7454a80 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 11:06:22 +0000 Subject: [PATCH 29/41] Implement count_stack_sorts --- README.rst | 1 + permuta/patterns/perm.py | 30 +++++++++++++++++++++ permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 46 +++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/README.rst b/README.rst index ad70d97..de96e84 100644 --- a/README.rst +++ b/README.rst @@ -241,6 +241,7 @@ and a class (no class will use the set of all permutations). [18] Maximum drop size [19] Number of primes in the column sums [20] Holeyness of a permutation + [21] Number of stack-sorts needed >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 738ab91..cad664f 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1208,6 +1208,36 @@ def _set_generator(num: int) -> Iterator[Set[int]]: for tmp_set in _set_generator(len(self)) ) + def count_stack_sorts(self): + """The number of stack-sorts needed to sort a permutation. + See: https://www.findstat.org/StatisticsDatabase/St000028/ + https://mathscinet.ams.org/mathscinet/search/publdoc.html?pg1=MR&s1=MR2028290 + https://arxiv.org/abs/1110.1219 + https://mathscinet.ams.org/mathscinet/search/publdoc.html?pg1=MR&s1=MR0445948 + https://mathscinet.ams.org/mathscinet/search/publdoc.html?pg1=MR&s1=MR1168135 + + Examples: + >>> Perm(()).count_stack_sorts() + 0 + >>> Perm((0,)).count_stack_sorts() + 0 + >>> Perm((0, 1)).count_stack_sorts() + 0 + >>> Perm((1, 0)).count_stack_sorts() + 1 + >>> Perm((1, 2, 0)).count_stack_sorts() + 2 + >>> Perm((2, 1, 0)).count_stack_sorts() + 1 + """ + i = 0 + identity = list(self.identity(len(self))) + perm_list = list(self) + while perm_list != identity: + perm_list = self._stack_sort(perm_list) + i += 1 + return i + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index f7371ec..b07a432 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -37,6 +37,7 @@ class PermutationStatistic: ("Maximum drop size", Perm.max_drop_size), ("Number of primes in the column sums", Perm.count_column_sum_primes), ("Holeyness of a permutation", Perm.holeyness), + ("Number of stack-sorts needed", Perm.count_stack_sorts), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 1c9649b..e50b371 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2731,3 +2731,49 @@ def test_holeyness(): assert Perm((0, 2, 3, 1, 5, 6, 4)).holeyness() == 2 assert Perm((0, 2, 5, 4, 3, 6, 1)).holeyness() == 2 assert Perm((0, 3, 2, 1, 5, 6, 4)).holeyness() == 1 + + +def test_count_stack_sorts(): + assert Perm(()).count_stack_sorts() == 0 + assert Perm((0,)).count_stack_sorts() == 0 + assert Perm((0, 1)).count_stack_sorts() == 0 + assert Perm((1, 0)).count_stack_sorts() == 1 + assert Perm((0, 1, 2)).count_stack_sorts() == 0 + assert Perm((0, 2, 1)).count_stack_sorts() == 1 + assert Perm((1, 0, 2)).count_stack_sorts() == 1 + assert Perm((1, 2, 0)).count_stack_sorts() == 2 + assert Perm((2, 0, 1)).count_stack_sorts() == 1 + assert Perm((2, 1, 0)).count_stack_sorts() == 1 + assert Perm((1, 4, 3, 0, 2)).count_stack_sorts() == 2 + assert Perm((0, 1, 3, 2, 4, 5)).count_stack_sorts() == 1 + assert Perm((0, 4, 3, 2, 1, 5)).count_stack_sorts() == 1 + assert Perm((1, 2, 5, 4, 0, 3)).count_stack_sorts() == 3 + assert Perm((2, 0, 3, 1, 4, 5)).count_stack_sorts() == 2 + assert Perm((2, 4, 3, 1, 0, 5)).count_stack_sorts() == 2 + assert Perm((3, 1, 5, 4, 0, 2)).count_stack_sorts() == 3 + assert Perm((4, 0, 2, 1, 3, 5)).count_stack_sorts() == 1 + assert Perm((4, 3, 2, 1, 0, 5)).count_stack_sorts() == 1 + assert Perm((5, 1, 4, 3, 0, 2)).count_stack_sorts() == 2 + assert Perm((0, 2, 6, 1, 3, 4, 5)).count_stack_sorts() == 2 + assert Perm((3, 2, 4, 1, 5, 6, 0)).count_stack_sorts() == 6 + assert Perm((7, 6, 5, 4, 3, 2, 1, 0)).count_stack_sorts() == 1 + assert Perm((7, 1, 0, 2, 3, 4, 5, 6)).count_stack_sorts() == 1 + assert Perm((1, 0, 4, 3, 5, 2, 7, 6)).count_stack_sorts() == 3 + assert Perm((2, 0, 3, 1, 5, 7, 4, 6)).count_stack_sorts() == 2 + assert Perm((0, 5, 6, 1, 2, 3, 4, 7)).count_stack_sorts() == 2 + assert Perm((5, 4, 7, 6, 1, 0, 3, 2)).count_stack_sorts() == 3 + assert Perm((0, 5, 1, 4, 2, 6, 3, 7)).count_stack_sorts() == 3 + assert Perm((1, 0, 7, 3, 6, 4, 5, 2)).count_stack_sorts() == 3 + assert Perm((1, 0, 4, 2, 7, 6, 5, 3)).count_stack_sorts() == 2 + assert Perm((2, 1, 4, 0, 6, 3, 7, 5)).count_stack_sorts() == 3 + assert Perm((5, 4, 1, 0, 6, 2, 7, 3)).count_stack_sorts() == 4 + assert Perm((6, 5, 7, 0, 2, 1, 3, 4)).count_stack_sorts() == 3 + assert Perm((4, 3, 6, 0, 7, 2, 1, 5)).count_stack_sorts() == 4 + assert Perm((6, 0, 4, 3, 7, 1, 5, 2)).count_stack_sorts() == 4 + assert Perm((0, 7, 8, 1, 2, 3, 4, 5, 6)).count_stack_sorts() == 2 + assert Perm((9, 6, 5, 4, 3, 2, 1, 8, 7, 0)).count_stack_sorts() == 7 + assert Perm((8, 4, 9, 1, 5, 6, 0, 2, 3, 7)).count_stack_sorts() == 3 + assert Perm((9, 8, 7, 5, 6, 3, 4, 0, 1, 2)).count_stack_sorts() == 2 + assert Perm((2, 3, 7, 8, 10, 11, 0, 1, 4, 5, 6, 9)).count_stack_sorts() == 6 + assert Perm((2, 3, 5, 9, 10, 11, 0, 1, 4, 6, 7, 8)).count_stack_sorts() == 6 + assert Perm((1, 0, 3, 2, 5, 4, 11, 10, 9, 8, 7, 6)).count_stack_sorts() == 1 From 9743bec75f75ca09d928c48ca0b4b9bc66ca56e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigurj=C3=B3n=20Ingi=20J=C3=B3nsson?= <34385890+quintant@users.noreply.github.com> Date: Fri, 4 Jun 2021 11:45:29 +0000 Subject: [PATCH 30/41] Ascents step size (#162) * added step size to ascent and descent * Added docsrting and more tests for asc/desc funcs * Added typing hints to asc/desc in perm.py * Added missing tests * Fixed mypy error and use optional insted of union * wrapper for count_asc/desc in statistics.py * Removed type check, better eamples and ValueError in ascent and descent functions --- permuta/patterns/perm.py | 97 +++++++++++++++++++++++++-------- permuta/permutils/statistics.py | 12 +++- tests/patterns/test_perm.py | 90 ++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 25 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 738ab91..d7f9194 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -746,96 +746,147 @@ def is_sum_decomposable(self) -> bool: sum_decomposable = is_sum_decomposable - def descents(self) -> Iterator[int]: - """Yield the 0-based descents of self. + def descents(self, step_size: Optional[int] = None) -> Iterator[int]: + """Yield the 0-based descents of self. If step size is specified it only yields + descents of that size, otherwise it yields all descents. Examples: >>> tuple(Perm((0, 1, 3, 2, 4)).descents()) (2,) - >>> tuple(Perm((3, 2, 1, 0)).descents()) - (0, 1, 2) + >>> tuple(Perm((0, 1, 3, 2, 4)).descents(step_size=2)) + () + >>> tuple(Perm((3, 1, 0, 2)).descents()) + (0, 1) + >>> tuple(Perm((3, 1, 0, 2)).descents(step_size=2)) + (0,) >>> tuple(Perm((0, 1, 2)).descents()) () """ + + if step_size is None: + return ( + idx + for idx, (prev, curr) in enumerate( + zip(self, itertools.islice(self, 1, None)) + ) + if prev > curr + ) + + if step_size < 1: + raise ValueError("Step size has to be 1 or more") + return ( idx for idx, (prev, curr) in enumerate( zip(self, itertools.islice(self, 1, None)) ) - if prev > curr + if prev == curr + step_size ) - def descent_set(self) -> List[int]: - """Return the list of descents of self. + def descent_set(self, step_size: Optional[int] = None) -> List[int]: + """Return the list of descents of self. If step size is specified it only + returns a list of descents of that size, + otherwise it returns list of all descents. Examples: - >>> Perm((0, 1, 3, 2, 4)).descent_set() + >>> Perm((0, 4, 3, 1, 2)).descent_set() + [1, 2] + >>> Perm((0, 4, 3, 1, 2)).descent_set(step_size=2) [2] >>> Perm((3, 2, 1, 0)).descent_set() [0, 1, 2] >>> Perm((0, 1, 2)).descent_set() [] """ - return list(self.descents()) + return list(self.descents(step_size)) + + def count_descents(self, step_size: Optional[int] = None) -> int: + """Count the number of descents of self. If step size is specified + if only counts descents of that size, otherwise it counts all descents. - def count_descents(self) -> int: - """Count the number of descents of self. Examples: - >>> Perm((0, 1, 3, 2, 4)).count_descents() + >>> Perm((0, 4, 3, 1, 2)).count_descents() + 2 + >>> Perm((0, 4, 3, 1, 2)).count_descents(step_size=2) 1 >>> Perm((3, 2, 1, 0)).count_descents() 3 >>> Perm((0, 1, 2)).count_descents() 0 """ - return sum(1 for _ in self.descents()) + return sum(1 for _ in self.descents(step_size)) num_descents = count_descents - def ascents(self) -> Iterator[int]: - """Yield the 0-based ascent of self. + def ascents(self, step_size: Optional[int] = None) -> Iterator[int]: + """Yield the 0-based ascent of self. If step size is specified it only yields + ascents of that size, otherwise it yields all ascents. Examples: >>> tuple(Perm((0, 1, 3, 2, 4)).ascents()) (0, 1, 3) + >>> tuple(Perm((0, 1, 3, 2, 4)).ascents(step_size=2)) + (1, 3) >>> tuple(Perm((0, 4, 3, 2, 1)).ascents()) (0,) + >>> tuple(Perm((0, 4, 3, 2, 1)).ascents(step_size=1)) + () >>> tuple(Perm((3, 2, 1, 0)).ascents()) () """ + + if step_size is None: + return ( + idx + for idx, (prev, curr) in enumerate( + zip(self, itertools.islice(self, 1, None)) + ) + if prev < curr + ) + + if step_size < 1: + raise ValueError("Step size has to be 1 or more") + return ( idx for idx, (prev, curr) in enumerate( zip(self, itertools.islice(self, 1, None)) ) - if prev < curr + if prev + step_size == curr ) - def ascent_set(self) -> List[int]: - """Return the list of ascents of self. + def ascent_set(self, step_size: Optional[int] = None) -> List[int]: + """Return the list of ascents of self. If step size is specified it only + returns a list of ascents of that size, + otherwise it returns list of all ascents. Examples: >>> Perm((0, 1, 3, 2, 4)).ascent_set() [0, 1, 3] + >>> Perm((0, 1, 3, 2, 4)).ascent_set(step_size=2) + [1, 3] >>> Perm((0, 4, 3, 2, 1)).ascent_set() [0] >>> Perm((3, 2, 1, 0)).ascent_set() [] """ - return list(self.ascents()) + return list(self.ascents(step_size)) - def count_ascents(self) -> int: - """Count the number of ascents in self. + def count_ascents(self, step_size: Optional[int] = None) -> int: + """Count the number of ascents in self. If step size is specified + if only counts ascents of that size, otherwise it counts all ascents. Examples: >>> Perm((0, 1, 3, 2, 4)).count_ascents() 3 + >>> Perm((0, 1, 3, 2, 4)).count_ascents(step_size=2) + 2 >>> Perm((0, 4, 3, 2, 1)).count_ascents() 1 >>> Perm((3, 2, 1, 0)).count_ascents() 0 """ - return sum(1 for _ in self.ascents()) + return sum(1 for _ in self.ascents(step_size)) num_ascents = count_ascents @@ -1140,7 +1191,7 @@ def count_inversions(self) -> int: bit_index += bit_index & -bit_index return bit[0] - def count_bounces(self): + def count_bounces(self) -> int: """The Number of "bounces" in a permutation. See https://www.findstat.org/StatisticsDatabase/St000133/# diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index f7371ec..9d35975 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -8,6 +8,14 @@ BijectionType = Dict[Perm, Perm] +def _count_descents(perm: Perm) -> int: + return perm.count_descents() + + +def _count_ascents(perm: Perm) -> int: + return perm.count_ascents() + + class PermutationStatistic: """ A class for checking preservation of statistics @@ -19,8 +27,8 @@ class PermutationStatistic: ("Number of inversions", Perm.count_inversions), ("Number of non-inversions", Perm.count_non_inversions), ("Major index", Perm.major_index), - ("Number of descents", Perm.count_descents), - ("Number of ascents", Perm.count_ascents), + ("Number of descents", _count_descents), + ("Number of ascents", _count_ascents), ("Number of peaks", Perm.count_peaks), ("Number of valleys", Perm.count_valleys), ("Number of cycles", Perm.count_cycles), diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 1c9649b..d6a1430 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -1164,38 +1164,128 @@ def test_sum_decomposition(): def test_descent_set(): assert Perm().descent_set() == [] + assert Perm().descent_set(step_size=2) == [] + assert Perm((0, 1, 2, 3)).descent_set() == [] + assert Perm((0, 1, 2, 3)).descent_set(step_size=2) == [] + assert Perm((3, 2, 1, 0)).descent_set() == [0, 1, 2] + assert Perm((3, 2, 1, 0)).descent_set(step_size=1) == [0, 1, 2] + assert Perm((3, 2, 1, 0)).descent_set(step_size=2) == [] + assert Perm((2, 1, 0, 4, 3, 5)).descent_set() == [0, 1, 3] + assert Perm((2, 1, 0, 4, 3, 5)).descent_set(step_size=1) == [0, 1, 3] + assert Perm((2, 1, 0, 4, 3, 5)).descent_set(step_size=2) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).descent_set() == [2, 4, 5] + assert Perm((1, 2, 3, 0, 6, 5, 4)).descent_set(step_size=1) == [4, 5] + assert Perm((1, 2, 3, 0, 6, 5, 4)).descent_set(step_size=2) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).descent_set(step_size=3) == [2] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set() == [0, 3, 5, 6] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set(step_size=1) == [5] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set(step_size=2) == [0] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set(step_size=3) == [] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set(step_size=4) == [6] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).descent_set(step_size=5) == [3] def test_count_descents(): assert Perm().count_descents() == 0 + assert Perm().count_descents(step_size=2) == 0 + assert Perm((0, 1, 2, 3)).count_descents() == 0 + assert Perm((0, 1, 2, 3)).count_descents(step_size=2) == 0 + assert Perm((3, 2, 1, 0)).count_descents() == 3 + assert Perm((3, 2, 1, 0)).count_descents(step_size=1) == 3 + assert Perm((3, 2, 1, 0)).count_descents(step_size=2) == 0 + assert Perm((2, 1, 0, 4, 3, 5)).count_descents() == 3 + assert Perm((2, 1, 0, 4, 3, 5)).count_descents(step_size=1) == 3 + assert Perm((2, 1, 0, 4, 3, 5)).count_descents(step_size=2) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_descents() == 3 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_descents(step_size=1) == 2 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_descents(step_size=2) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_descents(step_size=3) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents() == 4 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents(step_size=1) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents(step_size=2) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents(step_size=3) == 0 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents(step_size=4) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_descents(step_size=5) == 1 def test_ascent_set(): assert Perm().ascent_set() == [] + assert Perm().ascent_set(step_size=2) == [] + assert Perm((0, 1, 2, 3)).ascent_set() == [0, 1, 2] + assert Perm((0, 1, 2, 3)).ascent_set(step_size=1) == [0, 1, 2] + assert Perm((0, 1, 2, 3)).ascent_set(step_size=2) == [] + assert Perm((3, 2, 1, 0)).ascent_set() == [] + assert Perm((3, 2, 1, 0)).ascent_set(step_size=2) == [] + assert Perm((2, 1, 0, 4, 3, 5)).ascent_set() == [2, 4] + assert Perm((2, 1, 0, 4, 3, 5)).ascent_set(step_size=1) == [] + assert Perm((2, 1, 0, 4, 3, 5)).ascent_set(step_size=2) == [4] + assert Perm((2, 1, 0, 4, 3, 5)).ascent_set(step_size=3) == [] + assert Perm((2, 1, 0, 4, 3, 5)).ascent_set(step_size=4) == [2] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set() == [0, 1, 3] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=1) == [0, 1] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=2) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=3) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=4) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=5) == [] + assert Perm((1, 2, 3, 0, 6, 5, 4)).ascent_set(step_size=6) == [3] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set() == [1, 2, 4] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=1) == [2] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=2) == [] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=3) == [1] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=4) == [] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=5) == [] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=6) == [] + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).ascent_set(step_size=7) == [4] def test_count_ascents(): assert Perm().count_ascents() == 0 + assert Perm((0, 1, 2, 3)).count_ascents() == 3 + assert Perm((0, 1, 2, 3)).count_ascents(step_size=1) == 3 + assert Perm((0, 1, 2, 3)).count_ascents(step_size=2) == 0 + assert Perm((3, 2, 1, 0)).count_ascents() == 0 + assert Perm((3, 2, 1, 0)).count_ascents(step_size=1) == 0 + assert Perm((3, 2, 1, 0)).count_ascents(step_size=2) == 0 + assert Perm((2, 1, 0, 4, 3, 5)).count_ascents() == 2 + assert Perm((2, 1, 0, 4, 3, 5)).count_ascents(step_size=1) == 0 + assert Perm((2, 1, 0, 4, 3, 5)).count_ascents(step_size=2) == 1 + assert Perm((2, 1, 0, 4, 3, 5)).count_ascents(step_size=3) == 0 + assert Perm((2, 1, 0, 4, 3, 5)).count_ascents(step_size=4) == 1 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents() == 3 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=1) == 2 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=2) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=3) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=4) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=5) == 0 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_ascents(step_size=6) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents() == 3 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=1) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=2) == 0 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=3) == 1 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=4) == 0 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=5) == 0 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=6) == 0 + assert Perm((3, 1, 4, 5, 0, 7, 6, 2)).count_ascents(step_size=7) == 1 def test_peaks(): From e7f2dc669a10a8243c89797420f3219e48239399 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 11:49:18 +0000 Subject: [PATCH 31/41] More descriptive variable name in count_stack_sorts --- permuta/patterns/perm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index cad664f..5d65edc 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1230,13 +1230,13 @@ def count_stack_sorts(self): >>> Perm((2, 1, 0)).count_stack_sorts() 1 """ - i = 0 + num_sorts = 0 identity = list(self.identity(len(self))) perm_list = list(self) while perm_list != identity: perm_list = self._stack_sort(perm_list) - i += 1 - return i + num_sorts += 1 + return num_sorts def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j From 42a6f38c705c2dd36530a362cd55d7bed4f57bf2 Mon Sep 17 00:00:00 2001 From: quintant Date: Fri, 4 Jun 2021 15:13:27 +0000 Subject: [PATCH 32/41] Added pop_stack_sort and count_pop_stack_sorts --- README.rst | 1 + permuta/patterns/perm.py | 47 +++++++++++++++++++++++++++++++ permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 50 +++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/README.rst b/README.rst index de96e84..8c0b085 100644 --- a/README.rst +++ b/README.rst @@ -242,6 +242,7 @@ and a class (no class will use the set of all permutations). [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 >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 26588ba..b16c980 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1289,6 +1289,36 @@ def count_stack_sorts(self): num_sorts += 1 return num_sorts + def count_pop_stack_sorts(self): + """The number of pop-stack-sorts needed to sort a permutation. + See: https://www.findstat.org/StatisticsDatabase/St001090/ + http://www.arxiv.org/abs/1710.04978 + http://www.arxiv.org/abs/1801.05005 + http://www.arxiv.org/abs/1911.03104 + + Examples: + >>> Perm(()).count_pop_stack_sorts() + 0 + >>> Perm((0,)).count_pop_stack_sorts() + 0 + >>> Perm((0, 1)).count_pop_stack_sorts() + 0 + >>> Perm((1, 0)).count_pop_stack_sorts() + 1 + >>> Perm((4, 0, 2, 1, 3, 5)).count_pop_stack_sorts() + 4 + >>> Perm((4, 3, 2, 1, 0, 5)).count_pop_stack_sorts() + 1 + >>> Perm((5, 1, 4, 3, 0, 2)).count_pop_stack_sorts() + 4 + """ + num_sorts = 0 + perm = self + while not perm.is_increasing(): + perm = perm.pop_stack_sort() + num_sorts += 1 + return num_sorts + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). @@ -2226,6 +2256,23 @@ def stack_sortable(self) -> bool: """Returns true if perm is stack sortable.""" return self.stack_sort().is_increasing() + def pop_stack_sort(self) -> "Perm": + """Pop-stack sorting the permutation""" + stack: Deque[int] = collections.deque() + result: List[int] = [] + for num in self: + if stack and num > stack[0]: + result.extend(stack) + stack.clear() + stack.appendleft(num) + + result.extend(stack) + return Perm(result) + + def pop_stack_sortable(self) -> bool: + """Returns true if perm is pop-stack sortable.""" + return self.pop_stack_sort().is_increasing() + @staticmethod def _bubble_sort(perm_slice: List[int]) -> List[int]: """Helper function for the bubble sorting function on perms""" diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index cb4e6b2..88f6576 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -46,6 +46,7 @@ class PermutationStatistic: ("Number of primes in the column sums", Perm.count_column_sum_primes), ("Holeyness of a permutation", Perm.holeyness), ("Number of stack-sorts needed", Perm.count_stack_sorts), + ("Number of pop-stack-sorts needed", Perm.count_pop_stack_sorts), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 2a866b4..8d57479 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2867,3 +2867,53 @@ def test_count_stack_sorts(): assert Perm((2, 3, 7, 8, 10, 11, 0, 1, 4, 5, 6, 9)).count_stack_sorts() == 6 assert Perm((2, 3, 5, 9, 10, 11, 0, 1, 4, 6, 7, 8)).count_stack_sorts() == 6 assert Perm((1, 0, 3, 2, 5, 4, 11, 10, 9, 8, 7, 6)).count_stack_sorts() == 1 + + +def test_count_pop_stack_sorts(): + assert Perm(()).count_pop_stack_sorts() == 0 + assert Perm((0,)).count_pop_stack_sorts() == 0 + assert Perm((0, 1)).count_pop_stack_sorts() == 0 + assert Perm((1, 0)).count_pop_stack_sorts() == 1 + assert Perm((0, 1, 2)).count_pop_stack_sorts() == 0 + assert Perm((0, 2, 1)).count_pop_stack_sorts() == 1 + assert Perm((1, 0, 2)).count_pop_stack_sorts() == 1 + assert Perm((1, 2, 0)).count_pop_stack_sorts() == 2 + assert Perm((2, 0, 1)).count_pop_stack_sorts() == 2 + assert Perm((2, 1, 0)).count_pop_stack_sorts() == 1 + assert Perm((1, 4, 3, 0, 2)).count_pop_stack_sorts() == 3 + assert Perm((0, 1, 3, 2, 4, 5)).count_pop_stack_sorts() == 1 + assert Perm((0, 4, 3, 2, 1, 5)).count_pop_stack_sorts() == 1 + assert Perm((1, 2, 5, 4, 0, 3)).count_pop_stack_sorts() == 3 + assert Perm((2, 0, 3, 1, 4, 5)).count_pop_stack_sorts() == 2 + assert Perm((2, 4, 3, 1, 0, 5)).count_pop_stack_sorts() == 3 + assert Perm((3, 1, 5, 4, 0, 2)).count_pop_stack_sorts() == 4 + assert Perm((4, 0, 2, 1, 3, 5)).count_pop_stack_sorts() == 4 + assert Perm((4, 3, 2, 1, 0, 5)).count_pop_stack_sorts() == 1 + assert Perm((5, 1, 4, 3, 0, 2)).count_pop_stack_sorts() == 4 + assert Perm((0, 1, 2, 4, 3, 5, 6)).count_pop_stack_sorts() == 1 + assert Perm((0, 1, 5, 4, 3, 2, 6)).count_pop_stack_sorts() == 1 + assert Perm((0, 2, 3, 6, 5, 1, 4)).count_pop_stack_sorts() == 3 + assert Perm((0, 3, 1, 4, 2, 5, 6)).count_pop_stack_sorts() == 2 + assert Perm((0, 3, 5, 4, 2, 1, 6)).count_pop_stack_sorts() == 3 + assert Perm((3, 2, 4, 1, 5, 6, 0)).count_pop_stack_sorts() == 6 + assert Perm((7, 6, 5, 4, 3, 2, 1, 0)).count_pop_stack_sorts() == 1 + assert Perm((7, 1, 0, 2, 3, 4, 5, 6)).count_pop_stack_sorts() == 6 + assert Perm((1, 0, 4, 3, 5, 2, 7, 6)).count_pop_stack_sorts() == 3 + assert Perm((2, 0, 3, 1, 5, 7, 4, 6)).count_pop_stack_sorts() == 2 + assert Perm((0, 5, 6, 1, 2, 3, 4, 7)).count_pop_stack_sorts() == 5 + assert Perm((5, 4, 7, 6, 1, 0, 3, 2)).count_pop_stack_sorts() == 6 + assert Perm((0, 5, 1, 4, 2, 6, 3, 7)).count_pop_stack_sorts() == 4 + assert Perm((1, 0, 7, 3, 6, 4, 5, 2)).count_pop_stack_sorts() == 5 + assert Perm((1, 0, 4, 2, 7, 6, 5, 3)).count_pop_stack_sorts() == 2 + assert Perm((2, 1, 4, 0, 6, 3, 7, 5)).count_pop_stack_sorts() == 3 + assert Perm((5, 4, 1, 0, 6, 2, 7, 3)).count_pop_stack_sorts() == 4 + assert Perm((6, 5, 7, 0, 2, 1, 3, 4)).count_pop_stack_sorts() == 7 + assert Perm((4, 3, 6, 0, 7, 2, 1, 5)).count_pop_stack_sorts() == 5 + assert Perm((6, 0, 4, 3, 7, 1, 5, 2)).count_pop_stack_sorts() == 6 + assert Perm((0, 7, 8, 1, 2, 3, 4, 5, 6)).count_pop_stack_sorts() == 7 + assert Perm((9, 6, 5, 4, 3, 2, 1, 8, 7, 0)).count_pop_stack_sorts() == 8 + assert Perm((8, 4, 9, 1, 5, 6, 0, 2, 3, 7)).count_pop_stack_sorts() == 7 + assert Perm((9, 8, 7, 5, 6, 3, 4, 0, 1, 2)).count_pop_stack_sorts() == 9 + assert Perm((2, 3, 7, 8, 10, 11, 0, 1, 4, 5, 6, 9)).count_pop_stack_sorts() == 8 + assert Perm((2, 3, 5, 9, 10, 11, 0, 1, 4, 6, 7, 8)).count_pop_stack_sorts() == 8 + assert Perm((1, 0, 3, 2, 5, 4, 11, 10, 9, 8, 7, 6)).count_pop_stack_sorts() == 1 From c949bfc41ae5f4d9f94987a10f90839238d2cfd3 Mon Sep 17 00:00:00 2001 From: quintant Date: Mon, 7 Jun 2021 10:02:21 +0000 Subject: [PATCH 33/41] Implemented pinnacle set and count pinnacles --- README.rst | 3 +++ permuta/patterns/perm.py | 43 +++++++++++++++++++++++++++++++++ permuta/permutils/statistics.py | 1 + tests/patterns/test_perm.py | 23 ++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/README.rst b/README.rst index 8c0b085..c2860f7 100644 --- a/README.rst +++ b/README.rst @@ -243,6 +243,7 @@ and a class (no class will use the set of all permutations). [20] Holeyness of a permutation [21] Number of stack-sorts needed [22] Number of pop-stack-sorts needed + [23] Number of pinnacles >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] @@ -260,6 +261,7 @@ Given a bijection as a dictionary, we can check which statistics are preserved w 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 @@ -281,6 +283,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 ================== diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index b16c980..349c6d0 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -941,6 +941,49 @@ def count_peaks(self) -> int: return sum(1 for _ in self.peaks()) num_peaks = count_peaks + count_pinnacles = count_peaks + num_pinnacles = count_peaks + + def pinnacles(self) -> Iterator[int]: + """Yield the pinnacles of self. The value of the i-th element of a perm is + a pinnacle if self[i-1] < self[i] > self[i+1]. + See: https://arxiv.org/abs/2105.10388 + https://arxiv.org/abs/1704.05494 + https://arxiv.org/abs/2001.07325 + + Examples: + >>> tuple(Perm((5, 3, 4, 0, 2, 1)).pinnacles()) + (4, 2) + >>> tuple(Perm((1, 2, 0)).pinnacles()) + (2,) + >>> tuple(Perm((2, 1, 0)).pinnacles()) + () + """ + return ( + curr + for (prev, curr, nxt) in zip( + itertools.islice(self, 0, None), + itertools.islice(self, 1, None), + itertools.islice(self, 2, None), + ) + if prev < curr > nxt + ) + + def pinnacle_set(self) -> List[int]: + """Return the pinnacle set of self. + See: https://arxiv.org/abs/2105.10388 + https://arxiv.org/abs/1704.05494 + https://arxiv.org/abs/2001.07325 + + Examples: + >>> Perm((5, 3, 4, 0, 2, 1)).pinnacle_set() + [4, 2] + >>> Perm((1, 2, 0)).pinnacle_set() + [2] + >>> Perm((2, 1, 0)).pinnacle_set() + [] + """ + return list(self.pinnacles()) def count_column_sum_primes(self) -> int: """Returns the number of primes in the column sums of the two line notation diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 88f6576..09871e3 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -47,6 +47,7 @@ class PermutationStatistic: ("Holeyness of a permutation", Perm.holeyness), ("Number of stack-sorts needed", Perm.count_stack_sorts), ("Number of pop-stack-sorts needed", Perm.count_pop_stack_sorts), + ("Number of pinnacles", Perm.count_pinnacles), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 8d57479..6f3a897 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -1311,6 +1311,29 @@ def test_count_peaks(): assert Perm((1, 2, 3, 0, 6, 5, 4)).count_peaks() == 2 +def test_pinnacles(): + assert list(Perm().pinnacles()) == [] + assert list(Perm((0, 1, 2, 3)).pinnacles()) == [] + assert list(Perm((0, 1, 2, 4, 3)).pinnacles()) == [4] + assert list(Perm((2, 1, 0, 4, 3, 5)).pinnacles()) == [4] + assert list(Perm((1, 2, 3, 0, 6, 5, 4)).pinnacles()) == [3, 6] + + +def test_pinnacle_set(): + assert Perm().pinnacle_set() == [] + assert Perm((0, 1, 2, 3)).pinnacle_set() == [] + assert Perm((0, 1, 2, 4, 3)).pinnacle_set() == [4] + assert Perm((2, 1, 0, 4, 3, 5)).pinnacle_set() == [4] + assert Perm((1, 2, 3, 0, 6, 5, 4)).pinnacle_set() == [3, 6] + + +def test_count_pinnacles(): + assert Perm().count_pinnacles() == 0 + assert Perm((0, 1, 2, 3)).count_pinnacles() == 0 + assert Perm((2, 1, 0, 4, 3, 5)).count_pinnacles() == 1 + assert Perm((1, 2, 3, 0, 6, 5, 4)).count_pinnacles() == 2 + + def test_valleys(): assert list(Perm().valleys()) == [] assert list(Perm((0, 1, 2, 3)).valleys()) == [] From 0c5f6f73f0251f2dc067db6e53fc217bc2bd0929 Mon Sep 17 00:00:00 2001 From: quintant Date: Mon, 7 Jun 2021 11:11:57 +0000 Subject: [PATCH 34/41] Update changelog --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a486f4..1b6f156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## Unreleased +### Added + - Statistic: bounce of a permutation. + - Statistic: maximum drop size. + - Statistic: number of primes in the column sums. + - Statistic: holeyness of a permutation. + - Algorith: `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 sortings functions from `permuta/bisc/perm_properties.py` to `permuta/patterns/perm.py`. ## 2.0.3 - 2021-04-28 ### Added From 8d55f20a84811247be978cc420e4414b3d74e2c1 Mon Sep 17 00:00:00 2001 From: quintant Date: Tue, 8 Jun 2021 11:31:19 +0000 Subject: [PATCH 35/41] Various cyclic functions added --- README.rst | 7 + permuta/patterns/perm.py | 358 ++++++++++++++++++++ permuta/permutils/statistics.py | 6 + tests/patterns/test_perm.py | 578 ++++++++++++++++++++++++++++++++ 4 files changed, 949 insertions(+) diff --git a/README.rst b/README.rst index c2860f7..9f67822 100644 --- a/README.rst +++ b/README.rst @@ -244,6 +244,13 @@ and a class (no class will use the set of all permutations). [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 + >>> depth = PermutationStatistic.get_by_index(16) >>> depth.distribution_for_length(5) [1, 4, 12, 24, 35, 24, 20] diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 349c6d0..51efe03 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1362,6 +1362,364 @@ def count_pop_stack_sorts(self): num_sorts += 1 return num_sorts + def cyclic_peaks(self) -> Iterator[int]: + """Yields the indexes of cyclic peaks in the permutation. + Satisfies: i < x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> list(Perm((3, 2, 0, 1)).cyclic_peaks()) + [0, 1] + >>> list(Perm((1, 0, 2)).cyclic_peaks()) + [0] + >>> list(Perm((0, 1, 2)).cyclic_peaks()) + [] + >>> list(Perm((2, 0, 1)).cyclic_peaks()) + [0] + >>> list(Perm((1, 3, 0, 2)).cyclic_peaks()) + [1] + >>> list(Perm((0, 1, 2, 3)).cyclic_peaks()) + [] + >>> list(Perm((0, 2, 1, 3)).cyclic_peaks()) + [1] + """ + for i, x in enumerate(self): + if i < x > self[x]: + yield i + + def cyclic_peaks_list(self) -> List[int]: + """Returns a list of indexes of the cyclic peaks in the permutation. + Satisfies: i < x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 2, 0, 1)).cyclic_peaks_list() + [0, 1] + >>> Perm((1, 0, 2)).cyclic_peaks_list() + [0] + >>> Perm((0, 1, 2)).cyclic_peaks_list() + [] + >>> Perm((2, 0, 1)).cyclic_peaks_list() + [0] + >>> Perm((1, 3, 0, 2)).cyclic_peaks_list() + [1] + >>> Perm((0, 1, 2, 3)).cyclic_peaks_list() + [] + >>> Perm((0, 2, 1, 3)).cyclic_peaks_list() + [1] + """ + return list(self.cyclic_peaks()) + + def count_cyclic_peaks(self) -> int: + """Returns the number of cyclic peaks in the permutation. + Satisfies: i < x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 2, 0, 1)).count_cyclic_peaks() + 2 + >>> Perm((1, 0, 2)).count_cyclic_peaks() + 1 + >>> Perm((0, 1, 2)).count_cyclic_peaks() + 0 + >>> Perm((2, 0, 1)).count_cyclic_peaks() + 1 + >>> Perm((1, 3, 0, 2)).count_cyclic_peaks() + 1 + >>> Perm((0, 1, 2, 3)).count_cyclic_peaks() + 0 + >>> Perm((0, 2, 1, 3)).count_cyclic_peaks() + 1 + """ + return sum(1 for _ in self.cyclic_peaks()) + + def cyclic_valleys(self) -> Iterator[int]: + """Yields the indexes of cyclic valleys in the permutation. + Satisfies: i > x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> list(Perm((1, 3, 0, 2)).cyclic_valleys()) + [2] + >>> list(Perm((2, 1, 0)).cyclic_valleys()) + [2] + >>> list(Perm((1, 2, 3, 0)).cyclic_valleys()) + [3] + >>> list(Perm((1, 2, 0)).cyclic_valleys()) + [2] + >>> list(Perm((2, 0, 1)).cyclic_valleys()) + [1] + >>> list(Perm((0, 1, 2)).cyclic_valleys()) + [] + """ + for i, x in enumerate(self): + if i > x < self[x]: + yield i + + def cyclic_valleys_list(self) -> List[int]: + """Returns a list of index of the cyclic valleys in the permutation. + Satisfies: i > x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((1, 3, 0, 2)).cyclic_valleys_list() + [2] + >>> Perm((2, 1, 0)).cyclic_valleys_list() + [2] + >>> Perm((1, 2, 3, 0)).cyclic_valleys_list() + [3] + >>> Perm((1, 2, 0)).cyclic_valleys_list() + [2] + >>> Perm((2, 0, 1)).cyclic_valleys_list() + [1] + >>> Perm((0, 1, 2)).cyclic_valleys_list() + [] + """ + return list(self.cyclic_valleys()) + + def count_cyclic_valleys(self) -> int: + """Returns the number of cyclic valleys in the permutation. + Satisfies: i > x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((1, 3, 0, 2)).count_cyclic_valleys() + 1 + >>> Perm((2, 1, 0)).count_cyclic_valleys() + 1 + >>> Perm((1, 2, 3, 0)).count_cyclic_valleys() + 1 + >>> Perm((1, 2, 0)).count_cyclic_valleys() + 1 + >>> Perm((2, 0, 1)).count_cyclic_valleys() + 1 + >>> Perm((0, 1, 2)).count_cyclic_valleys() + 0 + """ + return sum(1 for _ in self.cyclic_valleys()) + + def double_excedance(self) -> Iterator[int]: + """Yields the indexes of double excedances in the permutation. + Satisfies: i < x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> list(Perm((1, 0, 3, 2)).double_excedance()) + [] + >>> list(Perm((1, 3, 0, 2)).double_excedance()) + [0] + >>> list(Perm((2, 1, 0)).double_excedance()) + [] + >>> list(Perm((3, 1, 0, 2)).double_excedance()) + [] + >>> list(Perm((1, 2, 3, 0)).double_excedance()) + [0, 1] + >>> list(Perm((2, 0, 3, 1)).double_excedance()) + [0] + """ + for i, x in enumerate(self): + if i < x < self[x]: + yield i + + def double_excedance_list(self) -> List[int]: + """Returns a list of indees of the double excedances in the permutation. + Satisfies: i < x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((1, 0, 3, 2)).double_excedance_list() + [] + >>> Perm((1, 3, 0, 2)).double_excedance_list() + [0] + >>> Perm((2, 1, 0)).double_excedance_list() + [] + >>> Perm((3, 1, 0, 2)).double_excedance_list() + [] + >>> Perm((1, 2, 3, 0)).double_excedance_list() + [0, 1] + >>> Perm((2, 0, 3, 1)).double_excedance_list() + [0] + """ + return list(self.double_excedance()) + + def count_double_excedance(self) -> int: + """Returns the number of double excedances in the permutation. + Satisfies: i < x < P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((1, 0, 3, 2)).count_double_excedance() + 0 + >>> Perm((1, 3, 0, 2)).count_double_excedance() + 1 + >>> Perm((2, 1, 0)).count_double_excedance() + 0 + >>> Perm((3, 1, 0, 2)).count_double_excedance() + 0 + >>> Perm((1, 2, 3, 0)).count_double_excedance() + 2 + >>> Perm((2, 0, 3, 1)).count_double_excedance() + 1 + """ + return sum(1 for _ in self.double_excedance()) + + def double_drops(self) -> Iterator[int]: + """Yields the indexes of double drops in the permutation. + Satisfies: i > x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> list(Perm((2, 0, 1)).double_drops()) + [2] + >>> list(Perm((1, 0, 2)).double_drops()) + [] + >>> list(Perm((2, 1, 3, 0)).double_drops()) + [] + >>> list(Perm((2, 0, 3, 1)).double_drops()) + [3] + >>> list(Perm((3, 0, 1, 2)).double_drops()) + [2, 3] + >>> list(Perm((2, 0, 1, 3)).double_drops()) + [2] + """ + for i, x in enumerate(self): + if i > x > self[x]: + yield i + + def double_drops_list(self) -> List[int]: + """Returns a list of indexes of the double drops in the permutation. + Satisfies: i > x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((2, 0, 1)).double_drops_list() + [2] + >>> Perm((1, 0, 2)).double_drops_list() + [] + >>> Perm((2, 1, 3, 0)).double_drops_list() + [] + >>> Perm((2, 0, 3, 1)).double_drops_list() + [3] + >>> Perm((3, 0, 1, 2)).double_drops_list() + [2, 3] + >>> Perm((2, 0, 1, 3)).double_drops_list() + [2] + """ + return list(self.double_drops()) + + def count_double_drops(self) -> int: + """Counts the number of double drops in the permutation. + Satisfies: i > x > P(x), where x = P(i) + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((2, 0, 1)).count_double_drops() + 1 + >>> Perm((1, 0, 2)).count_double_drops() + 0 + >>> Perm((2, 1, 3, 0)).count_double_drops() + 0 + >>> Perm((2, 0, 3, 1)).count_double_drops() + 1 + >>> Perm((3, 0, 1, 2)).count_double_drops() + 2 + >>> Perm((2, 0, 1, 3)).count_double_drops() + 1 + """ + return sum(1 for _ in self.double_drops()) + + def foremaxima(self) -> List[int]: + """Returns a list of indexes of the foremaxima of the permutation. + If P(i) is both a double ascent and ltrmax it is a foremaximum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 2, 5, 0, 1, 4)).foremaxima() + [] + >>> Perm((3, 4, 1, 0, 5, 2)).foremaxima() + [] + >>> Perm((1, 3, 5, 2, 4, 0)).foremaxima() + [0, 1] + >>> Perm((2, 3, 5, 4, 1, 6, 0)).foremaxima() + [1] + >>> Perm((1, 3, 2, 5, 4, 0, 6)).foremaxima() + [0] + >>> Perm((2, 5, 4, 1, 3, 0)).foremaxima() + [] + """ + double_ascents = set(self.ascent_set(step_size=2)) + ltrmax = set(self.ltrmax()) + return list(double_ascents & ltrmax) + + def count_foremaxima(self): + """Returns the number of foremaxima in the permutation. + If P(i) is both a double ascent and ltrmax it is a foremaximum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 2, 5, 0, 1, 4)).count_foremaxima() + 0 + >>> Perm((3, 4, 1, 0, 5, 2)).count_foremaxima() + 0 + >>> Perm((1, 3, 5, 2, 4, 0)).count_foremaxima() + 2 + >>> Perm((2, 3, 5, 4, 1, 6, 0)).count_foremaxima() + 1 + >>> Perm((1, 3, 2, 5, 4, 0, 6)).count_foremaxima() + 1 + >>> Perm((2, 5, 4, 1, 3, 0)).count_foremaxima() + 0 + """ + return len(self.foremaxima()) + + def afterminima(self) -> List[int]: + """Returns a list of indexes of the afterminima of the permutation. + If P(i) is both a double ascent and rtlmin it is a afterminimum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 1, 4, 6, 5, 0, 2)).afterminima() + [5] + >>> Perm((2, 1, 0)).afterminima() + [] + >>> Perm((1, 5, 0, 3, 2, 4, 6)).afterminima() + [4, 5] + >>> Perm((2, 0, 1, 3)).afterminima() + [2] + >>> Perm((0, 2, 1, 3, 4)).afterminima() + [0, 2] + >>> Perm((3, 1, 0, 2, 4, 6, 5)).afterminima() + [2, 3, 4] + >>> Perm((3, 4, 0, 2, 1)).afterminima() + [2] + """ + double_ascents = set(self.ascent_set(step_size=2)) + rtlmin = set(self.rtlmin()) + return list(double_ascents & rtlmin) + + def count_afterminima(self): + """Returns the number of afterminima in the permutation. + If P(i) is both a double ascent and rtlmin it is a afterminimum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((3, 1, 4, 6, 5, 0, 2)).count_afterminima() + 1 + >>> Perm((2, 1, 0)).count_afterminima() + 0 + >>> Perm((1, 5, 0, 3, 2, 4, 6)).count_afterminima() + 2 + >>> Perm((2, 0, 1, 3)).count_afterminima() + 1 + >>> Perm((0, 2, 1, 3, 4)).count_afterminima() + 2 + >>> Perm((3, 1, 0, 2, 4, 6, 5)).count_afterminima() + 3 + >>> Perm((3, 4, 0, 2, 1)).count_afterminima() + 1 + """ + return len(self.afterminima()) + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 09871e3..0c23fe8 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -48,6 +48,12 @@ class PermutationStatistic: ("Number of stack-sorts needed", Perm.count_stack_sorts), ("Number of pop-stack-sorts needed", Perm.count_pop_stack_sorts), ("Number of pinnacles", Perm.count_pinnacles), + ("Number of cyclic peaks", Perm.count_cyclic_peaks), + ("Number of cyclic valleys", Perm.count_cyclic_valleys), + ("Number of double excedance", Perm.count_double_excedance), + ("Number of double drops", Perm.count_double_drops), + ("Number of foremaxima", Perm.count_foremaxima), + ("Number of afterminima", Perm.count_afterminima), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 6f3a897..3f995ac 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2940,3 +2940,581 @@ def test_count_pop_stack_sorts(): assert Perm((2, 3, 7, 8, 10, 11, 0, 1, 4, 5, 6, 9)).count_pop_stack_sorts() == 8 assert Perm((2, 3, 5, 9, 10, 11, 0, 1, 4, 6, 7, 8)).count_pop_stack_sorts() == 8 assert Perm((1, 0, 3, 2, 5, 4, 11, 10, 9, 8, 7, 6)).count_pop_stack_sorts() == 1 + + +def test_cyclic_peaks(): + assert list(Perm((0,)).cyclic_peaks()) == [] + assert list(Perm((0, 1)).cyclic_peaks()) == [] + assert list(Perm((1, 0)).cyclic_peaks()) == [0] + assert list(Perm((0, 1, 2)).cyclic_peaks()) == [] + assert list(Perm((0, 2, 1)).cyclic_peaks()) == [1] + assert list(Perm((1, 0, 2)).cyclic_peaks()) == [0] + assert list(Perm((1, 2, 0)).cyclic_peaks()) == [1] + assert list(Perm((2, 0, 1)).cyclic_peaks()) == [0] + assert list(Perm((2, 1, 0)).cyclic_peaks()) == [0] + assert list(Perm((0, 1, 2, 3)).cyclic_peaks()) == [] + assert list(Perm((0, 1, 3, 2)).cyclic_peaks()) == [2] + assert list(Perm((0, 2, 1, 3)).cyclic_peaks()) == [1] + assert list(Perm((0, 2, 3, 1)).cyclic_peaks()) == [2] + assert list(Perm((0, 3, 1, 2)).cyclic_peaks()) == [1] + assert list(Perm((0, 3, 2, 1)).cyclic_peaks()) == [1] + assert list(Perm((1, 0, 2, 3)).cyclic_peaks()) == [0] + assert list(Perm((1, 0, 3, 2)).cyclic_peaks()) == [0, 2] + assert list(Perm((1, 2, 0, 3)).cyclic_peaks()) == [1] + assert list(Perm((1, 2, 3, 0)).cyclic_peaks()) == [2] + assert list(Perm((1, 3, 0, 2)).cyclic_peaks()) == [1] + assert list(Perm((1, 3, 2, 0)).cyclic_peaks()) == [1] + assert list(Perm((2, 0, 1, 3)).cyclic_peaks()) == [0] + assert list(Perm((2, 0, 3, 1)).cyclic_peaks()) == [2] + assert list(Perm((2, 1, 0, 3)).cyclic_peaks()) == [0] + assert list(Perm((2, 1, 3, 0)).cyclic_peaks()) == [2] + assert list(Perm((2, 3, 0, 1)).cyclic_peaks()) == [0, 1] + assert list(Perm((2, 3, 1, 0)).cyclic_peaks()) == [0, 1] + assert list(Perm((3, 0, 1, 2)).cyclic_peaks()) == [0] + assert list(Perm((3, 0, 2, 1)).cyclic_peaks()) == [0] + assert list(Perm((3, 1, 0, 2)).cyclic_peaks()) == [0] + assert list(Perm((3, 1, 2, 0)).cyclic_peaks()) == [0] + assert list(Perm((3, 2, 0, 1)).cyclic_peaks()) == [0, 1] + assert list(Perm((3, 2, 1, 0)).cyclic_peaks()) == [0, 1] + + +def test_cyclic_peaks_list(): + assert Perm((0,)).cyclic_peaks_list() == [] + assert Perm((0, 1)).cyclic_peaks_list() == [] + assert Perm((1, 0)).cyclic_peaks_list() == [0] + assert Perm((0, 1, 2)).cyclic_peaks_list() == [] + assert Perm((0, 2, 1)).cyclic_peaks_list() == [1] + assert Perm((1, 0, 2)).cyclic_peaks_list() == [0] + assert Perm((1, 2, 0)).cyclic_peaks_list() == [1] + assert Perm((2, 0, 1)).cyclic_peaks_list() == [0] + assert Perm((2, 1, 0)).cyclic_peaks_list() == [0] + assert Perm((0, 1, 2, 3)).cyclic_peaks_list() == [] + assert Perm((0, 1, 3, 2)).cyclic_peaks_list() == [2] + assert Perm((0, 2, 1, 3)).cyclic_peaks_list() == [1] + assert Perm((0, 2, 3, 1)).cyclic_peaks_list() == [2] + assert Perm((0, 3, 1, 2)).cyclic_peaks_list() == [1] + assert Perm((0, 3, 2, 1)).cyclic_peaks_list() == [1] + assert Perm((1, 0, 2, 3)).cyclic_peaks_list() == [0] + assert Perm((1, 0, 3, 2)).cyclic_peaks_list() == [0, 2] + assert Perm((1, 2, 0, 3)).cyclic_peaks_list() == [1] + assert Perm((1, 2, 3, 0)).cyclic_peaks_list() == [2] + assert Perm((1, 3, 0, 2)).cyclic_peaks_list() == [1] + assert Perm((1, 3, 2, 0)).cyclic_peaks_list() == [1] + assert Perm((2, 0, 1, 3)).cyclic_peaks_list() == [0] + assert Perm((2, 0, 3, 1)).cyclic_peaks_list() == [2] + assert Perm((2, 1, 0, 3)).cyclic_peaks_list() == [0] + assert Perm((2, 1, 3, 0)).cyclic_peaks_list() == [2] + assert Perm((2, 3, 0, 1)).cyclic_peaks_list() == [0, 1] + assert Perm((2, 3, 1, 0)).cyclic_peaks_list() == [0, 1] + assert Perm((3, 0, 1, 2)).cyclic_peaks_list() == [0] + assert Perm((3, 0, 2, 1)).cyclic_peaks_list() == [0] + assert Perm((3, 1, 0, 2)).cyclic_peaks_list() == [0] + assert Perm((3, 1, 2, 0)).cyclic_peaks_list() == [0] + assert Perm((3, 2, 0, 1)).cyclic_peaks_list() == [0, 1] + assert Perm((3, 2, 1, 0)).cyclic_peaks_list() == [0, 1] + + +def test_count_cyclic_peaks(): + assert Perm((0,)).count_cyclic_peaks() == 0 + assert Perm((0, 1)).count_cyclic_peaks() == 0 + assert Perm((1, 0)).count_cyclic_peaks() == 1 + assert Perm((0, 1, 2)).count_cyclic_peaks() == 0 + assert Perm((0, 2, 1)).count_cyclic_peaks() == 1 + assert Perm((1, 0, 2)).count_cyclic_peaks() == 1 + assert Perm((1, 2, 0)).count_cyclic_peaks() == 1 + assert Perm((2, 0, 1)).count_cyclic_peaks() == 1 + assert Perm((2, 1, 0)).count_cyclic_peaks() == 1 + assert Perm((0, 1, 2, 3)).count_cyclic_peaks() == 0 + assert Perm((0, 1, 3, 2)).count_cyclic_peaks() == 1 + assert Perm((0, 2, 1, 3)).count_cyclic_peaks() == 1 + assert Perm((0, 2, 3, 1)).count_cyclic_peaks() == 1 + assert Perm((0, 3, 1, 2)).count_cyclic_peaks() == 1 + assert Perm((0, 3, 2, 1)).count_cyclic_peaks() == 1 + assert Perm((1, 0, 2, 3)).count_cyclic_peaks() == 1 + assert Perm((1, 0, 3, 2)).count_cyclic_peaks() == 2 + assert Perm((1, 2, 0, 3)).count_cyclic_peaks() == 1 + assert Perm((1, 2, 3, 0)).count_cyclic_peaks() == 1 + assert Perm((1, 3, 0, 2)).count_cyclic_peaks() == 1 + assert Perm((1, 3, 2, 0)).count_cyclic_peaks() == 1 + assert Perm((2, 0, 1, 3)).count_cyclic_peaks() == 1 + assert Perm((2, 0, 3, 1)).count_cyclic_peaks() == 1 + assert Perm((2, 1, 0, 3)).count_cyclic_peaks() == 1 + assert Perm((2, 1, 3, 0)).count_cyclic_peaks() == 1 + assert Perm((2, 3, 0, 1)).count_cyclic_peaks() == 2 + assert Perm((2, 3, 1, 0)).count_cyclic_peaks() == 2 + assert Perm((3, 0, 1, 2)).count_cyclic_peaks() == 1 + assert Perm((3, 0, 2, 1)).count_cyclic_peaks() == 1 + assert Perm((3, 1, 0, 2)).count_cyclic_peaks() == 1 + assert Perm((3, 1, 2, 0)).count_cyclic_peaks() == 1 + assert Perm((3, 2, 0, 1)).count_cyclic_peaks() == 2 + assert Perm((3, 2, 1, 0)).count_cyclic_peaks() == 2 + + +def test_cyclic_valleys(): + assert list(Perm((0,)).cyclic_valleys()) == [] + assert list(Perm((0, 1)).cyclic_valleys()) == [] + assert list(Perm((1, 0)).cyclic_valleys()) == [1] + assert list(Perm((0, 1, 2)).cyclic_valleys()) == [] + assert list(Perm((0, 2, 1)).cyclic_valleys()) == [2] + assert list(Perm((1, 0, 2)).cyclic_valleys()) == [1] + assert list(Perm((1, 2, 0)).cyclic_valleys()) == [2] + assert list(Perm((2, 0, 1)).cyclic_valleys()) == [1] + assert list(Perm((2, 1, 0)).cyclic_valleys()) == [2] + assert list(Perm((0, 1, 2, 3)).cyclic_valleys()) == [] + assert list(Perm((0, 1, 3, 2)).cyclic_valleys()) == [3] + assert list(Perm((0, 2, 1, 3)).cyclic_valleys()) == [2] + assert list(Perm((0, 2, 3, 1)).cyclic_valleys()) == [3] + assert list(Perm((0, 3, 1, 2)).cyclic_valleys()) == [2] + assert list(Perm((0, 3, 2, 1)).cyclic_valleys()) == [3] + assert list(Perm((1, 0, 2, 3)).cyclic_valleys()) == [1] + assert list(Perm((1, 0, 3, 2)).cyclic_valleys()) == [1, 3] + assert list(Perm((1, 2, 0, 3)).cyclic_valleys()) == [2] + assert list(Perm((1, 2, 3, 0)).cyclic_valleys()) == [3] + assert list(Perm((1, 3, 0, 2)).cyclic_valleys()) == [2] + assert list(Perm((1, 3, 2, 0)).cyclic_valleys()) == [3] + assert list(Perm((2, 0, 1, 3)).cyclic_valleys()) == [1] + assert list(Perm((2, 0, 3, 1)).cyclic_valleys()) == [1] + assert list(Perm((2, 1, 0, 3)).cyclic_valleys()) == [2] + assert list(Perm((2, 1, 3, 0)).cyclic_valleys()) == [3] + assert list(Perm((2, 3, 0, 1)).cyclic_valleys()) == [2, 3] + assert list(Perm((2, 3, 1, 0)).cyclic_valleys()) == [2, 3] + assert list(Perm((3, 0, 1, 2)).cyclic_valleys()) == [1] + assert list(Perm((3, 0, 2, 1)).cyclic_valleys()) == [1] + assert list(Perm((3, 1, 0, 2)).cyclic_valleys()) == [2] + assert list(Perm((3, 1, 2, 0)).cyclic_valleys()) == [3] + assert list(Perm((3, 2, 0, 1)).cyclic_valleys()) == [2, 3] + assert list(Perm((3, 2, 1, 0)).cyclic_valleys()) == [2, 3] + + +def test_cyclic_valleys_list(): + assert Perm((0,)).cyclic_valleys_list() == [] + assert Perm((0, 1)).cyclic_valleys_list() == [] + assert Perm((1, 0)).cyclic_valleys_list() == [1] + assert Perm((0, 1, 2)).cyclic_valleys_list() == [] + assert Perm((0, 2, 1)).cyclic_valleys_list() == [2] + assert Perm((1, 0, 2)).cyclic_valleys_list() == [1] + assert Perm((1, 2, 0)).cyclic_valleys_list() == [2] + assert Perm((2, 0, 1)).cyclic_valleys_list() == [1] + assert Perm((2, 1, 0)).cyclic_valleys_list() == [2] + assert Perm((0, 1, 2, 3)).cyclic_valleys_list() == [] + assert Perm((0, 1, 3, 2)).cyclic_valleys_list() == [3] + assert Perm((0, 2, 1, 3)).cyclic_valleys_list() == [2] + assert Perm((0, 2, 3, 1)).cyclic_valleys_list() == [3] + assert Perm((0, 3, 1, 2)).cyclic_valleys_list() == [2] + assert Perm((0, 3, 2, 1)).cyclic_valleys_list() == [3] + assert Perm((1, 0, 2, 3)).cyclic_valleys_list() == [1] + assert Perm((1, 0, 3, 2)).cyclic_valleys_list() == [1, 3] + assert Perm((1, 2, 0, 3)).cyclic_valleys_list() == [2] + assert Perm((1, 2, 3, 0)).cyclic_valleys_list() == [3] + assert Perm((1, 3, 0, 2)).cyclic_valleys_list() == [2] + assert Perm((1, 3, 2, 0)).cyclic_valleys_list() == [3] + assert Perm((2, 0, 1, 3)).cyclic_valleys_list() == [1] + assert Perm((2, 0, 3, 1)).cyclic_valleys_list() == [1] + assert Perm((2, 1, 0, 3)).cyclic_valleys_list() == [2] + assert Perm((2, 1, 3, 0)).cyclic_valleys_list() == [3] + assert Perm((2, 3, 0, 1)).cyclic_valleys_list() == [2, 3] + assert Perm((2, 3, 1, 0)).cyclic_valleys_list() == [2, 3] + assert Perm((3, 0, 1, 2)).cyclic_valleys_list() == [1] + assert Perm((3, 0, 2, 1)).cyclic_valleys_list() == [1] + assert Perm((3, 1, 0, 2)).cyclic_valleys_list() == [2] + assert Perm((3, 1, 2, 0)).cyclic_valleys_list() == [3] + assert Perm((3, 2, 0, 1)).cyclic_valleys_list() == [2, 3] + assert Perm((3, 2, 1, 0)).cyclic_valleys_list() == [2, 3] + + +def test_count_cyclic_valleys(): + assert Perm((0,)).count_cyclic_valleys() == 0 + assert Perm((0, 1)).count_cyclic_valleys() == 0 + assert Perm((1, 0)).count_cyclic_valleys() == 1 + assert Perm((0, 1, 2)).count_cyclic_valleys() == 0 + assert Perm((0, 2, 1)).count_cyclic_valleys() == 1 + assert Perm((1, 0, 2)).count_cyclic_valleys() == 1 + assert Perm((1, 2, 0)).count_cyclic_valleys() == 1 + assert Perm((2, 0, 1)).count_cyclic_valleys() == 1 + assert Perm((2, 1, 0)).count_cyclic_valleys() == 1 + assert Perm((0, 1, 2, 3)).count_cyclic_valleys() == 0 + assert Perm((0, 1, 3, 2)).count_cyclic_valleys() == 1 + assert Perm((0, 2, 1, 3)).count_cyclic_valleys() == 1 + assert Perm((0, 2, 3, 1)).count_cyclic_valleys() == 1 + assert Perm((0, 3, 1, 2)).count_cyclic_valleys() == 1 + assert Perm((0, 3, 2, 1)).count_cyclic_valleys() == 1 + assert Perm((1, 0, 2, 3)).count_cyclic_valleys() == 1 + assert Perm((1, 0, 3, 2)).count_cyclic_valleys() == 2 + assert Perm((1, 2, 0, 3)).count_cyclic_valleys() == 1 + assert Perm((1, 2, 3, 0)).count_cyclic_valleys() == 1 + assert Perm((1, 3, 0, 2)).count_cyclic_valleys() == 1 + assert Perm((1, 3, 2, 0)).count_cyclic_valleys() == 1 + assert Perm((2, 0, 1, 3)).count_cyclic_valleys() == 1 + assert Perm((2, 0, 3, 1)).count_cyclic_valleys() == 1 + assert Perm((2, 1, 0, 3)).count_cyclic_valleys() == 1 + assert Perm((2, 1, 3, 0)).count_cyclic_valleys() == 1 + assert Perm((2, 3, 0, 1)).count_cyclic_valleys() == 2 + assert Perm((2, 3, 1, 0)).count_cyclic_valleys() == 2 + assert Perm((3, 0, 1, 2)).count_cyclic_valleys() == 1 + assert Perm((3, 0, 2, 1)).count_cyclic_valleys() == 1 + assert Perm((3, 1, 0, 2)).count_cyclic_valleys() == 1 + assert Perm((3, 1, 2, 0)).count_cyclic_valleys() == 1 + assert Perm((3, 2, 0, 1)).count_cyclic_valleys() == 2 + assert Perm((3, 2, 1, 0)).count_cyclic_valleys() == 2 + + +def test_double_excedance(): + assert list(Perm((0,)).double_excedance()) == [] + assert list(Perm((0, 1)).double_excedance()) == [] + assert list(Perm((1, 0)).double_excedance()) == [] + assert list(Perm((0, 1, 2)).double_excedance()) == [] + assert list(Perm((0, 2, 1)).double_excedance()) == [] + assert list(Perm((1, 0, 2)).double_excedance()) == [] + assert list(Perm((1, 2, 0)).double_excedance()) == [0] + assert list(Perm((2, 0, 1)).double_excedance()) == [] + assert list(Perm((2, 1, 0)).double_excedance()) == [] + assert list(Perm((0, 1, 2, 3)).double_excedance()) == [] + assert list(Perm((0, 1, 3, 2)).double_excedance()) == [] + assert list(Perm((0, 2, 1, 3)).double_excedance()) == [] + assert list(Perm((0, 2, 3, 1)).double_excedance()) == [1] + assert list(Perm((0, 3, 1, 2)).double_excedance()) == [] + assert list(Perm((0, 3, 2, 1)).double_excedance()) == [] + assert list(Perm((1, 0, 2, 3)).double_excedance()) == [] + assert list(Perm((1, 0, 3, 2)).double_excedance()) == [] + assert list(Perm((1, 2, 0, 3)).double_excedance()) == [0] + assert list(Perm((1, 2, 3, 0)).double_excedance()) == [0, 1] + assert list(Perm((1, 3, 0, 2)).double_excedance()) == [0] + assert list(Perm((1, 3, 2, 0)).double_excedance()) == [0] + assert list(Perm((2, 0, 1, 3)).double_excedance()) == [] + assert list(Perm((2, 0, 3, 1)).double_excedance()) == [0] + assert list(Perm((2, 1, 0, 3)).double_excedance()) == [] + assert list(Perm((2, 1, 3, 0)).double_excedance()) == [0] + assert list(Perm((2, 3, 0, 1)).double_excedance()) == [] + assert list(Perm((2, 3, 1, 0)).double_excedance()) == [] + assert list(Perm((3, 0, 1, 2)).double_excedance()) == [] + assert list(Perm((3, 0, 2, 1)).double_excedance()) == [] + assert list(Perm((3, 1, 0, 2)).double_excedance()) == [] + assert list(Perm((3, 1, 2, 0)).double_excedance()) == [] + assert list(Perm((3, 2, 0, 1)).double_excedance()) == [] + assert list(Perm((3, 2, 1, 0)).double_excedance()) == [] + + +def tets_double_excedance_list(): + assert Perm((0,)).double_excedance_list() == [] + assert Perm((0, 1)).double_excedance_list() == [] + assert Perm((1, 0)).double_excedance_list() == [] + assert Perm((0, 1, 2)).double_excedance_list() == [] + assert Perm((0, 2, 1)).double_excedance_list() == [] + assert Perm((1, 0, 2)).double_excedance_list() == [] + assert Perm((1, 2, 0)).double_excedance_list() == [0] + assert Perm((2, 0, 1)).double_excedance_list() == [] + assert Perm((2, 1, 0)).double_excedance_list() == [] + assert Perm((0, 1, 2, 3)).double_excedance_list() == [] + assert Perm((0, 1, 3, 2)).double_excedance_list() == [] + assert Perm((0, 2, 1, 3)).double_excedance_list() == [] + assert Perm((0, 2, 3, 1)).double_excedance_list() == [1] + assert Perm((0, 3, 1, 2)).double_excedance_list() == [] + assert Perm((0, 3, 2, 1)).double_excedance_list() == [] + assert Perm((1, 0, 2, 3)).double_excedance_list() == [] + assert Perm((1, 0, 3, 2)).double_excedance_list() == [] + assert Perm((1, 2, 0, 3)).double_excedance_list() == [0] + assert Perm((1, 2, 3, 0)).double_excedance_list() == [0, 1] + assert Perm((1, 3, 0, 2)).double_excedance_list() == [0] + assert Perm((1, 3, 2, 0)).double_excedance_list() == [0] + assert Perm((2, 0, 1, 3)).double_excedance_list() == [] + assert Perm((2, 0, 3, 1)).double_excedance_list() == [0] + assert Perm((2, 1, 0, 3)).double_excedance_list() == [] + assert Perm((2, 1, 3, 0)).double_excedance_list() == [0] + assert Perm((2, 3, 0, 1)).double_excedance_list() == [] + assert Perm((2, 3, 1, 0)).double_excedance_list() == [] + assert Perm((3, 0, 1, 2)).double_excedance_list() == [] + assert Perm((3, 0, 2, 1)).double_excedance_list() == [] + assert Perm((3, 1, 0, 2)).double_excedance_list() == [] + assert Perm((3, 1, 2, 0)).double_excedance_list() == [] + assert Perm((3, 2, 0, 1)).double_excedance_list() == [] + assert Perm((3, 2, 1, 0)).double_excedance_list() == [] + + +def test_count_double_excedance(): + assert Perm((0,)).count_double_excedance() == 0 + assert Perm((0, 1)).count_double_excedance() == 0 + assert Perm((1, 0)).count_double_excedance() == 0 + assert Perm((0, 1, 2)).count_double_excedance() == 0 + assert Perm((0, 2, 1)).count_double_excedance() == 0 + assert Perm((1, 0, 2)).count_double_excedance() == 0 + assert Perm((1, 2, 0)).count_double_excedance() == 1 + assert Perm((2, 0, 1)).count_double_excedance() == 0 + assert Perm((2, 1, 0)).count_double_excedance() == 0 + assert Perm((0, 1, 2, 3)).count_double_excedance() == 0 + assert Perm((0, 1, 3, 2)).count_double_excedance() == 0 + assert Perm((0, 2, 1, 3)).count_double_excedance() == 0 + assert Perm((0, 2, 3, 1)).count_double_excedance() == 1 + assert Perm((0, 3, 1, 2)).count_double_excedance() == 0 + assert Perm((0, 3, 2, 1)).count_double_excedance() == 0 + assert Perm((1, 0, 2, 3)).count_double_excedance() == 0 + assert Perm((1, 0, 3, 2)).count_double_excedance() == 0 + assert Perm((1, 2, 0, 3)).count_double_excedance() == 1 + assert Perm((1, 2, 3, 0)).count_double_excedance() == 2 + assert Perm((1, 3, 0, 2)).count_double_excedance() == 1 + assert Perm((1, 3, 2, 0)).count_double_excedance() == 1 + assert Perm((2, 0, 1, 3)).count_double_excedance() == 0 + assert Perm((2, 0, 3, 1)).count_double_excedance() == 1 + assert Perm((2, 1, 0, 3)).count_double_excedance() == 0 + assert Perm((2, 1, 3, 0)).count_double_excedance() == 1 + assert Perm((2, 3, 0, 1)).count_double_excedance() == 0 + assert Perm((2, 3, 1, 0)).count_double_excedance() == 0 + assert Perm((3, 0, 1, 2)).count_double_excedance() == 0 + assert Perm((3, 0, 2, 1)).count_double_excedance() == 0 + assert Perm((3, 1, 0, 2)).count_double_excedance() == 0 + assert Perm((3, 1, 2, 0)).count_double_excedance() == 0 + assert Perm((3, 2, 0, 1)).count_double_excedance() == 0 + assert Perm((3, 2, 1, 0)).count_double_excedance() == 0 + + +def test_double_drops(): + assert list(Perm((0,)).double_drops()) == [] + assert list(Perm((0, 1)).double_drops()) == [] + assert list(Perm((1, 0)).double_drops()) == [] + assert list(Perm((0, 1, 2)).double_drops()) == [] + assert list(Perm((0, 2, 1)).double_drops()) == [] + assert list(Perm((1, 0, 2)).double_drops()) == [] + assert list(Perm((1, 2, 0)).double_drops()) == [] + assert list(Perm((2, 0, 1)).double_drops()) == [2] + assert list(Perm((2, 1, 0)).double_drops()) == [] + assert list(Perm((0, 1, 2, 3)).double_drops()) == [] + assert list(Perm((0, 1, 3, 2)).double_drops()) == [] + assert list(Perm((0, 2, 1, 3)).double_drops()) == [] + assert list(Perm((0, 2, 3, 1)).double_drops()) == [] + assert list(Perm((0, 3, 1, 2)).double_drops()) == [3] + assert list(Perm((0, 3, 2, 1)).double_drops()) == [] + assert list(Perm((1, 0, 2, 3)).double_drops()) == [] + assert list(Perm((1, 0, 3, 2)).double_drops()) == [] + assert list(Perm((1, 2, 0, 3)).double_drops()) == [] + assert list(Perm((1, 2, 3, 0)).double_drops()) == [] + assert list(Perm((1, 3, 0, 2)).double_drops()) == [3] + assert list(Perm((1, 3, 2, 0)).double_drops()) == [] + assert list(Perm((2, 0, 1, 3)).double_drops()) == [2] + assert list(Perm((2, 0, 3, 1)).double_drops()) == [3] + assert list(Perm((2, 1, 0, 3)).double_drops()) == [] + assert list(Perm((2, 1, 3, 0)).double_drops()) == [] + assert list(Perm((2, 3, 0, 1)).double_drops()) == [] + assert list(Perm((2, 3, 1, 0)).double_drops()) == [] + assert list(Perm((3, 0, 1, 2)).double_drops()) == [2, 3] + assert list(Perm((3, 0, 2, 1)).double_drops()) == [3] + assert list(Perm((3, 1, 0, 2)).double_drops()) == [3] + assert list(Perm((3, 1, 2, 0)).double_drops()) == [] + assert list(Perm((3, 2, 0, 1)).double_drops()) == [] + assert list(Perm((3, 2, 1, 0)).double_drops()) == [] + + +def test_double_drops_list(): + assert Perm((0,)).double_drops_list() == [] + assert Perm((0, 1)).double_drops_list() == [] + assert Perm((1, 0)).double_drops_list() == [] + assert Perm((0, 1, 2)).double_drops_list() == [] + assert Perm((0, 2, 1)).double_drops_list() == [] + assert Perm((1, 0, 2)).double_drops_list() == [] + assert Perm((1, 2, 0)).double_drops_list() == [] + assert Perm((2, 0, 1)).double_drops_list() == [2] + assert Perm((2, 1, 0)).double_drops_list() == [] + assert Perm((0, 1, 2, 3)).double_drops_list() == [] + assert Perm((0, 1, 3, 2)).double_drops_list() == [] + assert Perm((0, 2, 1, 3)).double_drops_list() == [] + assert Perm((0, 2, 3, 1)).double_drops_list() == [] + assert Perm((0, 3, 1, 2)).double_drops_list() == [3] + assert Perm((0, 3, 2, 1)).double_drops_list() == [] + assert Perm((1, 0, 2, 3)).double_drops_list() == [] + assert Perm((1, 0, 3, 2)).double_drops_list() == [] + assert Perm((1, 2, 0, 3)).double_drops_list() == [] + assert Perm((1, 2, 3, 0)).double_drops_list() == [] + assert Perm((1, 3, 0, 2)).double_drops_list() == [3] + assert Perm((1, 3, 2, 0)).double_drops_list() == [] + assert Perm((2, 0, 1, 3)).double_drops_list() == [2] + assert Perm((2, 0, 3, 1)).double_drops_list() == [3] + assert Perm((2, 1, 0, 3)).double_drops_list() == [] + assert Perm((2, 1, 3, 0)).double_drops_list() == [] + assert Perm((2, 3, 0, 1)).double_drops_list() == [] + assert Perm((2, 3, 1, 0)).double_drops_list() == [] + assert Perm((3, 0, 1, 2)).double_drops_list() == [2, 3] + assert Perm((3, 0, 2, 1)).double_drops_list() == [3] + assert Perm((3, 1, 0, 2)).double_drops_list() == [3] + assert Perm((3, 1, 2, 0)).double_drops_list() == [] + assert Perm((3, 2, 0, 1)).double_drops_list() == [] + assert Perm((3, 2, 1, 0)).double_drops_list() == [] + + +def test_count_double_drops(): + assert Perm((0,)).count_double_drops() == 0 + assert Perm((0, 1)).count_double_drops() == 0 + assert Perm((1, 0)).count_double_drops() == 0 + assert Perm((0, 1, 2)).count_double_drops() == 0 + assert Perm((0, 2, 1)).count_double_drops() == 0 + assert Perm((1, 0, 2)).count_double_drops() == 0 + assert Perm((1, 2, 0)).count_double_drops() == 0 + assert Perm((2, 0, 1)).count_double_drops() == 1 + assert Perm((2, 1, 0)).count_double_drops() == 0 + assert Perm((0, 1, 2, 3)).count_double_drops() == 0 + assert Perm((0, 1, 3, 2)).count_double_drops() == 0 + assert Perm((0, 2, 1, 3)).count_double_drops() == 0 + assert Perm((0, 2, 3, 1)).count_double_drops() == 0 + assert Perm((0, 3, 1, 2)).count_double_drops() == 1 + assert Perm((0, 3, 2, 1)).count_double_drops() == 0 + assert Perm((1, 0, 2, 3)).count_double_drops() == 0 + assert Perm((1, 0, 3, 2)).count_double_drops() == 0 + assert Perm((1, 2, 0, 3)).count_double_drops() == 0 + assert Perm((1, 2, 3, 0)).count_double_drops() == 0 + assert Perm((1, 3, 0, 2)).count_double_drops() == 1 + assert Perm((1, 3, 2, 0)).count_double_drops() == 0 + assert Perm((2, 0, 1, 3)).count_double_drops() == 1 + assert Perm((2, 0, 3, 1)).count_double_drops() == 1 + assert Perm((2, 1, 0, 3)).count_double_drops() == 0 + assert Perm((2, 1, 3, 0)).count_double_drops() == 0 + assert Perm((2, 3, 0, 1)).count_double_drops() == 0 + assert Perm((2, 3, 1, 0)).count_double_drops() == 0 + assert Perm((3, 0, 1, 2)).count_double_drops() == 2 + assert Perm((3, 0, 2, 1)).count_double_drops() == 1 + assert Perm((3, 1, 0, 2)).count_double_drops() == 1 + assert Perm((3, 1, 2, 0)).count_double_drops() == 0 + assert Perm((3, 2, 0, 1)).count_double_drops() == 0 + assert Perm((3, 2, 1, 0)).count_double_drops() == 0 + + +def test_foremaxima(): + assert Perm((0,)).foremaxima() == [] + assert Perm((0, 1)).foremaxima() == [] + assert Perm((1, 0)).foremaxima() == [] + assert Perm((0, 1, 2)).foremaxima() == [] + assert Perm((0, 2, 1)).foremaxima() == [0] + assert Perm((1, 0, 2)).foremaxima() == [] + assert Perm((1, 2, 0)).foremaxima() == [] + assert Perm((2, 0, 1)).foremaxima() == [] + assert Perm((2, 1, 0)).foremaxima() == [] + assert Perm((0, 1, 2, 3)).foremaxima() == [] + assert Perm((0, 1, 3, 2)).foremaxima() == [1] + assert Perm((0, 2, 1, 3)).foremaxima() == [0] + assert Perm((0, 2, 3, 1)).foremaxima() == [0] + assert Perm((0, 3, 1, 2)).foremaxima() == [] + assert Perm((0, 3, 2, 1)).foremaxima() == [] + assert Perm((1, 0, 2, 3)).foremaxima() == [] + assert Perm((1, 0, 3, 2)).foremaxima() == [] + assert Perm((1, 2, 0, 3)).foremaxima() == [] + assert Perm((1, 2, 3, 0)).foremaxima() == [] + assert Perm((1, 3, 0, 2)).foremaxima() == [0] + assert Perm((1, 3, 2, 0)).foremaxima() == [0] + assert Perm((2, 0, 1, 3)).foremaxima() == [] + assert Perm((2, 0, 3, 1)).foremaxima() == [] + assert Perm((2, 1, 0, 3)).foremaxima() == [] + assert Perm((2, 1, 3, 0)).foremaxima() == [] + assert Perm((2, 3, 0, 1)).foremaxima() == [] + assert Perm((2, 3, 1, 0)).foremaxima() == [] + assert Perm((3, 0, 1, 2)).foremaxima() == [] + assert Perm((3, 0, 2, 1)).foremaxima() == [] + assert Perm((3, 1, 0, 2)).foremaxima() == [] + assert Perm((3, 1, 2, 0)).foremaxima() == [] + assert Perm((3, 2, 0, 1)).foremaxima() == [] + assert Perm((3, 2, 1, 0)).foremaxima() == [] + assert Perm((1, 3, 5, 4, 2, 0)).foremaxima() == [0, 1] + + +def test_count_foremaxima(): + assert Perm((0,)).count_foremaxima() == 0 + assert Perm((0, 1)).count_foremaxima() == 0 + assert Perm((1, 0)).count_foremaxima() == 0 + assert Perm((0, 1, 2)).count_foremaxima() == 0 + assert Perm((0, 2, 1)).count_foremaxima() == 1 + assert Perm((1, 0, 2)).count_foremaxima() == 0 + assert Perm((1, 2, 0)).count_foremaxima() == 0 + assert Perm((2, 0, 1)).count_foremaxima() == 0 + assert Perm((2, 1, 0)).count_foremaxima() == 0 + assert Perm((0, 1, 2, 3)).count_foremaxima() == 0 + assert Perm((0, 1, 3, 2)).count_foremaxima() == 1 + assert Perm((0, 2, 1, 3)).count_foremaxima() == 1 + assert Perm((0, 2, 3, 1)).count_foremaxima() == 1 + assert Perm((0, 3, 1, 2)).count_foremaxima() == 0 + assert Perm((0, 3, 2, 1)).count_foremaxima() == 0 + assert Perm((1, 0, 2, 3)).count_foremaxima() == 0 + assert Perm((1, 0, 3, 2)).count_foremaxima() == 0 + assert Perm((1, 2, 0, 3)).count_foremaxima() == 0 + assert Perm((1, 2, 3, 0)).count_foremaxima() == 0 + assert Perm((1, 3, 0, 2)).count_foremaxima() == 1 + assert Perm((1, 3, 2, 0)).count_foremaxima() == 1 + assert Perm((2, 0, 1, 3)).count_foremaxima() == 0 + assert Perm((2, 0, 3, 1)).count_foremaxima() == 0 + assert Perm((2, 1, 0, 3)).count_foremaxima() == 0 + assert Perm((2, 1, 3, 0)).count_foremaxima() == 0 + assert Perm((2, 3, 0, 1)).count_foremaxima() == 0 + assert Perm((2, 3, 1, 0)).count_foremaxima() == 0 + assert Perm((3, 0, 1, 2)).count_foremaxima() == 0 + assert Perm((3, 0, 2, 1)).count_foremaxima() == 0 + assert Perm((3, 1, 0, 2)).count_foremaxima() == 0 + assert Perm((3, 1, 2, 0)).count_foremaxima() == 0 + assert Perm((3, 2, 0, 1)).count_foremaxima() == 0 + assert Perm((3, 2, 1, 0)).count_foremaxima() == 0 + assert Perm((1, 3, 5, 4, 2, 0)).count_foremaxima() == 2 + + +def test_afterminima(): + assert Perm((0,)).afterminima() == [] + assert Perm((0, 1)).afterminima() == [] + assert Perm((1, 0)).afterminima() == [] + assert Perm((0, 1, 2)).afterminima() == [] + assert Perm((0, 2, 1)).afterminima() == [0] + assert Perm((1, 0, 2)).afterminima() == [1] + assert Perm((1, 2, 0)).afterminima() == [] + assert Perm((2, 0, 1)).afterminima() == [] + assert Perm((2, 1, 0)).afterminima() == [] + assert Perm((0, 1, 2, 3)).afterminima() == [] + assert Perm((0, 1, 3, 2)).afterminima() == [1] + assert Perm((0, 2, 1, 3)).afterminima() == [0, 2] + assert Perm((0, 2, 3, 1)).afterminima() == [0] + assert Perm((0, 3, 1, 2)).afterminima() == [] + assert Perm((0, 3, 2, 1)).afterminima() == [] + assert Perm((1, 0, 2, 3)).afterminima() == [1] + assert Perm((1, 0, 3, 2)).afterminima() == [] + assert Perm((1, 2, 0, 3)).afterminima() == [] + assert Perm((1, 2, 3, 0)).afterminima() == [] + assert Perm((1, 3, 0, 2)).afterminima() == [2] + assert Perm((1, 3, 2, 0)).afterminima() == [] + assert Perm((2, 0, 1, 3)).afterminima() == [2] + assert Perm((2, 0, 3, 1)).afterminima() == [] + assert Perm((2, 1, 0, 3)).afterminima() == [] + assert Perm((2, 1, 3, 0)).afterminima() == [] + assert Perm((2, 3, 0, 1)).afterminima() == [] + assert Perm((2, 3, 1, 0)).afterminima() == [] + assert Perm((3, 0, 1, 2)).afterminima() == [] + assert Perm((3, 0, 2, 1)).afterminima() == [1] + assert Perm((3, 1, 0, 2)).afterminima() == [2] + assert Perm((3, 1, 2, 0)).afterminima() == [] + assert Perm((3, 2, 0, 1)).afterminima() == [] + assert Perm((3, 2, 1, 0)).afterminima() == [] + + +def test_count_afterminima(): + assert Perm((0,)).count_afterminima() == 0 + assert Perm((0, 1)).count_afterminima() == 0 + assert Perm((1, 0)).count_afterminima() == 0 + assert Perm((0, 1, 2)).count_afterminima() == 0 + assert Perm((0, 2, 1)).count_afterminima() == 1 + assert Perm((1, 0, 2)).count_afterminima() == 1 + assert Perm((1, 2, 0)).count_afterminima() == 0 + assert Perm((2, 0, 1)).count_afterminima() == 0 + assert Perm((2, 1, 0)).count_afterminima() == 0 + assert Perm((0, 1, 2, 3)).count_afterminima() == 0 + assert Perm((0, 1, 3, 2)).count_afterminima() == 1 + assert Perm((0, 2, 1, 3)).count_afterminima() == 2 + assert Perm((0, 2, 3, 1)).count_afterminima() == 1 + assert Perm((0, 3, 1, 2)).count_afterminima() == 0 + assert Perm((0, 3, 2, 1)).count_afterminima() == 0 + assert Perm((1, 0, 2, 3)).count_afterminima() == 1 + assert Perm((1, 0, 3, 2)).count_afterminima() == 0 + assert Perm((1, 2, 0, 3)).count_afterminima() == 0 + assert Perm((1, 2, 3, 0)).count_afterminima() == 0 + assert Perm((1, 3, 0, 2)).count_afterminima() == 1 + assert Perm((1, 3, 2, 0)).count_afterminima() == 0 + assert Perm((2, 0, 1, 3)).count_afterminima() == 1 + assert Perm((2, 0, 3, 1)).count_afterminima() == 0 + assert Perm((2, 1, 0, 3)).count_afterminima() == 0 + assert Perm((2, 1, 3, 0)).count_afterminima() == 0 + assert Perm((2, 3, 0, 1)).count_afterminima() == 0 + assert Perm((2, 3, 1, 0)).count_afterminima() == 0 + assert Perm((3, 0, 1, 2)).count_afterminima() == 0 + assert Perm((3, 0, 2, 1)).count_afterminima() == 1 + assert Perm((3, 1, 0, 2)).count_afterminima() == 1 + assert Perm((3, 1, 2, 0)).count_afterminima() == 0 + assert Perm((3, 2, 0, 1)).count_afterminima() == 0 + assert Perm((3, 2, 1, 0)).count_afterminima() == 0 From 220fafc69803bb8c5694df5bf6b6dd4693ab8cf7 Mon Sep 17 00:00:00 2001 From: quintant Date: Tue, 8 Jun 2021 11:39:45 +0000 Subject: [PATCH 36/41] add empy tests to cyclic functions --- tests/patterns/test_perm.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 3f995ac..593ca97 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -2943,6 +2943,7 @@ def test_count_pop_stack_sorts(): def test_cyclic_peaks(): + assert list(Perm(()).cyclic_peaks()) == [] assert list(Perm((0,)).cyclic_peaks()) == [] assert list(Perm((0, 1)).cyclic_peaks()) == [] assert list(Perm((1, 0)).cyclic_peaks()) == [0] @@ -2979,6 +2980,7 @@ def test_cyclic_peaks(): def test_cyclic_peaks_list(): + assert Perm(()).cyclic_peaks_list() == [] assert Perm((0,)).cyclic_peaks_list() == [] assert Perm((0, 1)).cyclic_peaks_list() == [] assert Perm((1, 0)).cyclic_peaks_list() == [0] @@ -3015,6 +3017,7 @@ def test_cyclic_peaks_list(): def test_count_cyclic_peaks(): + assert Perm(()).count_cyclic_peaks() == 0 assert Perm((0,)).count_cyclic_peaks() == 0 assert Perm((0, 1)).count_cyclic_peaks() == 0 assert Perm((1, 0)).count_cyclic_peaks() == 1 @@ -3051,6 +3054,7 @@ def test_count_cyclic_peaks(): def test_cyclic_valleys(): + assert list(Perm(()).cyclic_valleys()) == [] assert list(Perm((0,)).cyclic_valleys()) == [] assert list(Perm((0, 1)).cyclic_valleys()) == [] assert list(Perm((1, 0)).cyclic_valleys()) == [1] @@ -3087,6 +3091,7 @@ def test_cyclic_valleys(): def test_cyclic_valleys_list(): + assert Perm(()).cyclic_valleys_list() == [] assert Perm((0,)).cyclic_valleys_list() == [] assert Perm((0, 1)).cyclic_valleys_list() == [] assert Perm((1, 0)).cyclic_valleys_list() == [1] @@ -3123,6 +3128,7 @@ def test_cyclic_valleys_list(): def test_count_cyclic_valleys(): + assert Perm(()).count_cyclic_valleys() == 0 assert Perm((0,)).count_cyclic_valleys() == 0 assert Perm((0, 1)).count_cyclic_valleys() == 0 assert Perm((1, 0)).count_cyclic_valleys() == 1 @@ -3159,6 +3165,7 @@ def test_count_cyclic_valleys(): def test_double_excedance(): + assert list(Perm(()).double_excedance()) == [] assert list(Perm((0,)).double_excedance()) == [] assert list(Perm((0, 1)).double_excedance()) == [] assert list(Perm((1, 0)).double_excedance()) == [] @@ -3195,6 +3202,7 @@ def test_double_excedance(): def tets_double_excedance_list(): + assert Perm(()).double_excedance_list() == [] assert Perm((0,)).double_excedance_list() == [] assert Perm((0, 1)).double_excedance_list() == [] assert Perm((1, 0)).double_excedance_list() == [] @@ -3231,6 +3239,7 @@ def tets_double_excedance_list(): def test_count_double_excedance(): + assert Perm(()).count_double_excedance() == 0 assert Perm((0,)).count_double_excedance() == 0 assert Perm((0, 1)).count_double_excedance() == 0 assert Perm((1, 0)).count_double_excedance() == 0 @@ -3267,6 +3276,7 @@ def test_count_double_excedance(): def test_double_drops(): + assert list(Perm(()).double_drops()) == [] assert list(Perm((0,)).double_drops()) == [] assert list(Perm((0, 1)).double_drops()) == [] assert list(Perm((1, 0)).double_drops()) == [] @@ -3303,6 +3313,7 @@ def test_double_drops(): def test_double_drops_list(): + assert Perm(()).double_drops_list() == [] assert Perm((0,)).double_drops_list() == [] assert Perm((0, 1)).double_drops_list() == [] assert Perm((1, 0)).double_drops_list() == [] @@ -3339,6 +3350,7 @@ def test_double_drops_list(): def test_count_double_drops(): + assert Perm(()).count_double_drops() == 0 assert Perm((0,)).count_double_drops() == 0 assert Perm((0, 1)).count_double_drops() == 0 assert Perm((1, 0)).count_double_drops() == 0 @@ -3375,6 +3387,7 @@ def test_count_double_drops(): def test_foremaxima(): + assert Perm(()).foremaxima() == [] assert Perm((0,)).foremaxima() == [] assert Perm((0, 1)).foremaxima() == [] assert Perm((1, 0)).foremaxima() == [] @@ -3412,6 +3425,7 @@ def test_foremaxima(): def test_count_foremaxima(): + assert Perm(()).count_foremaxima() == 0 assert Perm((0,)).count_foremaxima() == 0 assert Perm((0, 1)).count_foremaxima() == 0 assert Perm((1, 0)).count_foremaxima() == 0 @@ -3449,6 +3463,7 @@ def test_count_foremaxima(): def test_afterminima(): + assert Perm(()).afterminima() == [] assert Perm((0,)).afterminima() == [] assert Perm((0, 1)).afterminima() == [] assert Perm((1, 0)).afterminima() == [] @@ -3485,6 +3500,7 @@ def test_afterminima(): def test_count_afterminima(): + assert Perm(()).count_afterminima() == 0 assert Perm((0,)).count_afterminima() == 0 assert Perm((0, 1)).count_afterminima() == 0 assert Perm((1, 0)).count_afterminima() == 0 From 5fba2b98eec4773557449e8f72c8e5db8d18cbb3 Mon Sep 17 00:00:00 2001 From: quintant Date: Tue, 8 Jun 2021 12:17:09 +0000 Subject: [PATCH 37/41] Changed variabe names --- permuta/patterns/perm.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index 51efe03..d971d3d 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1383,9 +1383,9 @@ def cyclic_peaks(self) -> Iterator[int]: >>> list(Perm((0, 2, 1, 3)).cyclic_peaks()) [1] """ - for i, x in enumerate(self): - if i < x > self[x]: - yield i + for idx, val in enumerate(self): + if idx < val > self[val]: + yield idx def cyclic_peaks_list(self) -> List[int]: """Returns a list of indexes of the cyclic peaks in the permutation. @@ -1452,9 +1452,9 @@ def cyclic_valleys(self) -> Iterator[int]: >>> list(Perm((0, 1, 2)).cyclic_valleys()) [] """ - for i, x in enumerate(self): - if i > x < self[x]: - yield i + for idx, val in enumerate(self): + if idx > val < self[val]: + yield idx def cyclic_valleys_list(self) -> List[int]: """Returns a list of index of the cyclic valleys in the permutation. @@ -1517,9 +1517,9 @@ def double_excedance(self) -> Iterator[int]: >>> list(Perm((2, 0, 3, 1)).double_excedance()) [0] """ - for i, x in enumerate(self): - if i < x < self[x]: - yield i + for idx, val in enumerate(self): + if idx < val < self[val]: + yield idx def double_excedance_list(self) -> List[int]: """Returns a list of indees of the double excedances in the permutation. @@ -1582,9 +1582,9 @@ def double_drops(self) -> Iterator[int]: >>> list(Perm((2, 0, 1, 3)).double_drops()) [2] """ - for i, x in enumerate(self): - if i > x > self[x]: - yield i + for idx, val in enumerate(self): + if idx > val > self[val]: + yield idx def double_drops_list(self) -> List[int]: """Returns a list of indexes of the double drops in the permutation. From cadf3397fc25837816b564be52e153edf1215ac0 Mon Sep 17 00:00:00 2001 From: quintant Date: Tue, 8 Jun 2021 15:12:12 +0000 Subject: [PATCH 38/41] Added aftermaxima and foreminima --- README.rst | 2 + permuta/patterns/perm.py | 96 +++++++++++++++++++++ permuta/permutils/statistics.py | 2 + tests/patterns/test_perm.py | 148 ++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+) diff --git a/README.rst b/README.rst index 9f67822..1c5d3ec 100644 --- a/README.rst +++ b/README.rst @@ -250,6 +250,8 @@ and a class (no class will use the set of all permutations). [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) diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index d971d3d..a2c29cb 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -1720,6 +1720,102 @@ def count_afterminima(self): """ return len(self.afterminima()) + def aftermaxima(self): + """Returns a list of indexes of the aftermaxima of the permutation. + If P(i) is both a double descent and rtlmax it is an aftermaximum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((4, 1, 2, 5, 3, 0, 6)).aftermaxima() + [] + >>> Perm((5, 4, 3, 1, 2, 0)).aftermaxima() + [2, 4] + >>> Perm((1, 2, 0)).aftermaxima() + [1] + >>> Perm((2, 4, 0, 3, 1)).aftermaxima() + [3] + >>> Perm((1, 3, 2, 0)).aftermaxima() + [2] + >>> Perm((2, 0, 1)).aftermaxima() + [0] + >>> Perm((1, 4, 2, 0, 3)).aftermaxima() + [1] + """ + double_descents = set(self.descents(step_size=2)) + rtlmax = set(self.rtlmax()) + return list(double_descents & rtlmax) + + def count_aftermaxima(self): + """Returns the number of aftermaxima in the permutation. + If P(i) is both a double descent and rtlmax it is an afermaximum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((4, 1, 2, 5, 3, 0, 6)).count_aftermaxima() + 0 + >>> Perm((5, 4, 3, 1, 2, 0)).count_aftermaxima() + 2 + >>> Perm((1, 2, 0)).count_aftermaxima() + 1 + >>> Perm((2, 4, 0, 3, 1)).count_aftermaxima() + 1 + >>> Perm((1, 3, 2, 0)).count_aftermaxima() + 1 + >>> Perm((2, 0, 1)).count_aftermaxima() + 1 + >>> Perm((1, 4, 2, 0, 3)).count_aftermaxima() + 1 + """ + return len(self.aftermaxima()) + + def foreminima(self): + """Returns a list of indexes of the foreminima of the permutation. + If P(i) is both a double descent and ltrmin it is a foreminimum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((5, 6, 0, 1, 3, 4, 2)).foreminima() + [] + >>> Perm((3, 1, 4, 0, 2)).foreminima() + [0] + >>> Perm((3, 1, 2, 5, 4, 0)).foreminima() + [0] + >>> Perm((3, 1, 4, 2, 0)).foreminima() + [0] + >>> Perm((3, 1, 0, 5, 4, 2)).foreminima() + [0] + >>> Perm((2, 0, 1)).foreminima() + [0] + >>> Perm((6, 4, 2, 3, 5, 1, 0)).foreminima() + [0, 1] + """ + double_descents = set(self.descents(step_size=2)) + ltrmin = set(self.ltrmin()) + return list(double_descents & ltrmin) + + def count_foreminima(self): + """Returns the number of foreminima in the permutation. + If P(i) is both a double descent and ltrmin it is a foreminimum. + See: https://arxiv.org/abs/1908.01084 + + Examples: + >>> Perm((5, 6, 0, 1, 3, 4, 2)).count_foreminima() + 0 + >>> Perm((3, 1, 4, 0, 2)).count_foreminima() + 1 + >>> Perm((3, 1, 2, 5, 4, 0)).count_foreminima() + 1 + >>> Perm((3, 1, 4, 2, 0)).count_foreminima() + 1 + >>> Perm((3, 1, 0, 5, 4, 2)).count_foreminima() + 1 + >>> Perm((2, 0, 1)).count_foreminima() + 1 + >>> Perm((6, 4, 2, 3, 5, 1, 0)).count_foreminima() + 2 + """ + return len(self.foreminima()) + def inversions(self) -> Iterator[Tuple[int, int]]: """Yield the inversions of the permutation, i.e., the pairs i,j such that i < j and self(i) > self(j). diff --git a/permuta/permutils/statistics.py b/permuta/permutils/statistics.py index 0c23fe8..47657ea 100644 --- a/permuta/permutils/statistics.py +++ b/permuta/permutils/statistics.py @@ -54,6 +54,8 @@ class PermutationStatistic: ("Number of double drops", Perm.count_double_drops), ("Number of foremaxima", Perm.count_foremaxima), ("Number of afterminima", Perm.count_afterminima), + ("Number of aftermaxima", Perm.count_aftermaxima), + ("Number of foreminima", Perm.count_foreminima), ) @staticmethod diff --git a/tests/patterns/test_perm.py b/tests/patterns/test_perm.py index 593ca97..f070df4 100644 --- a/tests/patterns/test_perm.py +++ b/tests/patterns/test_perm.py @@ -3534,3 +3534,151 @@ def test_count_afterminima(): assert Perm((3, 1, 2, 0)).count_afterminima() == 0 assert Perm((3, 2, 0, 1)).count_afterminima() == 0 assert Perm((3, 2, 1, 0)).count_afterminima() == 0 + + +def test_aftermaxima(): + assert Perm(()).aftermaxima() == [] + assert Perm((0,)).aftermaxima() == [] + assert Perm((0, 1)).aftermaxima() == [] + assert Perm((1, 0)).aftermaxima() == [] + assert Perm((0, 1, 2)).aftermaxima() == [] + assert Perm((0, 2, 1)).aftermaxima() == [] + assert Perm((1, 0, 2)).aftermaxima() == [] + assert Perm((1, 2, 0)).aftermaxima() == [1] + assert Perm((2, 0, 1)).aftermaxima() == [0] + assert Perm((2, 1, 0)).aftermaxima() == [] + assert Perm((0, 1, 2, 3)).aftermaxima() == [] + assert Perm((0, 1, 3, 2)).aftermaxima() == [] + assert Perm((0, 2, 1, 3)).aftermaxima() == [] + assert Perm((0, 2, 3, 1)).aftermaxima() == [2] + assert Perm((0, 3, 1, 2)).aftermaxima() == [1] + assert Perm((0, 3, 2, 1)).aftermaxima() == [] + assert Perm((1, 0, 2, 3)).aftermaxima() == [] + assert Perm((1, 0, 3, 2)).aftermaxima() == [] + assert Perm((1, 2, 0, 3)).aftermaxima() == [] + assert Perm((1, 2, 3, 0)).aftermaxima() == [] + assert Perm((1, 3, 0, 2)).aftermaxima() == [] + assert Perm((1, 3, 2, 0)).aftermaxima() == [2] + assert Perm((2, 0, 1, 3)).aftermaxima() == [] + assert Perm((2, 0, 3, 1)).aftermaxima() == [2] + assert Perm((2, 1, 0, 3)).aftermaxima() == [] + assert Perm((2, 1, 3, 0)).aftermaxima() == [] + assert Perm((2, 3, 0, 1)).aftermaxima() == [] + assert Perm((2, 3, 1, 0)).aftermaxima() == [1] + assert Perm((3, 0, 1, 2)).aftermaxima() == [] + assert Perm((3, 0, 2, 1)).aftermaxima() == [] + assert Perm((3, 1, 0, 2)).aftermaxima() == [0] + assert Perm((3, 1, 2, 0)).aftermaxima() == [0, 2] + assert Perm((3, 2, 0, 1)).aftermaxima() == [1] + assert Perm((3, 2, 1, 0)).aftermaxima() == [] + + +def test_count_aftermaxima(): + assert Perm(()).count_aftermaxima() == 0 + assert Perm((0,)).count_aftermaxima() == 0 + assert Perm((0, 1)).count_aftermaxima() == 0 + assert Perm((1, 0)).count_aftermaxima() == 0 + assert Perm((0, 1, 2)).count_aftermaxima() == 0 + assert Perm((0, 2, 1)).count_aftermaxima() == 0 + assert Perm((1, 0, 2)).count_aftermaxima() == 0 + assert Perm((1, 2, 0)).count_aftermaxima() == 1 + assert Perm((2, 0, 1)).count_aftermaxima() == 1 + assert Perm((2, 1, 0)).count_aftermaxima() == 0 + assert Perm((0, 1, 2, 3)).count_aftermaxima() == 0 + assert Perm((0, 1, 3, 2)).count_aftermaxima() == 0 + assert Perm((0, 2, 1, 3)).count_aftermaxima() == 0 + assert Perm((0, 2, 3, 1)).count_aftermaxima() == 1 + assert Perm((0, 3, 1, 2)).count_aftermaxima() == 1 + assert Perm((0, 3, 2, 1)).count_aftermaxima() == 0 + assert Perm((1, 0, 2, 3)).count_aftermaxima() == 0 + assert Perm((1, 0, 3, 2)).count_aftermaxima() == 0 + assert Perm((1, 2, 0, 3)).count_aftermaxima() == 0 + assert Perm((1, 2, 3, 0)).count_aftermaxima() == 0 + assert Perm((1, 3, 0, 2)).count_aftermaxima() == 0 + assert Perm((1, 3, 2, 0)).count_aftermaxima() == 1 + assert Perm((2, 0, 1, 3)).count_aftermaxima() == 0 + assert Perm((2, 0, 3, 1)).count_aftermaxima() == 1 + assert Perm((2, 1, 0, 3)).count_aftermaxima() == 0 + assert Perm((2, 1, 3, 0)).count_aftermaxima() == 0 + assert Perm((2, 3, 0, 1)).count_aftermaxima() == 0 + assert Perm((2, 3, 1, 0)).count_aftermaxima() == 1 + assert Perm((3, 0, 1, 2)).count_aftermaxima() == 0 + assert Perm((3, 0, 2, 1)).count_aftermaxima() == 0 + assert Perm((3, 1, 0, 2)).count_aftermaxima() == 1 + assert Perm((3, 1, 2, 0)).count_aftermaxima() == 2 + assert Perm((3, 2, 0, 1)).count_aftermaxima() == 1 + assert Perm((3, 2, 1, 0)).count_aftermaxima() == 0 + + +def test_foreminima(): + assert Perm(()).foreminima() == [] + assert Perm((0,)).foreminima() == [] + assert Perm((0, 1)).foreminima() == [] + assert Perm((1, 0)).foreminima() == [] + assert Perm((0, 1, 2)).foreminima() == [] + assert Perm((0, 2, 1)).foreminima() == [] + assert Perm((1, 0, 2)).foreminima() == [] + assert Perm((1, 2, 0)).foreminima() == [] + assert Perm((2, 0, 1)).foreminima() == [0] + assert Perm((2, 1, 0)).foreminima() == [] + assert Perm((0, 1, 2, 3)).foreminima() == [] + assert Perm((0, 1, 3, 2)).foreminima() == [] + assert Perm((0, 2, 1, 3)).foreminima() == [] + assert Perm((0, 2, 3, 1)).foreminima() == [] + assert Perm((0, 3, 1, 2)).foreminima() == [] + assert Perm((0, 3, 2, 1)).foreminima() == [] + assert Perm((1, 0, 2, 3)).foreminima() == [] + assert Perm((1, 0, 3, 2)).foreminima() == [] + assert Perm((1, 2, 0, 3)).foreminima() == [] + assert Perm((1, 2, 3, 0)).foreminima() == [] + assert Perm((1, 3, 0, 2)).foreminima() == [] + assert Perm((1, 3, 2, 0)).foreminima() == [] + assert Perm((2, 0, 1, 3)).foreminima() == [0] + assert Perm((2, 0, 3, 1)).foreminima() == [0] + assert Perm((2, 1, 0, 3)).foreminima() == [] + assert Perm((2, 1, 3, 0)).foreminima() == [] + assert Perm((2, 3, 0, 1)).foreminima() == [] + assert Perm((2, 3, 1, 0)).foreminima() == [] + assert Perm((3, 0, 1, 2)).foreminima() == [] + assert Perm((3, 0, 2, 1)).foreminima() == [] + assert Perm((3, 1, 0, 2)).foreminima() == [0] + assert Perm((3, 1, 2, 0)).foreminima() == [0] + assert Perm((3, 2, 0, 1)).foreminima() == [1] + assert Perm((3, 2, 1, 0)).foreminima() == [] + + +def test_count_foreminima(): + assert Perm(()).count_foreminima() == 0 + assert Perm((0,)).count_foreminima() == 0 + assert Perm((0, 1)).count_foreminima() == 0 + assert Perm((1, 0)).count_foreminima() == 0 + assert Perm((0, 1, 2)).count_foreminima() == 0 + assert Perm((0, 2, 1)).count_foreminima() == 0 + assert Perm((1, 0, 2)).count_foreminima() == 0 + assert Perm((1, 2, 0)).count_foreminima() == 0 + assert Perm((2, 0, 1)).count_foreminima() == 1 + assert Perm((2, 1, 0)).count_foreminima() == 0 + assert Perm((0, 1, 2, 3)).count_foreminima() == 0 + assert Perm((0, 1, 3, 2)).count_foreminima() == 0 + assert Perm((0, 2, 1, 3)).count_foreminima() == 0 + assert Perm((0, 2, 3, 1)).count_foreminima() == 0 + assert Perm((0, 3, 1, 2)).count_foreminima() == 0 + assert Perm((0, 3, 2, 1)).count_foreminima() == 0 + assert Perm((1, 0, 2, 3)).count_foreminima() == 0 + assert Perm((1, 0, 3, 2)).count_foreminima() == 0 + assert Perm((1, 2, 0, 3)).count_foreminima() == 0 + assert Perm((1, 2, 3, 0)).count_foreminima() == 0 + assert Perm((1, 3, 0, 2)).count_foreminima() == 0 + assert Perm((1, 3, 2, 0)).count_foreminima() == 0 + assert Perm((2, 0, 1, 3)).count_foreminima() == 1 + assert Perm((2, 0, 3, 1)).count_foreminima() == 1 + assert Perm((2, 1, 0, 3)).count_foreminima() == 0 + assert Perm((2, 1, 3, 0)).count_foreminima() == 0 + assert Perm((2, 3, 0, 1)).count_foreminima() == 0 + assert Perm((2, 3, 1, 0)).count_foreminima() == 0 + assert Perm((3, 0, 1, 2)).count_foreminima() == 0 + assert Perm((3, 0, 2, 1)).count_foreminima() == 0 + assert Perm((3, 1, 0, 2)).count_foreminima() == 1 + assert Perm((3, 1, 2, 0)).count_foreminima() == 1 + assert Perm((3, 2, 0, 1)).count_foreminima() == 1 + assert Perm((3, 2, 1, 0)).count_foreminima() == 0 From c38ad5e7ffeb72d3d25f1c8ea315548311bf3380 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Mon, 14 Jun 2021 12:57:55 +0000 Subject: [PATCH 39/41] add sigurjon as author (#173) --- .zenodo.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.zenodo.json b/.zenodo.json index 8240aa5..e4ec461 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -41,6 +41,10 @@ }, { "name": "Arnar Bjarni Arnarson" + }, + { + "affiliation": "Reykjavik University", + "mame": "Sigurjón Ingi Jónsson" } ] } \ No newline at end of file From 3196bdfb17f432b606c953b01a75830b3943ea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20Nadeau?= Date: Mon, 14 Jun 2021 09:18:44 -0400 Subject: [PATCH 40/41] [requires.io] dependency update on develop branch (#156) * [requires.io] dependency update * [requires.io] dependency update * [requires.io] dependency update * [requires.io] dependency update * [requires.io] dependency update * [requires.io] dependency update * [requires.io] dependency update * fix stuff * fix pylint * fix zenodo Co-authored-by: requires.io --- .pre-commit-config.yaml | 2 +- .zenodo.json | 4 ++-- permuta/patterns/perm.py | 4 ++-- tox.ini | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 743c5db..7677eaf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: - repo: https://github.com/psf/black - rev: 20.8b0 + rev: 21.6b0 hooks: - id: black diff --git a/.zenodo.json b/.zenodo.json index e4ec461..1855456 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -44,7 +44,7 @@ }, { "affiliation": "Reykjavik University", - "mame": "Sigurjón Ingi Jónsson" + "name": "Sigurjón Ingi Jónsson" } ] -} \ No newline at end of file +} diff --git a/permuta/patterns/perm.py b/permuta/patterns/perm.py index a2c29cb..9ea0c1e 100644 --- a/permuta/patterns/perm.py +++ b/permuta/patterns/perm.py @@ -2430,7 +2430,7 @@ def is_strongly_simple(self) -> bool: >>> Perm((4, 1, 6, 3, 0, 7, 2, 5)).is_strongly_simple() True """ - return self.is_simple() and all([patt.is_simple() for patt in self.children()]) + return self.is_simple() and all(patt.is_simple() for patt in self.children()) def children(self) -> List["Perm"]: """Returns all patterns of length one less than the permutation. One @@ -3012,7 +3012,7 @@ def __mul__(self, other: object) -> "Perm": return self.compose(other) def __repr__(self) -> "str": - return f"Perm({super(Perm, self).__repr__()})" + return f"Perm({super().__repr__()})" def __str__(self) -> "str": if not self: diff --git a/tox.ini b/tox.ini index 47b0fff..e6d8992 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ [tox] envlist = flake8, mypy, pylint, black - py{,37,38,39}, + py{37,38,39}, pypy37 [default] @@ -20,7 +20,7 @@ basepython = py39: python3.9 pypy37: pypy3 deps = - pytest==6.2.3 + pytest==6.2.4 pytest-timeout==1.4.2 commands = pytest @@ -34,7 +34,7 @@ description = run flake8 (linter) basepython = {[default]basepython} skip_install = True deps = - flake8==3.9.1 + flake8==3.9.2 flake8-isort==4.0.0 commands = flake8 --isort-show-traceback permuta tests setup.py @@ -43,19 +43,19 @@ commands = description = run pylint (static code analysis) basepython = {[default]basepython} deps = - pylint==2.5.3 + pylint==2.8.3 commands = pylint permuta [testenv:mypy] description = run mypy (static type checker) basepython = {[default]basepython} deps = - mypy==0.782 + mypy==0.902 commands = mypy [testenv:black] description = check that comply with autoformating basepython = {[default]basepython} deps = - black==21.4b1 + black==21.6b0 commands = black --check --diff . From c43e5e1afdc7457e23655579dbe7fd1bec72af17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20Nadeau?= Date: Mon, 14 Jun 2021 09:35:45 -0400 Subject: [PATCH 41/41] version 2.1.0 (#174) --- CHANGELOG.md | 6 ++++-- permuta/__init__.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6f156..660b846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## 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. - - Algorith: `pop stack sort`. + - 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 sortings functions from `permuta/bisc/perm_properties.py` to `permuta/patterns/perm.py`. + - Moved sorting functions from `permuta/bisc/perm_properties.py` to `permuta/patterns/perm.py`. ## 2.0.3 - 2021-04-28 ### Added diff --git a/permuta/__init__.py b/permuta/__init__.py index b0e3740..09decb3 100644 --- a/permuta/__init__.py +++ b/permuta/__init__.py @@ -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",