diff --git a/engine/maths/CMakeLists.txt b/engine/maths/CMakeLists.txt index cc504cd4ab..16e3f707f1 100644 --- a/engine/maths/CMakeLists.txt +++ b/engine/maths/CMakeLists.txt @@ -1,6 +1,7 @@ # maths ADD_SUBDIRECTORY("spec") +ADD_SUBDIRECTORY("detail") # Files to compile SET ( FILES diff --git a/engine/maths/detail/CMakeLists.txt b/engine/maths/detail/CMakeLists.txt new file mode 100644 index 0000000000..39d7a209a0 --- /dev/null +++ b/engine/maths/detail/CMakeLists.txt @@ -0,0 +1,8 @@ +# maths/detail + +if (${REGINA_INSTALL_DEV}) + INSTALL( FILES + permContractFront.h + DESTINATION "${INCLUDEDIR}/maths/detail" COMPONENT Development) +endif (${REGINA_INSTALL_DEV}) + diff --git a/engine/maths/detail/permContractFront.h b/engine/maths/detail/permContractFront.h new file mode 100644 index 0000000000..ff4a9d28bf --- /dev/null +++ b/engine/maths/detail/permContractFront.h @@ -0,0 +1,157 @@ + +/************************************************************************** + * * + * Regina - A Normal Surface Theory Calculator * + * Computational Engine * + * * + * Copyright (c) 1999-2023, Ben Burton * + * For further details contact Ben Burton (bab@debian.org). * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * As an exception, when this program is distributed through (i) the * + * App Store by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or * + * (iii) Google Play by Google Inc., then that store may impose any * + * digital rights management, device limits and/or redistribution * + * restrictions that are required by its terms of service. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * You should have received a copy of the GNU General Public * + * License along with this program; if not, write to the Free * + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + **************************************************************************/ + +#ifndef __REGINA_PERM_CONTRACT_FRONT_H +#ifndef __DOXYGEN +#define __REGINA_PERM_CONTRACT_FRONT_H +#endif + +/*! \file maths/detail/permContractFront.h + * \brief Implements Perm::contractFront. + */ + +namespace regina { + +namespace detail { + +/** + * A helper template to implement Perm::contractFront(Perm). + */ +template::codeType, + PermCodeType kPermCodeType = Perm::codeType> +struct PermContractFront; + +/* + * Generic implementation using the Perm(p[0], ..., p[n-1]) + * contructor which is only available when Perm encoding + * is PERM_CODE_INDEX. + */ +template +struct PermContractFront +{ + static_assert(n < k); + + Perm operator() (Perm p) { + return helper(p, std::make_integer_sequence()); + } + +private: + template + Perm helper(Perm p, std::integer_sequence) + { + constexpr int s = k - n; + return Perm(p[s + i] - s...); + } +}; + +/* + * Generic implementation where Perm is constructed using the + * bit-coded images, so internal encoding must be PERM_CODE_IMAGES. + */ +template +struct PermContractFront +{ + static_assert(n < k); + + Perm operator() (Perm p) { + constexpr int s = k - n; + + using Code = typename Perm::Code; + + Code c = 0; + for (int i = 0, bits = 0; i < n; ++i, bits += Perm::imageBits) + c |= static_cast(p[s + i] - s) << bits; + + return Perm::fromPermCode(c); + } +}; + +template +struct PermContractFront +{ + Perm operator() (Perm p) { + using Code = typename Perm::Code2; + return Perm::fromPermCode2(static_cast(p.permCode2())); + } +}; + +template +struct PermContractFront<2, k, PERM_CODE_INDEX, kPermCodeType> +{ + static_assert(2 < k); + + Perm<2> operator() (Perm p) { + using Code = typename Perm<2>::Code; + return Perm<2>::fromPermCode(static_cast( + p[k-1] == k - 1 ? 0 : 1)); + } +}; + +template<> +struct PermContractFront<2, 3, PERM_CODE_INDEX, PERM_CODE_INDEX> +{ + Perm<2> operator() (Perm<3> p) { + using Code = typename Perm<2>::Code; + return Perm<2>::fromPermCode(static_cast( + p.permCode() == 0 ? 0 : 1)); + } +}; + +template<> +struct PermContractFront<2, 4, PERM_CODE_INDEX, PERM_CODE_INDEX> +{ + Perm<2> operator() (Perm<4> p) { + const Perm<4>::Code2 c = p.permCode2(); + return Perm<2>::fromPermCode(static_cast::Code>( + c == 1 || c == 6 ? 1 : 0)); + } +}; + +template<> +struct PermContractFront<2, 5, PERM_CODE_INDEX, PERM_CODE_INDEX> +{ + Perm<2> operator() (Perm<5> p) { + const Perm<5>::Code2 c = p.permCode2(); + return Perm<2>::fromPermCode( + static_cast::Code>( + c == 1 || c == 6 || c == 24 || c == 31 || c == 49 || c == 54 + ? 1 : 0)); + } +}; + +} + +} + +#endif diff --git a/engine/maths/perm.h b/engine/maths/perm.h index 4d73ca488f..6977077284 100644 --- a/engine/maths/perm.h +++ b/engine/maths/perm.h @@ -1273,6 +1273,32 @@ class Perm { template static constexpr Perm contract(Perm p); + /** + * Restricts a k-element permutation to an n-element + * permutation, where \a k > \a n. + * + * This is similar to Perm::contract but is considering the last + * n elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - \a n - 1]. + * + * The resulting permutation maps 0,...,n-1 to + * \a p[k - \a n] + \a n - k, ..., + * \a p[k - 1] + \a n - k. + * + * \pre The given permutation maps k - \a n, ..., k - 1 + * to k - \a n, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than \a n. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last \a n elements. + */ + template + static constexpr Perm contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * @@ -2261,6 +2287,7 @@ constexpr Perm Perm::contract(Perm p) { return Perm(c); } + #endif // __DOXYGEN template @@ -2560,6 +2587,8 @@ inline PermClass PermClass::operator ++(int) { #include "maths/spec/perm5.h" #include "maths/spec/perm7.h" +#include "maths/detail/permContractFront.h" + // Explicitly declare the non-specialised classes as extern. Otherwise the // linker on Windows (and *only* Windows) fails to unify their static data // members between the DLL and the executable (even though they are correctly @@ -2579,10 +2608,25 @@ extern template class regina::Perm<16>; namespace regina { +template +template +constexpr Perm Perm::contractFront(Perm p) { + static_assert( + k > n, + "Given permutation needs to have more elements then permutation " + "we contract to."); + return detail::PermContractFront()(p); +} + // What follows are implementations that use these specialised classes. // We hide them from doxygen since specialisations can confuse it. #ifndef __DOXYGEN +template +inline constexpr Perm<2> Perm<2>::contractFront(Perm p) { + return detail::PermContractFront<2, k>()(p); +} + template inline constexpr Perm<2> Perm<2>::contract(Perm p) { static_assert(k >= 8, "The generic implementation of Perm<2>::contract " @@ -2635,6 +2679,11 @@ inline constexpr Perm<3> Perm<3>::contract(Perm p) { return Perm<3>(p[0], p[1], p[2]); } +template +inline constexpr Perm<3> Perm<3>::contractFront(Perm p) { + return detail::PermContractFront<3, k>()(p); +} + template <> inline constexpr Perm<3> Perm<3>::contract(Perm<4> p) { // Code map: 0,3,8,7,12,15 -> 0,1,2,3,4,5. @@ -2666,6 +2715,11 @@ inline constexpr Perm<4> Perm<4>::contract(Perm p) { return Perm<4>(p[0], p[1], p[2], p[3]); } +template +inline constexpr Perm<4> Perm<4>::contractFront(Perm p) { + return detail::PermContractFront<4, k>()(p); +} + inline void Perm<4>::clear(unsigned from) { if (from <= 1) code_ = 0; @@ -2697,6 +2751,11 @@ constexpr Perm<5> Perm<5>::contract(Perm p) { return Perm<5>(p[0], p[1], p[2], p[3], p[4]); } +template +inline constexpr Perm<5> Perm<5>::contractFront(Perm p) { + return detail::PermContractFront<5, k>()(p); +} + inline void Perm<5>::clear(unsigned from) { if (from <= 1) code2_ = 0; @@ -2747,6 +2806,11 @@ constexpr Perm<6> Perm<6>::contract(Perm p) { return Perm<6>(p[0], p[1], p[2], p[3], p[4], p[5]); } +template +inline constexpr Perm<6> Perm<6>::contractFront(Perm p) { + return detail::PermContractFront<6, k>()(p); +} + inline void Perm<6>::clear(unsigned from) { switch (from) { case 0: @@ -2800,6 +2864,11 @@ constexpr Perm<7> Perm<7>::contract(Perm p) { return Perm<7>(p[0], p[1], p[2], p[3], p[4], p[5], p[6]); } +template +inline constexpr Perm<7> Perm<7>::contractFront(Perm p) { + return detail::PermContractFront<7, k>()(p); +} + inline void Perm<7>::clear(unsigned from) { switch (from) { case 0: diff --git a/engine/maths/spec/perm2.h b/engine/maths/spec/perm2.h index 4e7616ea5e..3b97eadccd 100644 --- a/engine/maths/spec/perm2.h +++ b/engine/maths/spec/perm2.h @@ -121,6 +121,12 @@ class Perm<2> { */ using Code = uint8_t; + /** + * Alias for Code so that generic code can use Perm::Code2 + * for small n. + */ + using Code2 = Code; + private: /** * A lightweight array-like object used to implement Perm<2>::S2. @@ -354,6 +360,12 @@ class Perm<2> { */ constexpr Code permCode() const; + /** + * Alias for permCode so that generic code can use Perm::permCode2() + * for small n. + */ + constexpr Code permCode2() const; + /** * Sets this permutation to that represented by the given * internal code. @@ -377,6 +389,12 @@ class Perm<2> { */ static constexpr Perm<2> fromPermCode(Code code); + /** + * Alias for fromPermCode so that generic code can use + * Perm::fromPermCode2(c) for small n. + */ + static constexpr Perm<2> fromPermCode2(Code code); + /** * Determines whether the given integer is a valid internal * permutation code. Valid permutation codes can be passed to @@ -990,6 +1008,32 @@ class Perm<2> { template static constexpr Perm<2> contract(Perm p); + /** + * Restricts a k-element permutation to an 2-element + * permutation, where \a k > 2. + * + * This is similar to Perm::contract but is considering the last + * two elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ..., \a p[k - 3]. + * + * The resulting permutation maps 0 and 1 to + * \a p[k - 2] + 2 - k and + * \a p[k - 1] + 2 - k. + * + * \pre The given permutation maps k - 2 and k - 1 + * to k - 2 and k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 2. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last two elements. + */ + template + static constexpr Perm<2> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * @@ -1082,6 +1126,10 @@ inline constexpr Perm<2>::Code Perm<2>::permCode() const { return code_; } +inline constexpr Perm<2>::Code Perm<2>::permCode2() const { + return code_; +} + inline void Perm<2>::setPermCode(Code code) { code_ = code; } @@ -1090,6 +1138,10 @@ inline constexpr Perm<2> Perm<2>::fromPermCode(Code code) { return Perm<2>(code); } +inline constexpr Perm<2> Perm<2>::fromPermCode2(Code code) { + return Perm<2>(code); +} + inline constexpr bool Perm<2>::isPermCode(Code code) { // code >= 0 is a no-op because we are using an unsigned data type. return (code < 2); diff --git a/engine/maths/spec/perm3.h b/engine/maths/spec/perm3.h index e988a90ced..bb6ee961d0 100644 --- a/engine/maths/spec/perm3.h +++ b/engine/maths/spec/perm3.h @@ -110,6 +110,12 @@ class Perm<3> { */ using Code = uint8_t; + /** + * Alias for Code so that generic code can use Perm::Code2 + * for small n. + */ + using Code2 = Code; + private: /** * A lightweight array-like object used to implement Perm<3>::S3. @@ -421,6 +427,12 @@ class Perm<3> { */ constexpr Code permCode() const; + /** + * Alias for permCode so that generic code can use Perm::permCode2() + * for small n. + */ + constexpr Code permCode2() const; + /** * Sets this permutation to that represented by the given * internal code. @@ -444,6 +456,12 @@ class Perm<3> { */ static constexpr Perm<3> fromPermCode(Code code); + /** + * Alias for fromPermCode so that generic code can use + * Perm::fromPermCode2(c) for small n. + */ + static constexpr Perm<3> fromPermCode2(Code code); + /** * Determines whether the given integer is a valid internal * permutation code. Valid permutation codes can be passed to @@ -1090,6 +1108,32 @@ class Perm<3> { template static constexpr Perm<3> contract(Perm p); + /** + * Restricts a k-element permutation to a 3-element + * permutation, where \a k > 3. + * + * This is similar to Perm::contract but is considering the last + * three elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - 4]. + * + * The resulting permutation maps 0,...,2 to + * \a p[k - 3] + 3 - k, ..., + * \a p[k - 1] + 3 - k. + * + * \pre The given permutation maps k - 3, ..., k - 1 + * to k - 3, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 3. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last three elements. + */ + template + static constexpr Perm<3> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * @@ -1284,6 +1328,10 @@ inline constexpr Perm<3>::Code Perm<3>::permCode() const { return code_; } +inline constexpr Perm<3>::Code Perm<3>::permCode2() const { + return code_; +} + inline void Perm<3>::setPermCode(Code code) { code_ = code; } @@ -1292,6 +1340,10 @@ inline constexpr Perm<3> Perm<3>::fromPermCode(Code code) { return Perm<3>(code); } +inline constexpr Perm<3> Perm<3>::fromPermCode2(Code code) { + return Perm<3>(code); +} + inline constexpr bool Perm<3>::isPermCode(Code code) { // code >= 0 is a no-op because we are using an unsigned data type. return (code < 6); diff --git a/engine/maths/spec/perm4.h b/engine/maths/spec/perm4.h index e0e60461d9..aa912b4456 100644 --- a/engine/maths/spec/perm4.h +++ b/engine/maths/spec/perm4.h @@ -1358,6 +1358,32 @@ class Perm<4> { template static constexpr Perm<4> contract(Perm p); + /** + * Restricts a k-element permutation to a 4-element + * permutation, where \a k > 4. + * + * This is similar to Perm::contract but is considering the last + * three elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - 5]. + * + * The resulting permutation maps 0,...,2 to + * \a p[k - 4] + 4 - k, ..., + * \a p[k - 1] + 4 - k. + * + * \pre The given permutation maps k - 4, ..., k - 1 + * to k - 4, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 4. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last three elements. + */ + template + static constexpr Perm<4> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * diff --git a/engine/maths/spec/perm5.h b/engine/maths/spec/perm5.h index 7ace39b12b..123bafc074 100644 --- a/engine/maths/spec/perm5.h +++ b/engine/maths/spec/perm5.h @@ -1460,6 +1460,32 @@ class Perm<5> { template static constexpr Perm<5> contract(Perm p); + /** + * Restricts a k-element permutation to a 5-element + * permutation, where \a k > 5. + * + * This is similar to Perm::contract but is considering the last + * three elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - 6]. + * + * The resulting permutation maps 0,...,2 to + * \a p[k - 5] + 5 - k, ..., + * \a p[k - 1] + 5 - k. + * + * \pre The given permutation maps k - 5, ..., k - 1 + * to k - 5, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 5. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last three elements. + */ + template + static constexpr Perm<5> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * diff --git a/engine/maths/spec/perm6.h b/engine/maths/spec/perm6.h index 6ca0e6e63e..c2628d1f48 100644 --- a/engine/maths/spec/perm6.h +++ b/engine/maths/spec/perm6.h @@ -1174,6 +1174,32 @@ class Perm<6> { template static constexpr Perm<6> contract(Perm p); + /** + * Restricts a k-element permutation to a 6-element + * permutation, where \a k > 6. + * + * This is similar to Perm::contract but is considering the last + * three elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - 7]. + * + * The resulting permutation maps 0,...,2 to + * \a p[k - 6] + 6 - k, ..., + * \a p[k - 1] + 6 - k. + * + * \pre The given permutation maps k - 6, ..., k - 1 + * to k - 6, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 6. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last three elements. + */ + template + static constexpr Perm<6> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * diff --git a/engine/maths/spec/perm7.h b/engine/maths/spec/perm7.h index 1b47042a7a..f4eba5fa0a 100644 --- a/engine/maths/spec/perm7.h +++ b/engine/maths/spec/perm7.h @@ -1229,6 +1229,32 @@ class Perm<7> { template static constexpr Perm<7> contract(Perm p); + /** + * Restricts a k-element permutation to a 7-element + * permutation, where \a k > 7. + * + * This is similar to Perm::contract but is considering the last + * three elements of the k-element permutation rather than + * the first and ignores the "unused" images + * \a p[0], ...,\a p[k - 8]. + * + * The resulting permutation maps 0,...,2 to + * \a p[k - 7] + 7 - k, ..., + * \a p[k - 1] + 7 - k. + * + * \pre The given permutation maps k - 7, ..., k - 1 + * to k - 7, ..., k - 1 in some order. + * + * \tparam k the number of elements for the input permutation; + * this must be strictly greater than 7. + * + * \param p a permutation on \a k elements. + * \return the same permutation restricted to a permutation on + * the last three elements. + */ + template + static constexpr Perm<7> contractFront(Perm p); + /** * Is this permutation minimal in its conjugacy class? * diff --git a/python/docstrings/maths/perm.h b/python/docstrings/maths/perm.h index 17b4374a6c..1fd06f02af 100644 --- a/python/docstrings/maths/perm.h +++ b/python/docstrings/maths/perm.h @@ -689,6 +689,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on *n* elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to an *n*-element permutation, +where *k* > *n*. + +This is similar to Perm::contract but is considering the last *n* +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - *n* - 1]. + +The resulting permutation maps 0,...,*n*-1 to *p*[*k* - *n*] + *n* - +*k*, ..., *p*[*k* - 1] + *n* - *k*. + +Precondition: + The given permutation maps *k* - *n*, ..., *k* - 1 to *k* - *n*, + ..., *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than *n*. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last *n* + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to an *n*-element permutation, where diff --git a/python/docstrings/maths/perm2.h b/python/docstrings/maths/perm2.h index 9d9837d0a3..1bb9d4023f 100644 --- a/python/docstrings/maths/perm2.h +++ b/python/docstrings/maths/perm2.h @@ -433,6 +433,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 2 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to an 2-element permutation, where +*k* > 2. + +This is similar to Perm::contract but is considering the last two +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ..., *p*[*k* - 3]. + +The resulting permutation maps 0 and 1 to *p*[*k* - 2] + 2 - *k* and +*p*[*k* - 1] + 2 - *k*. + +Precondition: + The given permutation maps *k* - 2 and *k* - 1 to *k* - 2 and *k* + - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 2. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last two + elements.)doc"; + // Docstring regina::python::doc::Perm_::fromPermCode static const char *fromPermCode = R"doc(Creates a permutation from the given internal code. @@ -447,6 +474,11 @@ Parameter ``code``: Returns: the permutation represented by the given internal code.)doc"; +// Docstring regina::python::doc::Perm_::fromPermCode2 +static const char *fromPermCode2 = +R"doc(Alias for fromPermCode so that generic code can use +Perm::fromPermCode2(c) for small n.)doc"; + // Docstring regina::python::doc::Perm_::hash static const char *hash = R"doc(Hashes this permutation to a non-negative integer, allowing it to be @@ -558,6 +590,11 @@ isPermCode(). Returns: the internal code.)doc"; +// Docstring regina::python::doc::Perm_::permCode2 +static const char *permCode2 = +R"doc(Alias for permCode so that generic code can use Perm::permCode2() +for small n.)doc"; + // Docstring regina::python::doc::Perm_::pow static const char *pow = R"doc(Computes the given power of this permutation. diff --git a/python/docstrings/maths/perm3.h b/python/docstrings/maths/perm3.h index 593b8a8685..445377bef2 100644 --- a/python/docstrings/maths/perm3.h +++ b/python/docstrings/maths/perm3.h @@ -470,6 +470,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 3 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to a 3-element permutation, where +*k* > 3. + +This is similar to Perm::contract but is considering the last three +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - 4]. + +The resulting permutation maps 0,...,2 to *p*[*k* - 3] + 3 - *k*, ..., +*p*[*k* - 1] + 3 - *k*. + +Precondition: + The given permutation maps *k* - 3, ..., *k* - 1 to *k* - 3, ..., + *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 3. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last three + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to an 3-element permutation. where 2 @@ -504,6 +531,11 @@ Parameter ``code``: Returns: the permutation represented by the given internal code.)doc"; +// Docstring regina::python::doc::Perm_::fromPermCode2 +static const char *fromPermCode2 = +R"doc(Alias for fromPermCode so that generic code can use +Perm::fromPermCode2(c) for small n.)doc"; + // Docstring regina::python::doc::Perm_::hash static const char *hash = R"doc(Hashes this permutation to a non-negative integer, allowing it to be @@ -615,6 +647,11 @@ isPermCode(). Returns: the internal code.)doc"; +// Docstring regina::python::doc::Perm_::permCode2 +static const char *permCode2 = +R"doc(Alias for permCode so that generic code can use Perm::permCode2() +for small n.)doc"; + // Docstring regina::python::doc::Perm_::pow static const char *pow = R"doc(Computes the given power of this permutation. diff --git a/python/docstrings/maths/perm4.h b/python/docstrings/maths/perm4.h index 3a2a1294be..73d661f453 100644 --- a/python/docstrings/maths/perm4.h +++ b/python/docstrings/maths/perm4.h @@ -506,6 +506,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 4 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to a 4-element permutation, where +*k* > 4. + +This is similar to Perm::contract but is considering the last three +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - 5]. + +The resulting permutation maps 0,...,2 to *p*[*k* - 4] + 4 - *k*, ..., +*p*[*k* - 1] + 4 - *k*. + +Precondition: + The given permutation maps *k* - 4, ..., *k* - 1 to *k* - 4, ..., + *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 4. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last three + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to a 4-element permutation, where 2 diff --git a/python/docstrings/maths/perm5.h b/python/docstrings/maths/perm5.h index fd01e1056a..ed23ea24c1 100644 --- a/python/docstrings/maths/perm5.h +++ b/python/docstrings/maths/perm5.h @@ -522,6 +522,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 5 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to a 5-element permutation, where +*k* > 5. + +This is similar to Perm::contract but is considering the last three +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - 6]. + +The resulting permutation maps 0,...,2 to *p*[*k* - 5] + 5 - *k*, ..., +*p*[*k* - 1] + 5 - *k*. + +Precondition: + The given permutation maps *k* - 5, ..., *k* - 1 to *k* - 5, ..., + *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 5. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last three + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to a 5-element permutation, where 2 diff --git a/python/docstrings/maths/perm6.h b/python/docstrings/maths/perm6.h index 90dd64e7bb..4349f84844 100644 --- a/python/docstrings/maths/perm6.h +++ b/python/docstrings/maths/perm6.h @@ -512,6 +512,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 6 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to a 6-element permutation, where +*k* > 6. + +This is similar to Perm::contract but is considering the last three +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - 7]. + +The resulting permutation maps 0,...,2 to *p*[*k* - 6] + 6 - *k*, ..., +*p*[*k* - 1] + 6 - *k*. + +Precondition: + The given permutation maps *k* - 6, ..., *k* - 1 to *k* - 6, ..., + *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 6. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last three + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to a 6-element permutation, where 2 diff --git a/python/docstrings/maths/perm7.h b/python/docstrings/maths/perm7.h index 44cb830d0d..0fc0cb7863 100644 --- a/python/docstrings/maths/perm7.h +++ b/python/docstrings/maths/perm7.h @@ -548,6 +548,33 @@ Parameter ``p``: Returns: the same permutation restricted to a permutation on 7 elements.)doc"; +// Docstring regina::python::doc::Perm_::contractFront +static const char *contractFront = +R"doc(Restricts a *k*-element permutation to a 7-element permutation, where +*k* > 7. + +This is similar to Perm::contract but is considering the last three +elements of the *k*-element permutation rather than the first and +ignores the "unused" images *p*[0], ...,*p*[*k* - 8]. + +The resulting permutation maps 0,...,2 to *p*[*k* - 7] + 7 - *k*, ..., +*p*[*k* - 1] + 7 - *k*. + +Precondition: + The given permutation maps *k* - 7, ..., *k* - 1 to *k* - 7, ..., + *k* - 1 in some order. + +Template parameter ``k``: + the number of elements for the input permutation; this must be + strictly greater than 7. + +Parameter ``p``: + a permutation on *k* elements. + +Returns: + the same permutation restricted to a permutation on the last three + elements.)doc"; + // Docstring regina::python::doc::Perm_::extend static const char *extend = R"doc(Extends a *k*-element permutation to a 7-element permutation, where 2 diff --git a/python/docstrings/maths/permContractBackImpl.h b/python/docstrings/maths/permContractBackImpl.h new file mode 100644 index 0000000000..e1e0af60d5 --- /dev/null +++ b/python/docstrings/maths/permContractBackImpl.h @@ -0,0 +1,19 @@ +/* + This file contains docstrings for use in the Python bindings. + Do not edit! They were automatically extracted by ../gendoc.sh. + */ + +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +namespace regina::python::doc { + + +} // namespace regina::python::doc + +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif + diff --git a/python/maths/perm.cpp b/python/maths/perm.cpp index 375999af14..fac534b7bf 100644 --- a/python/maths/perm.cpp +++ b/python/maths/perm.cpp @@ -114,6 +114,10 @@ void addPerm(pybind11::module_& m, const char* name) { c.def_static("contract", &Perm::template contract, rdoc::contract); }); + regina::for_constexpr([&c](auto i) { + c.def_static("contractFront", &Perm::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm2.cpp b/python/maths/perm2.cpp index 325bbe3b56..6b6d71ee07 100644 --- a/python/maths/perm2.cpp +++ b/python/maths/perm2.cpp @@ -107,6 +107,10 @@ void addPerm2(pybind11::module_& m) { c.def_static("contract", &Perm<2>::template contract, rdoc::contract); }); + regina::for_constexpr<3, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<2>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm3.cpp b/python/maths/perm3.cpp index dd9fa5505e..e95f897983 100644 --- a/python/maths/perm3.cpp +++ b/python/maths/perm3.cpp @@ -117,6 +117,10 @@ void addPerm3(pybind11::module_& m) { c.def_static("contract", &Perm<3>::template contract, rdoc::contract); }); + regina::for_constexpr<4, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<3>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm4.cpp b/python/maths/perm4.cpp index 5b33a7e653..84977559ca 100644 --- a/python/maths/perm4.cpp +++ b/python/maths/perm4.cpp @@ -130,6 +130,10 @@ void addPerm4(pybind11::module_& m) { c.def_static("contract", &Perm<4>::template contract, rdoc::contract); }); + regina::for_constexpr<5, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<4>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm5.cpp b/python/maths/perm5.cpp index fb0efe14b0..fd807a71a1 100644 --- a/python/maths/perm5.cpp +++ b/python/maths/perm5.cpp @@ -133,6 +133,10 @@ void addPerm5(pybind11::module_& m) { c.def_static("contract", &Perm<5>::template contract, rdoc::contract); }); + regina::for_constexpr<6, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<5>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm6.cpp b/python/maths/perm6.cpp index 57c21ba6f5..c9d9d1c433 100644 --- a/python/maths/perm6.cpp +++ b/python/maths/perm6.cpp @@ -124,6 +124,10 @@ void addPerm6(pybind11::module_& m) { c.def_static("contract", &Perm<6>::template contract, rdoc::contract); }); + regina::for_constexpr<7, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<6>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/python/maths/perm7.cpp b/python/maths/perm7.cpp index 122bf2e906..4fc2bb06d3 100644 --- a/python/maths/perm7.cpp +++ b/python/maths/perm7.cpp @@ -128,6 +128,10 @@ void addPerm7(pybind11::module_& m) { c.def_static("contract", &Perm<7>::template contract, rdoc::contract); }); + regina::for_constexpr<8, 17>([&c](auto i) { + c.def_static("contractFront", &Perm<7>::template contractFront, + rdoc::contractFront); + }); regina::python::add_output_basic(c, rdoc::str); regina::python::add_tight_encoding(c, rdoc::tightEncoding, rdoc::tightDecoding, rdoc::hash); diff --git a/testsuite/maths/perm.cpp b/testsuite/maths/perm.cpp index 616a1af9dd..85bf54380e 100644 --- a/testsuite/maths/perm.cpp +++ b/testsuite/maths/perm.cpp @@ -735,6 +735,23 @@ class LargePermTest : public GeneralPermTest { for (int i = 0; i < nIdx; ++i) verifyTightEncoding(Perm::orderedSn[idx[i]]); } + + void contractFront() { + if (regina::Perm(n-6, n-4) != + regina::Perm::contractFront(Perm(n-5, n-3))) { + std::ostringstream msg; + msg << "Perm::contractFront(Perm(n-5, n-3)) " + "failed for n = " << n << "."; + CPPUNIT_FAIL(msg.str()); + } + if (regina::Perm(n-7, n-6) != + regina::Perm::contractFront(Perm(n-3, n-2))) { + std::ostringstream msg; + msg << "Perm::contractFront(Perm(n-3, n-2)) " + "failed for n = " << n << "."; + CPPUNIT_FAIL(msg.str()); + } + } }; template @@ -752,6 +769,7 @@ class PermTest : public LargePermTest { CPPUNIT_TEST(order); CPPUNIT_TEST(rot); CPPUNIT_TEST(tightEncoding); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); }; @@ -779,6 +797,7 @@ class PermTest<8> : public LargePermTest<8> { CPPUNIT_TEST(increment); CPPUNIT_TEST(conjugacyMinimal); CPPUNIT_TEST(tightEncoding); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); }; @@ -803,6 +822,7 @@ class PermTest<9> : public LargePermTest<9> { CPPUNIT_TEST(increment); CPPUNIT_TEST(conjugacyMinimal); CPPUNIT_TEST(tightEncoding); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); }; @@ -827,6 +847,7 @@ class PermTest<10> : public LargePermTest<10> { CPPUNIT_TEST(increment); CPPUNIT_TEST(conjugacyMinimal); CPPUNIT_TEST(tightEncoding); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); }; @@ -851,6 +872,7 @@ class PermTest<11> : public LargePermTest<11> { CPPUNIT_TEST(increment); CPPUNIT_TEST(conjugacyMinimal); CPPUNIT_TEST(tightEncoding); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); }; diff --git a/testsuite/maths/perm2.cpp b/testsuite/maths/perm2.cpp index 1619a0b0a7..e279bf41a2 100644 --- a/testsuite/maths/perm2.cpp +++ b/testsuite/maths/perm2.cpp @@ -62,6 +62,7 @@ class Perm2Test : public SmallPermTest<2> { // Tests specific to Perm<2>: CPPUNIT_TEST(productsViaPerm4); CPPUNIT_TEST(aliases); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -102,6 +103,64 @@ class Perm2Test : public SmallPermTest<2> { if (Perm<2>::S1[i] != Perm<2>::Sn_1[i]) CPPUNIT_FAIL("Arrays S1 and Sn_1 disagree for Perm<2>."); } + + void contractFront() { + if (Perm<2>() != + Perm<2>::contractFront(Perm<3>(0,1,2))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<3>(0,1,2)) failed."); + } + if (Perm<2>(1,0) != + Perm<2>::contractFront(Perm<3>(0,2,1))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<3>(0,2,1)) failed."); + } + + contractFrontChecks(Perm<2>(), Perm<4>()); + contractFrontChecks(Perm<2>(1,0), Perm<4>(0,1,3,2)); + + contractFrontChecks(Perm<2>(), Perm<5>()); + contractFrontChecks(Perm<2>(1,0), Perm<5>(0,1,2,4,3)); + + contractFrontChecks(Perm<2>(), Perm<6>()); + contractFrontChecks(Perm<2>(1,0), Perm<6>(0,1,2,3,5,4)); + + contractFrontChecks(Perm<2>(), Perm<7>()); + contractFrontChecks(Perm<2>(1,0), Perm<7>(0,1,2,3,4,6,5)); + + if (Perm<2>() != + Perm<2>::contractFront(Perm<8>())) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<8>()) failed."); + } + if (Perm<2>() != + Perm<2>::contractFront(Perm<8>(4,5))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<8>(4,5)) failed."); + } + if (Perm<2>(1,0) != + Perm<2>::contractFront(Perm<8>(6,7))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<8>(6,7)) failed."); + } + if (Perm<2>(1,0) != + Perm<2>::contractFront(Perm<8>(6,7)*Perm<8>(4,5))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<8>(6,7)*Perm<8>(4,5)) failed."); + } + + if (Perm<2>() != + Perm<2>::contractFront(Perm<12>())) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<12>()) failed."); + } + if (Perm<2>() != + Perm<2>::contractFront(Perm<12>(7,8))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<12>(7,8)) failed."); + } + if (Perm<2>(1,0) != + Perm<2>::contractFront(Perm<12>(10,11))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<12>(10,11)) failed."); + } + if (Perm<2>(1,0) != + Perm<2>::contractFront(Perm<12>(10,11)*Perm<12>(7,8))) { + CPPUNIT_FAIL("Perm<2>::contractFront(Perm<12>(10,11)*Perm<12>(7,8)) failed."); + } + + } }; void addPerm2(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/perm3.cpp b/testsuite/maths/perm3.cpp index 15d0507030..77b0b14f08 100644 --- a/testsuite/maths/perm3.cpp +++ b/testsuite/maths/perm3.cpp @@ -63,6 +63,7 @@ class Perm3Test : public SmallPermTest<3> { CPPUNIT_TEST(productsViaPerm4); CPPUNIT_TEST(aliases); CPPUNIT_TEST(S2); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -131,6 +132,52 @@ class Perm3Test : public SmallPermTest<3> { "match Perm<2>."); } } + + void contractFront() { + if (Perm<3>(0,1,2) != + Perm<3>::contractFront(Perm<4>(0,1,2,3))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,1,2,3)) failed."); + } + if (Perm<3>(0,2,1) != + Perm<3>::contractFront(Perm<4>(0,1,3,2))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,1,3,2)) failed."); + } + if (Perm<3>(1,0,2) != + Perm<3>::contractFront(Perm<4>(0,2,1,3))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,2,1,3)) failed."); + } + if (Perm<3>(1,2,0) != + Perm<3>::contractFront(Perm<4>(0,2,3,1))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,2,3,1)) failed."); + } + if (Perm<3>(2,0,1) != + Perm<3>::contractFront(Perm<4>(0,3,1,2))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,3,1,2)) failed."); + } + if (Perm<3>(2,1,0) != + Perm<3>::contractFront(Perm<4>(0,3,2,1))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<4>(0,3,2,1)) failed."); + } + + contractFrontChecks(Perm<3>(0,1,2), Perm<5>(0,1,2,3,4)); + contractFrontChecks(Perm<3>(0,2,1), Perm<5>(0,1,2,4,3)); + contractFrontChecks(Perm<3>(1,0,2), Perm<5>(0,1,3,2,4)); + contractFrontChecks(Perm<3>(1,2,0), Perm<5>(0,1,3,4,2)); + contractFrontChecks(Perm<3>(2,0,1), Perm<5>(0,1,4,2,3)); + contractFrontChecks(Perm<3>(2,1,0), Perm<5>(0,1,4,3,2)); + + contractFrontChecks(Perm<3>(0,1,2), Perm<6>(0,1,2,3,4,5)); + contractFrontChecks(Perm<3>(0,2,1), Perm<6>(0,1,2,3,5,4)); + contractFrontChecks(Perm<3>(1,0,2), Perm<6>(0,1,2,4,3,5)); + contractFrontChecks(Perm<3>(1,2,0), Perm<6>(0,1,2,4,5,3)); + contractFrontChecks(Perm<3>(2,0,1), Perm<6>(0,1,2,5,3,4)); + contractFrontChecks(Perm<3>(2,1,0), Perm<6>(0,1,2,5,4,3)); + + if (Perm<3>(1,2,0) != + Perm<3>::contractFront(Perm<10>(3,4) * Perm<10>(7,8) * Perm<10>(8,9))) { + CPPUNIT_FAIL("Perm<3>::contractFront(Perm<10>(...)) failed."); + } + } }; void addPerm3(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/perm4.cpp b/testsuite/maths/perm4.cpp index 6e823cd28e..e71af054e0 100644 --- a/testsuite/maths/perm4.cpp +++ b/testsuite/maths/perm4.cpp @@ -67,6 +67,7 @@ class Perm4Test : public SmallPermTest<4> { CPPUNIT_TEST(aliases); CPPUNIT_TEST(S2); CPPUNIT_TEST(S3); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -156,6 +157,38 @@ class Perm4Test : public SmallPermTest<4> { "match Perm<3>."); } } + + void contractFront() { + if (Perm<4>(1,2,0,3) != + Perm<4>::contractFront(Perm<5>(0,2,3,1,4))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<5>(0,2,3,1,4)) failed"); + } + if (Perm<4>(1,2,3,0) != + Perm<4>::contractFront(Perm<5>(0,2,3,4,1))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<5>(0,2,3,4,1)) failed"); + } + if (Perm<4>(1,3,0,2) != + Perm<4>::contractFront(Perm<5>(0,2,4,1,3))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<5>(0,2,4,1,3)) failed"); + } + if (Perm<4>(1,3,2,0) != + Perm<4>::contractFront(Perm<5>(0,2,4,3,1))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<5>(0,2,4,3,1)) failed"); + } + + contractFrontChecks(Perm<4>(2,0,1,3), Perm<6>(0,1,4,2,3,5)); + contractFrontChecks(Perm<4>(2,0,3,1), Perm<7>(0,1,2,5,3,6,4)); + + if (Perm<4>(0,1) != + Perm<4>::contractFront(Perm<10>(6,7))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<10>(6,7))"); + } + + if (Perm<4>(1,2) != + Perm<4>::contractFront(Perm<11>(8,9))) { + CPPUNIT_FAIL("Perm<4>::contractFront(Perm<11>(8,9))"); + } + } }; void addPerm4(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/perm5.cpp b/testsuite/maths/perm5.cpp index b1e9a68a16..1741df4e6a 100644 --- a/testsuite/maths/perm5.cpp +++ b/testsuite/maths/perm5.cpp @@ -65,6 +65,7 @@ class Perm5Test : public SmallPermTest<5> { CPPUNIT_TEST(S2); CPPUNIT_TEST(S3); CPPUNIT_TEST(S4); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -165,6 +166,28 @@ class Perm5Test : public SmallPermTest<5> { "match Perm<4>."); } } + + void contractFront() { + if (Perm<5>(1,2,0,3,4) != + Perm<5>::contractFront(Perm<6>(0,2,3,1,4,5))) { + CPPUNIT_FAIL("Perm<5>::contractFront(Perm<6>(0,2,3,1,4,5)) failed"); + } + if (Perm<5>(1,2,0,4,3) != + Perm<5>::contractFront(Perm<6>(0,2,3,1,5,4))) { + CPPUNIT_FAIL("Perm<5>::contractFront(Perm<6>(0,2,3,1,5,4)) failed"); + } + if (Perm<5>(1,2,3,0,4) != + Perm<5>::contractFront(Perm<6>(0,2,3,4,1,5))) { + CPPUNIT_FAIL("Perm<5>::contractFront(Perm<6>(0,2,3,4,1,5)) failed"); + } + + contractFrontChecks(Perm<5>(1,2,3,4,0), Perm<7>(0,1,3,4,5,6,2)); + + if (Perm<5>(1,0,2,4,3) != + Perm<5>::contractFront(Perm<10>(3,4) * Perm<10>(5,6) * Perm<10>(8,9))) { + CPPUNIT_FAIL("Perm<5>::contractFront(Perm<10>(...)) failed"); + } + } }; void addPerm5(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/perm6.cpp b/testsuite/maths/perm6.cpp index 5e929d97e6..fdeefd3752 100644 --- a/testsuite/maths/perm6.cpp +++ b/testsuite/maths/perm6.cpp @@ -62,6 +62,7 @@ class Perm6Test : public SmallPermTest<6> { // Tests specific to Perm<6>: CPPUNIT_TEST(aliases); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -71,6 +72,27 @@ class Perm6Test : public SmallPermTest<6> { if (Perm<6>::S6[i] != Perm<6>::Sn[i]) CPPUNIT_FAIL("Arrays S6 and Sn disagree for Perm<6>."); } + + void contractFront() { + if (Perm<6>(1,2,0,3,4,5) != + Perm<6>::contractFront(Perm<7>(0,2,3,1,4,5,6))) { + CPPUNIT_FAIL("Perm<6>::contractFront(Perm<7>(0,2,3,1,4,5,6))"); + } + if (Perm<6>(1,2,0,3,5,4) != + Perm<6>::contractFront(Perm<7>(0,2,3,1,4,6,5))) { + CPPUNIT_FAIL("Perm<6>::contractFront(Perm<7>(0,2,3,1,4,6,5))"); + } + + contractFrontChecks( + Perm<6>(1,2,0,4,3,5), Perm<8>({0,1,3,4,2,6,5,7})); + contractFrontChecks( + Perm<6>(1,2,0,4,3,5), Perm<9>({0,1,2,4,5,3,7,6,8})); + + if (Perm<6>(3,4) != + Perm<6>::contractFront(Perm<13>(10,11))) { + CPPUNIT_FAIL("Perm<6>::contractFront(Perm<13>(10,11))"); + } + } }; void addPerm6(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/perm7.cpp b/testsuite/maths/perm7.cpp index 2db11f75b4..0afd117137 100644 --- a/testsuite/maths/perm7.cpp +++ b/testsuite/maths/perm7.cpp @@ -62,6 +62,7 @@ class Perm7Test : public SmallPermTest<7> { // Tests specific to Perm<7>: CPPUNIT_TEST(aliases); + CPPUNIT_TEST(contractFront); CPPUNIT_TEST_SUITE_END(); @@ -71,6 +72,15 @@ class Perm7Test : public SmallPermTest<7> { if (Perm<7>::S7[i] != Perm<7>::Sn[i]) CPPUNIT_FAIL("Arrays S7 and Sn disagree for Perm<7>."); } + + void contractFront() { + if (Perm<7>(0,2,1,3,4,6,5) != + Perm<7>::contractFront(Perm<8>(2,3) * Perm<8>(6,7))) { + CPPUNIT_FAIL("Perm<7>::contractFront(Perm<8>(2,3) * Perm<8>(6,7)) failed"); + } + contractFrontChecks(Perm<7>(2,3), Perm<9>(4,5)); + contractFrontChecks(Perm<7>(1,4), Perm<10>(4,7)); + } }; void addPerm7(CppUnit::TextUi::TestRunner& runner) { diff --git a/testsuite/maths/permtest.h b/testsuite/maths/permtest.h index 54a8bd1a08..3f4514fde2 100644 --- a/testsuite/maths/permtest.h +++ b/testsuite/maths/permtest.h @@ -254,6 +254,28 @@ class GeneralPermTest : public CppUnit::TestFixture, ++p; } while (! p.isIdentity()); } + + template + void contractFrontChecks(Perm expected, Perm given) + { + if (expected != Perm::contractFront(given)) { + std::ostringstream msg; + msg << "Perm<" << n << ">" + "::contractFront(" << given << ") gives wrong result."; + CPPUNIT_FAIL(msg.str()); + } + + constexpr int s = k - n; + for (int i = 0; i < Perm::nPerms; ++i) { + const Perm p = Perm::extend(Perm::Sn[i]) * given; + if (expected != Perm::contractFront(p)) { + std::ostringstream msg; + msg << "Perm<" << n << ">" + "::contractFront(" << p << ") gives wrong result."; + CPPUNIT_FAIL(msg.str()); + } + } + } }; /**