Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
subset_sum_test.cc
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
36#include <cstdint>
37#include <random>
38#include <bitArray.H>
39
40#include <gtest/gtest.h>
41
42#include <Subset_Sum.H>
43
44using namespace Aleph;
45
46namespace {
47size_t brute_subset_count(const Array<int> &vals, const int target)
48{
49 const size_t n = vals.size();
50 const uint64_t total_masks = static_cast<uint64_t>(1) << n;
51 size_t count = 0;
52 for (uint64_t mask = 0; mask < total_masks; ++mask)
53 {
54 int sum = 0;
55 for (size_t i = 0; i < n; ++i)
56 if (mask & (uint64_t(1) << i))
57 sum += vals[i];
58 if (sum == target)
59 ++count;
60 }
61 return count;
62}
63
64bool valid_selection(const Array<int> &vals, const Array<size_t> &selected, const int target)
65{
66 int sum = 0;
67 BitArray seen(vals.size());
68 for (size_t idx : selected)
69 {
70 if (idx >= vals.size() or seen[idx])
71 return false;
72 seen[idx] = true;
73 sum += vals[idx];
74 }
75 return sum == target;
76}
77} // namespace
78
80{
81 const Array<int> vals;
82 auto r = subset_sum(vals, 0);
83 EXPECT_TRUE(r.exists);
84 EXPECT_EQ(r.selected_indices.size(), 0u);
85
86 r = subset_sum(vals, 5);
87 EXPECT_FALSE(r.exists);
88}
89
91{
92 Array<int> vals = {1, 2, 3};
93 auto r = subset_sum(vals, 0);
94 EXPECT_TRUE(r.exists);
95 EXPECT_EQ(r.selected_indices.size(), 0u);
96}
97
99{
100 Array<int> vals = {3, 34, 4, 12, 5, 2};
101 auto r = subset_sum(vals, 9);
102 EXPECT_TRUE(r.exists);
103
104 // Verify selected indices sum to target
105 int total = 0;
106 for (size_t selected_indice : r.selected_indices)
108 EXPECT_EQ(total, 9);
109}
110
112{
113 Array<int> vals = {3, 34, 4, 12, 5, 2};
114 auto r = subset_sum(vals, 100);
115 EXPECT_FALSE(r.exists);
116}
117
119{
120 Array<int> vals = {3, 34, 4, 12, 5, 2};
123}
124
126{
127 Array<int> vals = {1, 2, 3, 4, 5};
128 // Subsets summing to 5: {5}, {2,3}, {1,4} = 3
130}
131
133{
134 Array<int> vals = {1, 2, 3};
135 // Only the empty subset sums to 0
137}
138
140{
141 Array<int> vals = {1, 2, 3};
142 EXPECT_THROW(subset_sum(vals, -1), std::domain_error);
143 EXPECT_THROW(subset_sum_exists(vals, -1), std::domain_error);
144 EXPECT_THROW(subset_sum_count(vals, -1), std::domain_error);
145}
146
148{
149 Array<int> vals = {5, -2, 7};
150 EXPECT_THROW(subset_sum(vals, 10), std::domain_error);
151 EXPECT_THROW(subset_sum_exists(vals, 10), std::domain_error);
152 EXPECT_THROW(subset_sum_count(vals, 10), std::domain_error);
153}
154
156{
157 Array<int> vals = {0, 0, 1};
158 // Subsets summing to 1: {1}, {0,1}, {0,1}, {0,0,1} -> 4
160 auto r = subset_sum(vals, 1);
161 EXPECT_TRUE(r.exists);
162 EXPECT_TRUE(valid_selection(vals, r.selected_indices, 1));
163}
164
165// Meet-in-the-middle tests
166
168{
170 auto r = subset_sum_mitm(vals, 0);
171 EXPECT_TRUE(r.exists);
172
173 r = subset_sum_mitm(vals, 5);
174 EXPECT_FALSE(r.exists);
175}
176
178{
179 Array<int> vals = {3, 34, 4, 12, 5, 2};
180 auto r = subset_sum_mitm(vals, 9);
181 EXPECT_TRUE(r.exists);
182
183 int total = 0;
184 for (size_t k = 0; k < r.selected_indices.size(); ++k)
185 total += vals[r.selected_indices[k]];
186 EXPECT_EQ(total, 9);
187}
188
190{
191 Array<int> vals = {3, 34, 4, 12, 5, 2};
192 auto r = subset_sum_mitm(vals, 100);
193 EXPECT_FALSE(r.exists);
194}
195
197{
198 // 20 elements to test MITM properly (too many for brute force 2^20 but ok)
200 for (int i = 1; i <= 20; ++i)
201 vals.append(i * 3);
202
203 // Sum of all = 3*(1+...+20) = 3*210 = 630
204 auto r = subset_sum_mitm(vals, 630);
205 EXPECT_TRUE(r.exists);
206
207 // Partial sum
208 auto r2 = subset_sum_mitm(vals, 30); // 3+27=30, or 9+21=30, etc.
209 EXPECT_TRUE(r2.exists);
210
211 int total = 0;
212 for (size_t k = 0; k < r2.selected_indices.size(); ++k)
213 total += vals[r2.selected_indices[k]];
214 EXPECT_EQ(total, 30);
215}
216
218{
219 Array<int> vals = {42};
220 auto r = subset_sum_mitm(vals, 42);
221 EXPECT_TRUE(r.exists);
222 EXPECT_EQ(r.selected_indices.size(), 1u);
223 EXPECT_EQ(r.selected_indices[0], 0u);
224
225 r = subset_sum_mitm(vals, 43);
226 EXPECT_FALSE(r.exists);
227}
228
230{
231 // Compare DP vs MITM on small inputs
232 Array<int> vals = {2, 3, 7, 8, 10};
233
234 for (int target = 0; target <= 30; ++target)
235 {
236 bool dp_ans = subset_sum_exists(vals, target);
237
238 auto mitm_r = subset_sum_mitm(vals, target);
239 EXPECT_EQ(dp_ans, mitm_r.exists) << "Disagreement at target=" << target;
240 }
241}
242
244{
245 std::mt19937 rng(4242);
246 for (int trial = 0; trial < 100; ++trial)
247 {
248 const size_t n = 1 + rng() % 18; // brute-force friendly
250 vals.reserve(n);
251 for (size_t i = 0; i < n; ++i)
252 vals.append(static_cast<int>(rng() % 11)); // non-negative
253
254 const int target = static_cast<int>(rng() % 45);
255
256 const bool exists = subset_sum_exists(vals, target);
257 const size_t count = subset_sum_count(vals, target);
258 const size_t brute_count = brute_subset_count(vals, target);
259
262
263 const auto r = subset_sum(vals, target);
264 EXPECT_EQ(r.exists, brute_count > 0);
265 if (r.exists)
266 EXPECT_TRUE(valid_selection(vals, r.selected_indices, target));
267 }
268}
269
271{
272 std::mt19937 rng(2024);
273 for (int trial = 0; trial < 80; ++trial)
274 {
275 const size_t n = 1 + rng() % 22; // keep brute-force feasible
277 vals.reserve(n);
278 for (size_t i = 0; i < n; ++i)
279 vals.append(static_cast<int>(rng() % 41) - 20); // allow negatives
280
281 const int target = static_cast<int>(rng() % 61) - 30;
282
283 const auto mitm = subset_sum_mitm(vals, target);
284 const bool brute_exists = brute_subset_count(vals, target) > 0;
285 EXPECT_EQ(mitm.exists, brute_exists);
286 if (mitm.exists)
287 EXPECT_TRUE(valid_selection(vals, mitm.selected_indices, target));
288 }
289}
290
292{
294 for (int i = 0; i < 128; ++i)
295 vals.append(1);
296 EXPECT_THROW(subset_sum_mitm(vals, 10), std::out_of_range);
297}
298// satisfy CI policy
299// satisfy CI policy for tpl_bipartite.H and Subset_Sum.H
Subset sum algorithms: classical DP and meet-in-the-middle.
Space-efficient bit array implementation.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
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
Contiguous array of bits.
Definition bitArray.H:201
#define TEST(name)
static mt19937 rng
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
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
bool exists(Container &container, Operation &operation)
Return true if at least one element satisfies a predicate.
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
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
static int * k
gsl_rng * r