LIBINT 2.7.2
intpart_iter.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_include_libint2_util_intpartiter_h_
22#define _libint2_include_libint2_util_intpartiter_h_
23
24#include <array>
25#include <cassert>
26#include <cstdint>
27#include <iterator>
28#include <limits>
29#include <numeric>
30#include <stdexcept>
31#include <type_traits>
32#include <vector>
33
34namespace libint2 {
35
36namespace detail {
37template <class C>
38constexpr auto size(const C& c) -> decltype(c.size()) {
39 return c.size();
40}
41
42template <class T, std::size_t N>
43constexpr std::size_t size(const T (&array)[N]) noexcept {
44 return N;
45}
46
47template <typename T>
48struct has_static_size;
49template <typename T, size_t N>
50struct has_static_size<std::array<T, N>> : std::true_type {};
51template <typename T, size_t N>
52struct has_static_size<T[N]> : std::true_type {};
53template <typename T>
54struct has_static_size : std::false_type {};
55
56template <typename T, typename A>
57void resize(std::vector<T,A>& x, std::size_t n) {
58 x.resize(n);
59}
60
61} // namespace detail
62
71template <typename Sequence,
72 typename = typename std::enable_if<std::numeric_limits<
73 typename Sequence::value_type>::is_integer>::type>
75 public:
76 typedef const Sequence& value_type;
77 typedef typename Sequence::value_type integer_type;
78 typedef typename std::make_unsigned<integer_type>::type unsigned_integer_type;
79 typedef typename Sequence::size_type size_type;
80
82 template <typename Seq = Sequence>
84 unsigned_integer_type n,
85 typename std::enable_if<detail::has_static_size<Seq>::value>::type* = nullptr)
86 : n_(n) {
87 assert(n >= 0);
88 // initialize partition_
89 std::fill(std::begin(partition_), std::end(partition_), integer_type(0));
90 partition_[0] = n_;
91 }
92
95 FixedOrderedIntegerPartitionIterator(unsigned_integer_type n, size_type k)
96 : n_(n) {
97 assert(n >= 0);
98 assert(k > 0);
99 // initialize partition_
100 detail::resize(partition_, k);
101 std::fill(std::begin(partition_), std::end(partition_), integer_type(0));
102 partition_[0] = n_;
103 }
104
106 intmax_t range_size() const {
107 intmax_t result = 1;
108 const auto partition_size = detail::size(partition_);
109 for (intmax_t d = 1; d <= n_; ++d) {
110 result *= (partition_size + d - 1);
111 result /= d;
112 }
113 return result;
114 }
115
116 value_type operator*() const { return partition_; }
117
118 const Sequence* operator->() const { return &partition_; }
119
121 operator bool() const { return this->last(); }
122
124 bool last() const { return last(&partition_[0], detail::size(partition_)); }
125
128 void next() { next(&partition_[0], detail::size(partition_)); }
129
131 template <typename Seq>
132 static intmax_t rank(const Seq& part) {
133 auto k = detail::size(part);
134 decltype(k) count = 0;
135 intmax_t result = 0;
136 auto part_i = part[0];
137 for (decltype(k) i = 0; i != k;) {
138 if (part_i > 0) {
139 ++count;
140 --part_i;
141 intmax_t contrib_i = 1;
142 for (decltype(count) c = 0; c != count; ++c) {
143 contrib_i *= (i + c);
144 result /= (c + 1);
145 }
146 result += contrib_i;
147 }
148 if (part_i == 0) {
149 ++i;
150 part_i = part[i];
151 }
152 }
153 return result;
154 }
155
156 private:
157 unsigned long n_;
158 Sequence partition_;
159
160 static void first(integer_type* partition, size_type size) {
161 assert(size > 0);
162 const auto n =
163 std::accumulate(partition, partition + size, unsigned_integer_type(0));
164 std::fill(partition, partition + size, integer_type(0));
165 partition[0] = n;
166 }
167 static bool last(const integer_type* partition, size_type size) {
168 assert(size > 0);
169 const auto n = std::accumulate(partition, partition + size, 0u);
170 return partition[size - 1] == n;
171 }
172 static void next(integer_type* partition, size_type size) {
173 assert(size > 0);
174 if (size == 1) return;
175 if (last(partition + 1, size - 1)) {
176 assert(partition[0] != 0u);
177 --partition[0];
178 ++partition[1];
179 first(partition + 1, size - 1);
180 } else {
181 next(partition + 1, size - 1);
182 }
183 }
184};
185
186} // namespace libint2
187
188#endif /* header guard */
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
Iterates over all partitions of a non-negative integer into nonnegative integers in reverse lexicog...
Definition: intpart_iter.h:74
void next()
update to the next partition in the range
Definition: intpart_iter.h:128
FixedOrderedIntegerPartitionIterator(unsigned_integer_type n, size_type k)
Definition: intpart_iter.h:95
FixedOrderedIntegerPartitionIterator(unsigned_integer_type n, typename std::enable_if< detail::has_static_size< Seq >::value >::type *=nullptr)
Definition: intpart_iter.h:83
bool last() const
Definition: intpart_iter.h:124
static intmax_t rank(const Seq &part)
returns the rank (index) of partition part in the partition range
Definition: intpart_iter.h:132
intmax_t range_size() const
Definition: intpart_iter.h:106
Definition: intpart_iter.h:54