X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Futils.h;h=b0f24d92e9d414bce8f643beb2a5383e0498ac94;hp=816679d7e0338201995ff0e2aca1e7dc9bb84c85;hb=c3a7dda76e171bbd1e1418b3dab56df49920f721;hpb=3a7031219dabf8e5d15dc63ca4975c88e20abaec diff --git a/ginac/utils.h b/ginac/utils.h index 816679d7..b0f24d92 100644 --- a/ginac/utils.h +++ b/ginac/utils.h @@ -4,7 +4,7 @@ * of any interest to the user of the library. */ /* - * GiNaC Copyright (C) 1999-2017 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2020 Johannes Gutenberg University Mainz, Germany * * 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 @@ -272,32 +272,32 @@ again: } } -/** Generate all bounded combinatorial partitions of an integer n with exactly - * m parts (including zero parts) in non-decreasing order. +/** Base class for generating all bounded combinatorial partitions of an integer + * n with exactly m parts in non-decreasing order. */ -class partition_generator { -private: +class basic_partition_generator { +protected: // Partitions n into m parts, not including zero parts. // (Cf. OEIS sequence A008284; implementation adapted from Jörg Arndt's // FXT library) struct mpartition2 { // partition: x[1] + x[2] + ... + x[m] = n and sentinel x[0] == 0 - std::vector x; - int n; // n>0 - int m; // 0 x; + unsigned n; // n>0 + unsigned m; // 0 partition; // current partition + }; + mpartition2 mpgen; + basic_partition_generator(unsigned n_, unsigned m_) + : mpgen(n_, m_) + { } +}; + +/** Generate all bounded combinatorial partitions of an integer n with exactly + * m parts (including zero parts) in non-decreasing order. + */ +class partition_with_zero_parts_generator : public basic_partition_generator { +private: + unsigned m; // number of parts 0 partition; // current partition + mutable bool current_updated; // whether partition vector has been updated public: - partition_generator(unsigned n_, unsigned m_) - : mpgen(n_, 1), m(m_), partition(m_) + partition_with_zero_parts_generator(unsigned n_, unsigned m_) + : basic_partition_generator(n_, 1), m(m_), partition(m_), current_updated(false) { } // returns current partition in non-decreasing order, padded with zeros - const std::vector& current() const + const std::vector& get() const { - for (int i = 0; i < m - mpgen.m; ++i) - partition[i] = 0; // pad with zeros + if (!current_updated) { + for (unsigned i = 0; i < m - mpgen.m; ++i) + partition[i] = 0; // pad with zeros - for (int i = m - mpgen.m; i < m; ++i) - partition[i] = mpgen.x[i - m + mpgen.m + 1]; + for (unsigned i = m - mpgen.m; i < m; ++i) + partition[i] = mpgen.x[i - m + mpgen.m + 1]; + current_updated = true; + } return partition; } bool next() { + current_updated = false; if (!mpgen.next_partition()) { if (mpgen.m == m || mpgen.m == mpgen.n) return false; // current is last @@ -344,6 +360,35 @@ public: } }; +/** Generate all bounded combinatorial partitions of an integer n with exactly + * m parts (not including zero parts) in non-decreasing order. + */ +class partition_generator : public basic_partition_generator { +private: + mutable std::vector partition; // current partition + mutable bool current_updated; // whether partition vector has been updated +public: + partition_generator(unsigned n_, unsigned m_) + : basic_partition_generator(n_, m_), partition(m_), current_updated(false) + { } + // returns current partition in non-decreasing order, padded with zeros + const std::vector& get() const + { + if (!current_updated) { + for (unsigned i = 0; i < mpgen.m; ++i) + partition[i] = mpgen.x[i + 1]; + + current_updated = true; + } + return partition; + } + bool next() + { + current_updated = false; + return mpgen.next_partition(); + } +}; + /** Generate all compositions of a partition of an integer n, starting with the * compositions which has non-decreasing order. */ @@ -356,9 +401,9 @@ private: struct coolmulti { // element of singly linked list struct element { - int value; + unsigned value; element* next; - element(int val, element* n) + element(unsigned val, element* n) : value(val), next(n) {} ~element() { // recurses down to the end of the singly linked list @@ -367,7 +412,7 @@ private: }; element *head, *i, *after_i; // NB: Partition must be sorted in non-decreasing order. - explicit coolmulti(const std::vector& partition) + explicit coolmulti(const std::vector& partition) : head(nullptr), i(nullptr), after_i(nullptr) { for (unsigned n = 0; n < partition.size(); ++n) { @@ -403,22 +448,26 @@ private: } cmgen; bool atend; // needed for simplifying iteration over permutations bool trivial; // likewise, true if all elements are equal - mutable std::vector composition; // current compositions + mutable std::vector composition; // current compositions + mutable bool current_updated; // whether composition vector has been updated public: - explicit composition_generator(const std::vector& partition) - : cmgen(partition), atend(false), trivial(true), composition(partition.size()) + explicit composition_generator(const std::vector& partition) + : cmgen(partition), atend(false), trivial(true), composition(partition.size()), current_updated(false) { for (unsigned i=1; i& current() const + const std::vector& get() const { - coolmulti::element* it = cmgen.head; - size_t i = 0; - while (it != nullptr) { - composition[i] = it->value; - it = it->next; - ++i; + if (!current_updated) { + coolmulti::element* it = cmgen.head; + size_t i = 0; + while (it != nullptr) { + composition[i] = it->value; + it = it->next; + ++i; + } + current_updated = true; } return composition; } @@ -430,6 +479,7 @@ public: if (trivial || atend) return false; cmgen.next_permutation(); + current_updated = false; atend = cmgen.finished(); return true; } @@ -439,7 +489,7 @@ public: * n = p1+p2+...+pk, i.e. p is a partition of n. */ const numeric -multinomial_coefficient(const std::vector & p); +multinomial_coefficient(const std::vector & p); // Collection of `construct on first use' wrappers for safely avoiding