Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Subset_Sum.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
69#ifndef SUBSET_SUM_H
70#define SUBSET_SUM_H
71
72#include <algorithm>
73#include <concepts>
74#include <cstddef>
75#include <cstdint>
76#include <limits>
77#include <type_traits>
78#include <utility>
79
80#include <ah-errors.H>
81#include <tpl_array.H>
82#include <tpl_sort_utils.H>
83
84namespace Aleph {
89template <typename T>
95
96namespace subset_sum_detail {
97template <std::integral T>
98[[nodiscard]] inline size_t to_size_checked(const T value, const char *fn_name, const char *field_name)
99{
100 if constexpr (std::is_signed_v<T>)
101 ah_domain_error_if(value < T{}) << fn_name << ": " << field_name << " must be non-negative";
102
103 using UT = std::make_unsigned_t<T>;
104 const UT uvalue = static_cast<UT>(value);
105 if constexpr (sizeof(UT) > sizeof(size_t))
106 ah_out_of_range_error_if(uvalue > static_cast<UT>(std::numeric_limits<size_t>::max()))
107 << fn_name << ": " << field_name << " is too large for size_t";
108
109 return static_cast<size_t>(uvalue);
110}
111
112template <std::integral T>
113[[nodiscard]] inline Array<size_t> extract_values_checked(const Array<T> &values, const char *fn_name)
114{
116 for (size_t i = 0; i < values.size(); ++i)
117 converted(i) = to_size_checked(values[i], fn_name, "value");
118 return converted;
119}
120
121// Enumerate all subset sums of arr[start..start+len-1]
122// Returns array of pairs (sum, bitmask relative to start)
123template <typename T>
125{
126 ah_out_of_range_error_if(len >= std::numeric_limits<uint64_t>::digits)
127 << "subset_sum_mitm: each half must have fewer than 64 elements";
128
129 const uint64_t count = static_cast<uint64_t>(1) << len;
130 ah_out_of_range_error_if(count > std::numeric_limits<size_t>::max())
131 << "subset_sum_mitm: subset count does not fit size_t";
132
134 result.reserve(static_cast<size_t>(count));
135
136 for (uint64_t mask = 0; mask < count; ++mask)
137 {
138 long long s = 0;
139 for (size_t j = 0; j < len; ++j)
140 if (mask & (static_cast<uint64_t>(1) << j))
141 s += static_cast<long long>(arr[start + j]);
142 result.append(std::make_pair(s, mask));
143 }
144
145 return result;
146}
147} // namespace subset_sum_detail
148
165template <std::integral T>
167{
168 const size_t n = values.size();
169 const size_t tgt = subset_sum_detail::to_size_checked(target, "subset_sum", "target");
170 const Array<size_t> weights = subset_sum_detail::extract_values_checked(values, "subset_sum");
171
172 if (tgt == 0)
173 return Subset_Sum_Result<T>{true, Array<size_t>()};
174
175 if (n == 0)
176 return Subset_Sum_Result<T>{false, Array<size_t>()};
177
178 // dp[i][s] = can we achieve sum s using items 0..i-1?
179 // Use bit-per-row for space efficiency? No, we need reconstruction.
181 dp.reserve(n + 1);
182 for (size_t i = 0; i <= n; ++i)
183 {
185 for (size_t s = 0; s <= tgt; ++s)
186 row(s) = 0;
187 dp.append(std::move(row));
188 }
189
190 dp[0][0] = 1;
191
192 for (size_t i = 1; i <= n; ++i)
193 {
194 const size_t vi = weights[i - 1];
195 for (size_t s = 0; s <= tgt; ++s)
196 {
197 dp[i][s] = dp[i - 1][s];
198 if (not dp[i][s] and vi <= s and dp[i - 1][s - vi])
199 dp[i][s] = 1;
200 }
201 }
202
203 if (not dp[n][tgt])
204 return Subset_Sum_Result<T>{false, Array<size_t>()};
205
206 // reconstruct
208 size_t s = tgt;
209 for (size_t i = n; i > 0 and s > 0; --i)
210 if (dp[i][s] and not dp[i - 1][s])
211 {
212 sel.append(i - 1);
213 s -= weights[i - 1];
214 }
215
216 // reverse
217 Array<size_t> selected;
218 selected.reserve(sel.size());
219 for (size_t k = sel.size(); k > 0; --k)
220 selected.append(sel[k - 1]);
221
222 return Subset_Sum_Result<T>{true, std::move(selected)};
223}
224
239template <std::integral T>
240[[nodiscard]] bool subset_sum_exists(const Array<T> &values, T target)
241{
242 const size_t n = values.size();
243 const size_t tgt = subset_sum_detail::to_size_checked(target, "subset_sum_exists", "target");
244 const Array<size_t> weights
245 = subset_sum_detail::extract_values_checked(values, "subset_sum_exists");
246
247 if (tgt == 0)
248 return true;
249 if (n == 0)
250 return false;
251
252 Array<char> dp = Array<char>::create(tgt + 1);
253 for (size_t s = 0; s <= tgt; ++s)
254 dp(s) = 0;
255 dp(0) = 1;
256
257 for (size_t i = 0; i < n; ++i)
258 {
259 const size_t vi = weights[i];
260 for (size_t s = tgt; s >= vi and s != static_cast<size_t>(-1); --s)
261 if (dp[s - vi])
262 dp(s) = 1;
263 }
264
265 return dp[tgt];
266}
267
281template <std::integral T>
282[[nodiscard]] size_t subset_sum_count(const Array<T> &values, T target)
283{
284 const size_t n = values.size();
285 const size_t tgt = subset_sum_detail::to_size_checked(target, "subset_sum_count", "target");
286 const Array<size_t> weights
287 = subset_sum_detail::extract_values_checked(values, "subset_sum_count");
288
290 for (size_t s = 0; s <= tgt; ++s)
291 dp(s) = 0;
292 dp(0) = 1;
293
294 for (size_t i = 0; i < n; ++i)
295 {
296 const size_t vi = weights[i];
297 for (size_t s = tgt; s >= vi and s != static_cast<size_t>(-1); --s)
298 if (const size_t count = dp[s - vi]; count > 0)
299 if (dp(s) > std::numeric_limits<size_t>::max() - count)
300 dp(s) = std::numeric_limits<size_t>::max();
301 else
302 dp(s) += count;
303 }
304
305 return dp[tgt];
306}
307
328template <std::integral T>
330{
331 const size_t n = values.size();
332
333 if (n == 0)
334 return Subset_Sum_Result<T>{target == T{}, Array<size_t>()};
335
336 const size_t half1 = n / 2;
337 const size_t half2 = n - half1;
338
341
342 // sort sums2 by sum value
344 [](const auto &a, const auto &b)
345 {
346 return a.first < b.first;
347 });
348
349 const auto target_ll = static_cast<long long>(target);
350 for (size_t i = 0; i < sums1.size(); ++i)
351 {
352 const long long need = target_ll - sums1[i].first;
353
354 // binary search in sums2 for 'need'
355 size_t lo = 0, hi = sums2.size();
356 while (lo < hi)
357 {
358 const size_t mid = lo + (hi - lo) / 2;
359 if (sums2[mid].first < need)
360 lo = mid + 1;
361 else
362 hi = mid;
363 }
364
365 if (lo < sums2.size() and sums2[lo].first == need)
366 {
367 // reconstruct indices
369 const uint64_t mask1 = sums1[i].second;
370 const uint64_t mask2 = sums2[lo].second;
371
372 for (size_t j = 0; j < half1; ++j)
373 if (mask1 & (static_cast<uint64_t>(1) << j))
374 sel.append(j);
375
376 for (size_t j = 0; j < half2; ++j)
377 if (mask2 & (static_cast<uint64_t>(1) << j))
378 sel.append(half1 + j);
379
380 return Subset_Sum_Result<T>{true, std::move(sel)};
381 }
382 }
383
384 return Subset_Sum_Result<T>{false, Array<size_t>()};
385}
386} // namespace Aleph
387
388#endif // SUBSET_SUM_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t row
Definition ca-c-api.h:115
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Array< size_t > extract_values_checked(const Array< T > &values, const char *fn_name)
Definition Subset_Sum.H:113
Array< std::pair< long long, uint64_t > > enumerate_sums(const Array< T > &arr, size_t start, size_t len)
Definition Subset_Sum.H:124
size_t to_size_checked(const T value, const char *fn_name, const char *field_name)
Definition Subset_Sum.H:98
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool subset_sum_exists(const Array< T > &values, T target)
Check if a subset summing to target exists (space-optimized).
Definition Subset_Sum.H:240
size_t subset_sum_count(const Array< T > &values, T target)
Count the number of subsets that sum to target.
Definition Subset_Sum.H:282
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
Subset_Sum_Result< T > subset_sum_mitm(const Array< T > &values, T target)
Solve the subset sum problem via meet-in-the-middle (MITM).
Definition Subset_Sum.H:329
Subset_Sum_Result< T > subset_sum(const Array< T > &values, T target)
Solve the subset sum problem via classical DP with reconstruction.
Definition Subset_Sum.H:166
void introsort(T *a, const long l, const long r, const Compare &cmp=Compare())
Sort an array using introsort (introspective sort).
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
Result of a subset sum computation.
Definition Subset_Sum.H:91
Array< size_t > selected_indices
Indices (0-based) of the elements forming the subset.
Definition Subset_Sum.H:93
bool exists
Whether a valid subset was found.
Definition Subset_Sum.H:92
static int * k
Dynamic array container with automatic resizing.
Comprehensive sorting algorithms and search utilities for Aleph-w.