From f2ff7828ac999caccb262a37ada679c17ac1dc7c Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Fri, 2 Oct 2026 15:01:39 +0200 Subject: [PATCH 1/8] Add bounded knapsack-augmented cumulative overload checking Extract the advanced Int cumulative propagation from feature/model without its Model or scheduling dependencies. Retain mandatory-subset handling, two-word reachability, transient scratch, and propagation costs. Cover scalar recurrence agreement, residual bit boundaries, variable-capacity cloning, and optional arrays with more than 64 tasks. Document activation limits and include the header in Autotools installs. --- Makefile.in | 1 + changelog.in | 10 + gecode/int.hh | 28 ++ gecode/int/cumulative.hh | 37 +++ gecode/int/cumulative/knapsack-overload.hpp | 223 +++++++++++++++ gecode/int/cumulative/man-prop.hpp | 16 +- gecode/int/cumulative/opt-prop.hpp | 17 ++ test/int/cumulative.cpp | 285 ++++++++++++++++++++ 8 files changed, 616 insertions(+), 1 deletion(-) create mode 100644 gecode/int/cumulative/knapsack-overload.hpp diff --git a/Makefile.in b/Makefile.in index b446405125..db836852b9 100755 --- a/Makefile.in +++ b/Makefile.in @@ -417,6 +417,7 @@ INTHDR0 = \ unary/man-prop.hpp unary/opt-prop.hpp unary/post.hpp \ cumulative.hh cumulative/man-prop.hpp cumulative/opt-prop.hpp \ cumulative/task-view.hpp cumulative/overload.hpp \ + cumulative/knapsack-overload.hpp \ cumulative/time-tabling.hpp cumulative/task.hpp \ cumulative/edge-finding.hpp cumulative/post.hpp \ cumulative/tree.hpp cumulative/limits.hpp \ diff --git a/changelog.in b/changelog.in index 5356b24303..798a9cd439 100755 --- a/changelog.in +++ b/changelog.in @@ -73,6 +73,16 @@ Date: unreleased [DESCRIPTION] This is the development changelog for the next Gecode release. +[ENTRY] +Module: int +What: performance +Rank: major +[DESCRIPTION] +Advanced cumulative propagation uses knapsack-augmented overload checking +to detect conflicts missed by ordinary overload checking. The bounded checker +handles 4 to 64 currently mandatory fixed-processing tasks with positive +demands and resource capacities from 2 to 127. + [RELEASE] Version: 6.4.0 Date: 2026-07-15 diff --git a/gecode/int.hh b/gecode/int.hh index 2b6c2ea796..ac2012ac7c 100755 --- a/gecode/int.hh +++ b/gecode/int.hh @@ -3848,6 +3848,13 @@ namespace Gecode { * - If both flags are combined, all the above listed propagation is * performed. * + * For fixed-processing tasks, advanced propagation also performs + * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, + * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 + * currently mandatory tasks, capacities from 2 to 127, and positive demands + * with at least one non-unit demand. It detects overloads without pruning + * bounds; other task shapes retain the existing propagation. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3907,6 +3914,13 @@ namespace Gecode { * - If both flags are combined, all the above listed propagation is * performed. * + * For fixed-processing tasks, advanced propagation also performs + * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, + * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 + * currently mandatory tasks, capacities from 2 to 127, and positive demands + * with at least one non-unit demand. It detects overloads without pruning + * bounds; other task shapes retain the existing propagation. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3952,6 +3966,13 @@ namespace Gecode { * - If both flags are combined, all the above listed propagation is * performed. * + * For fixed-processing tasks, advanced propagation also performs + * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, + * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 + * currently mandatory tasks, capacities from 2 to 127, and positive demands + * with at least one non-unit demand. It detects overloads without pruning + * bounds; other task shapes retain the existing propagation. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3997,6 +4018,13 @@ namespace Gecode { * - If both flags are combined, all the above listed propagation is * performed. * + * For fixed-processing tasks, advanced propagation also performs + * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, + * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 + * currently mandatory tasks, capacities from 2 to 127, and positive demands + * with at least one non-unit demand. It detects overloads without pruning + * bounds; other task shapes retain the existing propagation. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative diff --git a/gecode/int/cumulative.hh b/gecode/int/cumulative.hh index 647cc00297..3b5f85e412 100644 --- a/gecode/int/cumulative.hh +++ b/gecode/int/cumulative.hh @@ -683,6 +683,36 @@ namespace Gecode { namespace Int { namespace Cumulative { template ExecStatus overload(Space& home, int c, TaskArray& t); + /// Bounded knapsack-augmented overload check (unsupported views are no-op) + template + forceinline ExecStatus + knapsack_overload(Space&, int, TaskArray&) { + return ES_OK; + } + template struct SupportsKnapsackOverload { + static const bool value = false; + }; + template<> struct SupportsKnapsackOverload { + static const bool value = true; + }; + template<> struct SupportsKnapsackOverload { + static const bool value = true; + }; + template<> struct SupportsKnapsackOverload { + static const bool value = true; + }; + template<> struct SupportsKnapsackOverload { + static const bool value = true; + }; + ExecStatus knapsack_overload(Space& home, int c, + TaskArray& t); + ExecStatus knapsack_overload(Space& home, int c, + TaskArray& t); + ExecStatus knapsack_overload(Space& home, int c, + TaskArray& t); + ExecStatus knapsack_overload(Space& home, int c, + TaskArray& t); + /// Perform time-tabling propagation template ExecStatus timetabling(Space& home, Propagator& p, Cap c, @@ -709,6 +739,9 @@ namespace Gecode { namespace Int { namespace Cumulative { /// Constructor for cloning \a p ManProp(Space& home, ManProp& p); public: + /// Return propagation cost, including bounded quadratic KAOC work + virtual PropCost cost(const Space& home, + const ModEventDelta& med) const; /// Perform copying during cloning virtual Actor* copy(Space& home); /// Perform propagation @@ -736,6 +769,9 @@ namespace Gecode { namespace Int { namespace Cumulative { /// Constructor for cloning \a p OptProp(Space& home, OptProp& p); public: + /// Return propagation cost, including bounded quadratic KAOC work + virtual PropCost cost(const Space& home, + const ModEventDelta& med) const; /// Perform copying during cloning virtual Actor* copy(Space& home); /// Perform propagation @@ -761,6 +797,7 @@ namespace Gecode { namespace Int { namespace Cumulative { #include #include #include +#include #include #include #include diff --git a/gecode/int/cumulative/knapsack-overload.hpp b/gecode/int/cumulative/knapsack-overload.hpp new file mode 100644 index 0000000000..ca5c90b621 --- /dev/null +++ b/gecode/int/cumulative/knapsack-overload.hpp @@ -0,0 +1,223 @@ +/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* + * Main authors: + * Mikael Zayenz Lagerkvist + * + * Copyright: + * Mikael Zayenz Lagerkvist, 2026 + * + * This file is part of Gecode, the generic constraint + * development environment: + * http://www.gecode.dev + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +// Knapsack-augmented overload checking from Cloutier and Quimper, +// "Augmenting the Cumulative Overload Check with Integral Resource Usage +// Reasoning", CP 2026, https://doi.org/10.4230/LIPIcs.CP.2026.13. +// Task-count and two-word capacity limits bound the quadratic work and +// transient Region storage; unsupported shapes retain existing propagation. + +namespace Gecode { namespace Int { namespace Cumulative { + + namespace Kaoc { + + struct Bits { + unsigned long long low; + unsigned long long high; + }; + + forceinline void + add(Bits& bits, int demand, int capacity) { + unsigned long long shifted_low = 0ULL; + unsigned long long shifted_high = 0ULL; + if (demand < 64) { + shifted_low = bits.low << demand; + shifted_high = bits.high << demand; + if (demand != 0) + shifted_high |= bits.low >> (64-demand); + } else if (demand < 128) { + shifted_high = bits.low << (demand-64); + } + bits.low |= shifted_low; + bits.high |= shifted_high; + if (capacity < 63) + bits.low &= (1ULL << (capacity+1))-1ULL; + if (capacity < 64) { + bits.high = 0ULL; + } else if (capacity < 127) { + bits.high &= (1ULL << (capacity-63))-1ULL; + } + } + + forceinline int + most_significant(unsigned long long word) { + assert(word != 0ULL); + int bit = 0; + if (word >> 32) { word >>= 32; bit += 32; } + if (word >> 16) { word >>= 16; bit += 16; } + if (word >> 8) { word >>= 8; bit += 8; } + if (word >> 4) { word >>= 4; bit += 4; } + if (word >> 2) { word >>= 2; bit += 2; } + if (word >> 1) { bit += 1; } + return bit; + } + + forceinline unsigned long long + through(int bit) { + assert((bit >= 0) && (bit < 64)); + return bit == 63 ? ~0ULL : (1ULL << (bit+1))-1ULL; + } + + forceinline int + available(const Bits& bits, int residual) { + if (residual <= 0) + return 0; + residual = (std::min)(residual,127); + if (residual >= 64) { + const int high_bit = residual-64; + const unsigned long long high = bits.high & through(high_bit); + if (high != 0ULL) + return 64+most_significant(high); + } + const int low_bit = (std::min)(residual,63); + const unsigned long long low = bits.low & through(low_bit); + return low == 0ULL ? 0 : most_significant(low); + } + + template + bool + conflict(Tasks& tasks, int capacity) { + const int n = tasks.size(); + if ((n < 4) || (n > 64) || + (capacity < 2) || (capacity > 127)) + return false; + bool non_unit = false; + for (int i=0; i capacity)) + return false; + non_unit = non_unit || (tasks[i].c() != 1); + } + if (!non_unit) + return false; + + Region region; + int* order = region.alloc(n); + int* times = region.alloc(4*n); + for (int i=0; i(events); + int* required = region.alloc(events); + Bits* bits = region.alloc(events); + for (int point=0; point capacity) + return true; + } + + int earliest = tasks[order[0]].est(); + for (int prefix=0; prefix= finish)) + continue; + const int right = (std::min)(times[point+1],finish); + const int usable = available(bits[point],capacity-fixed[point]); + overflow = (std::max)(0LL,overflow+ + (static_cast(right)-left) * + static_cast(required[point]-usable)); + } + if (overflow > 0) + return true; + } + return false; + } + + } + + template + forceinline ExecStatus + supported_knapsack_overload(TaskArray& tasks, int capacity) { + return Kaoc::conflict(tasks,capacity) ? ES_FAILED : ES_OK; + } + + forceinline ExecStatus + knapsack_overload(Space&, int c, TaskArray& t) { + return supported_knapsack_overload(t,c); + } + forceinline ExecStatus + knapsack_overload(Space&, int c, TaskArray& t) { + return supported_knapsack_overload(t,c); + } + forceinline ExecStatus + knapsack_overload(Space&, int c, TaskArray& t) { + return supported_knapsack_overload(t,c); + } + forceinline ExecStatus + knapsack_overload(Space&, int c, TaskArray& t) { + return supported_knapsack_overload(t,c); + } + +}}} + +// STATISTICS: int-prop diff --git a/gecode/int/cumulative/man-prop.hpp b/gecode/int/cumulative/man-prop.hpp index 74d5443cc9..21b6815a8b 100755 --- a/gecode/int/cumulative/man-prop.hpp +++ b/gecode/int/cumulative/man-prop.hpp @@ -74,6 +74,17 @@ namespace Gecode { namespace Int { namespace Cumulative { return ES_OK; } + template + PropCost + ManProp::cost(const Space& home, + const ModEventDelta& med) const { + if (PL::advanced && SupportsKnapsackOverload::value && + (t.size() >= 4) && (t.size() <= 64) && + (c.max() >= 2) && (c.max() <= 127)) + return PropCost::quadratic(PropCost::HI,t.size()); + return TaskProp::cost(home,med); + } + template Actor* ManProp::copy(Space& home) { @@ -92,8 +103,11 @@ namespace Gecode { namespace Int { namespace Cumulative { ExecStatus ManProp::propagate(Space& home, const ModEventDelta& med) { // Only bounds changes? - if (IntView::me(med) != ME_INT_DOM) + if (IntView::me(med) != ME_INT_DOM) { GECODE_ES_CHECK(overload(home,c.max(),t)); + if (PL::advanced) + GECODE_ES_CHECK(knapsack_overload(home,c.max(),t)); + } if (PL::advanced) GECODE_ES_CHECK(edgefinding(home,c.max(),t)); diff --git a/gecode/int/cumulative/opt-prop.hpp b/gecode/int/cumulative/opt-prop.hpp index a0c6540606..51df7c4e8e 100755 --- a/gecode/int/cumulative/opt-prop.hpp +++ b/gecode/int/cumulative/opt-prop.hpp @@ -97,6 +97,21 @@ namespace Gecode { namespace Int { namespace Cumulative { return ES_OK; } + template + PropCost + OptProp::cost(const Space& home, + const ModEventDelta& med) const { + if (PL::advanced && SupportsKnapsackOverload::value && + (c.max() >= 2) && (c.max() <= 127)) { + int mandatory = 0; + for (int i=0; i= 4) && (mandatory <= 64)) + return PropCost::quadratic(PropCost::HI,mandatory); + } + return TaskProp::cost(home,med); + } + template Actor* OptProp::copy(Space& home) { @@ -139,6 +154,8 @@ namespace Gecode { namespace Int { namespace Cumulative { if (i > 1) { // Truncate array to only contain mandatory tasks t.size(i); + if (IntView::me(med) != ME_INT_DOM) + GECODE_ES_CHECK(knapsack_overload(home,c.max(),t)); GECODE_ES_CHECK(edgefinding(home,c.max(),t)); // Restore to also include optional tasks t.size(n); diff --git a/test/int/cumulative.cpp b/test/int/cumulative.cpp index 99cddc4df2..ce2267279c 100755 --- a/test/int/cumulative.cpp +++ b/test/int/cumulative.cpp @@ -34,6 +34,10 @@ #include "test/int.hh" #include +#include + +#include +#include namespace Test { namespace Int { @@ -484,6 +488,287 @@ namespace Test { namespace Int { } }; + /// Focused test for bounded knapsack-augmented overload checking + class KnapsackAugmentedOverload : public Test::Base { + private: + struct Task { + int e, l, p, d; + int est(void) const { return e; } + int lst(void) const { return l; } + int ect(void) const { return e+p; } + int lct(void) const { return l+p; } + int c(void) const { return d; } + }; + + static int scalar_available(const std::vector& demands, + int capacity) { + std::vector reachable(static_cast(capacity+1), + false); + reachable[0] = true; + for (int demand : demands) + for (int value=capacity; value>=demand; value--) + reachable[static_cast(value)] = + reachable[static_cast(value)] || + reachable[static_cast(value-demand)]; + for (int value=capacity; value>=0; value--) + if (reachable[static_cast(value)]) + return value; + return 0; + } + + static bool scalar_conflict(const std::vector& tasks, + int capacity) { + std::vector order(tasks.size()); + std::vector times; + for (std::size_t i=0; i(i); + times.push_back(tasks[i].est()); + times.push_back(tasks[i].ect()); + times.push_back(tasks[i].lst()); + times.push_back(tasks[i].lct()); + } + std::sort(order.begin(),order.end(),[&](int a, int b) { + return tasks[static_cast(a)].lct() != + tasks[static_cast(b)].lct() ? + tasks[static_cast(a)].lct() < + tasks[static_cast(b)].lct() : a < b; + }); + std::sort(times.begin(),times.end()); + times.erase(std::unique(times.begin(),times.end()),times.end()); + int earliest = tasks[static_cast(order[0])].est(); + std::vector prefix; + for (int index : order) { + prefix.push_back(index); + earliest = (std::min)(earliest, + tasks[static_cast(index)].est()); + const int finish = tasks[static_cast(index)].lct(); + long long overflow = 0; + for (std::size_t point=0; point+1= finish)) + continue; + int fixed = 0; + int required = 0; + std::vector free; + for (const Task& task : tasks) + if ((task.lst() <= left) && (left < task.ect())) + fixed += task.c(); + if (fixed > capacity) + return true; + for (int member : prefix) { + const Task& task = tasks[static_cast(member)]; + const bool compulsory = + (task.lst() <= left) && (left < task.ect()); + if ((task.est() <= left) && (left < task.lct()) && !compulsory) + free.push_back(task.c()); + if ((task.est() <= left) && + (left < (std::min)(task.ect(),task.lst()))) + required += task.c(); + } + const int right = (std::min)(times[point+1],finish); + overflow = (std::max)(0LL,overflow+ + static_cast(right-left) * + (required-scalar_available(free,capacity-fixed))); + } + if (overflow > 0) + return true; + } + return false; + } + + static bool reference_parity(void) { + std::vector shapes; + for (int est=0; est<=1; est++) + for (int lst=est; lst<=2; lst++) + for (int duration=1; duration<=2; duration++) + for (int demand=1; demand<=3; demand++) + shapes.push_back({est,lst,duration,demand}); + for (std::size_t a=0; a tasks = + {shapes[a],shapes[b],shapes[c],shapes[d]}; + for (int capacity=2; capacity<=3; capacity++) { + bool supported = true; + bool non_unit = false; + for (const Task& task : tasks) { + supported = supported && (task.c() <= capacity); + non_unit = non_unit || (task.c() != 1); + } + if (supported && non_unit && + (Gecode::Int::Cumulative::Kaoc::conflict( + tasks,capacity) != scalar_conflict(tasks,capacity))) + return false; + } + } + return true; + } + + class Fixture : public Gecode::Space { + public: + Gecode::IntVarArray starts; + Fixture(Gecode::IntPropLevel level) + : starts(*this,5,0,6) { + starts[0] = Gecode::IntVar(*this,1,4); + starts[1] = Gecode::IntVar(*this,0,6); + starts[2] = Gecode::IntVar(*this,2,6); + starts[3] = Gecode::IntVar(*this,0,0); + starts[4] = Gecode::IntVar(*this,0,1); + Gecode::cumulative(*this,3,starts, + Gecode::IntArgs({3,1,1,2,4}), + Gecode::IntArgs({3,3,1,2,1}),level); + } + Fixture(Fixture& fixture) : Gecode::Space(fixture) { + starts.update(*this,fixture.starts); + } + virtual Gecode::Space* copy(void) { + return new Fixture(*this); + } + }; + + class VariableCapacityFixture : public Gecode::Space { + public: + Gecode::IntVarArray starts; + Gecode::IntVar capacity; + VariableCapacityFixture(void) + : starts(*this,5,0,6), capacity(*this,3,4) { + starts[0] = Gecode::IntVar(*this,1,4); + starts[1] = Gecode::IntVar(*this,0,6); + starts[2] = Gecode::IntVar(*this,2,6); + starts[3] = Gecode::IntVar(*this,0,0); + starts[4] = Gecode::IntVar(*this,0,1); + Gecode::cumulative(*this,capacity,starts, + Gecode::IntArgs({3,1,1,2,4}), + Gecode::IntArgs({3,3,1,2,1}),Gecode::IPL_ADVANCED); + } + VariableCapacityFixture(VariableCapacityFixture& fixture) + : Gecode::Space(fixture) { + starts.update(*this,fixture.starts); + capacity.update(*this,fixture.capacity); + } + virtual Gecode::Space* copy(void) { + return new VariableCapacityFixture(*this); + } + }; + + static bool variable_capacity_rechecks(void) { + VariableCapacityFixture root; + if (root.status() == Gecode::SS_FAILED) + return false; + std::unique_ptr clone( + static_cast(root.clone())); + Gecode::rel(*clone,clone->capacity,Gecode::IRT_EQ,3); + return clone->status() == Gecode::SS_FAILED; + } + + static bool bit_boundaries(void) { + using Gecode::Int::Cumulative::Kaoc::Bits; + using Gecode::Int::Cumulative::Kaoc::add; + using Gecode::Int::Cumulative::Kaoc::available; + const int capacities[] = {63,64,65,127}; + for (int capacity : capacities) { + for (int first=1; first<=capacity; first+=7) { + Bits bits = {1ULL,0ULL}; + std::vector demands; + for (int demand=first; demand<=capacity; demand+=13) { + add(bits,demand,capacity); + demands.push_back(demand); + for (int residual=0; residual<=capacity; residual++) + if (available(bits,residual) != + scalar_available(demands,residual)) + return false; + } + } + } + Bits gap = {1ULL,0ULL}; + add(gap,4,9); + add(gap,6,9); + return available(gap,9) == 6; + } + + static bool gates_and_optional_subset(void) { + std::vector all_unit(4,Task{0,1,1,1}); + std::vector parity(4,Task{0,5,2,2}); + std::vector too_few(3,Task{0,1,1,2}); + std::vector too_many(65,Task{0,1,1,2}); + std::vector bad_demand(4,Task{0,1,1,1}); + bad_demand[0].d = 4; + if (Gecode::Int::Cumulative::Kaoc::conflict(all_unit,3) || + !Gecode::Int::Cumulative::Kaoc::conflict(parity,3) || + Gecode::Int::Cumulative::Kaoc::conflict(parity,1) || + Gecode::Int::Cumulative::Kaoc::conflict(parity,128) || + Gecode::Int::Cumulative::Kaoc::conflict(too_few,3) || + Gecode::Int::Cumulative::Kaoc::conflict(too_many,3) || + Gecode::Int::Cumulative::Kaoc::conflict(bad_demand,3)) + return false; + + class OptionalSubsetFixture : public Gecode::Space { + public: + OptionalSubsetFixture(Gecode::IntPropLevel level) { + const int n = 69; + Gecode::IntVarArgs starts(n); + Gecode::BoolVarArgs mandatory(n); + Gecode::IntArgs processing(n); + Gecode::IntArgs demand(n); + for (int i=0; i Date: Sat, 3 Oct 2026 08:10:21 +0200 Subject: [PATCH 2/8] Shorten KAOC documentation and integrate algorithm references --- gecode/int.hh | 68 ++++++++++----------- gecode/int/cumulative.hh | 8 ++- gecode/int/cumulative/knapsack-overload.hpp | 7 +-- 3 files changed, 38 insertions(+), 45 deletions(-) diff --git a/gecode/int.hh b/gecode/int.hh index ac2012ac7c..b79a3f03b0 100755 --- a/gecode/int.hh +++ b/gecode/int.hh @@ -3843,18 +3843,12 @@ namespace Gecode { * propagation level \a ipl as follows: * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. - * - If \a IPL_ADVANCED is set, the propagator performs overload checking - * and edge finding. + * - If \a IPL_ADVANCED is set, the propagator performs overload checking, + * edge finding, and knapsack-augmented overload checking for + * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * - * For fixed-processing tasks, advanced propagation also performs - * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, - * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 - * currently mandatory tasks, capacities from 2 to 127, and positive demands - * with at least one non-unit demand. It detects overloads without pruning - * bounds; other task shapes retain the existing propagation. - * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3867,6 +3861,11 @@ namespace Gecode { * resources in O(kn log n). In I. P. Gent, editor, CP, volume 5732 of LNCS, * pages 802-816. Springer, 2009. * + * and + * + * Samuel Cloutier and Claude-Guy Quimper, Augmenting the Cumulative + * Overload Check with Integral Resource Usage Reasoning, CP, 2026. + * * - Throws an exception of type Int::ArgumentSizeMismatch, if \a t, \a s * \a p, or \a u are of different size. * - Throws an exception of type Int::OutOfLimits, if \a p, \a u, or \a c @@ -3909,18 +3908,12 @@ namespace Gecode { * propagation level \a ipl as follows: * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. - * - If \a IPL_ADVANCED is set, the propagator performs overload checking - * and edge finding. + * - If \a IPL_ADVANCED is set, the propagator performs overload checking, + * edge finding, and knapsack-augmented overload checking for + * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * - * For fixed-processing tasks, advanced propagation also performs - * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, - * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 - * currently mandatory tasks, capacities from 2 to 127, and positive demands - * with at least one non-unit demand. It detects overloads without pruning - * bounds; other task shapes retain the existing propagation. - * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3933,6 +3926,11 @@ namespace Gecode { * resources in O(kn log n). In I. P. Gent, editor, CP, volume 5732 of LNCS, * pages 802-816. Springer, 2009. * + * and + * + * Samuel Cloutier and Claude-Guy Quimper, Augmenting the Cumulative + * Overload Check with Integral Resource Usage Reasoning, CP, 2026. + * * - Throws an exception of type Int::ArgumentSizeMismatch, if \a t, \a s * \a p, or \a u are of different size. * - Throws an exception of type Int::OutOfLimits, if \a p, \a u, or \a c @@ -3961,18 +3959,12 @@ namespace Gecode { * propagation level \a ipl as follows: * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. - * - If \a IPL_ADVANCED is set, the propagator performs overload checking - * and edge finding. + * - If \a IPL_ADVANCED is set, the propagator performs overload checking, + * edge finding, and knapsack-augmented overload checking for + * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * - * For fixed-processing tasks, advanced propagation also performs - * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, - * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 - * currently mandatory tasks, capacities from 2 to 127, and positive demands - * with at least one non-unit demand. It detects overloads without pruning - * bounds; other task shapes retain the existing propagation. - * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3985,6 +3977,11 @@ namespace Gecode { * resources in O(kn log n). In I. P. Gent, editor, CP, volume 5732 of LNCS, * pages 802-816. Springer, 2009. * + * and + * + * Samuel Cloutier and Claude-Guy Quimper, Augmenting the Cumulative + * Overload Check with Integral Resource Usage Reasoning, CP, 2026. + * * - Throws an exception of type Int::ArgumentSizeMismatch, if \a s * \a p, or \a u are of different size. * - Throws an exception of type Int::OutOfLimits, if \a p, \a u, or \a c @@ -4013,18 +4010,12 @@ namespace Gecode { * propagation level \a ipl as follows: * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. - * - If \a IPL_ADVANCED is set, the propagator performs overload checking - * and edge finding. + * - If \a IPL_ADVANCED is set, the propagator performs overload checking, + * edge finding, and knapsack-augmented overload checking for + * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * - * For fixed-processing tasks, advanced propagation also performs - * knapsack-augmented overload checking (Cloutier and Quimper, CP 2026, - * https://doi.org/10.4230/LIPIcs.CP.2026.13). This check handles 4 to 64 - * currently mandatory tasks, capacities from 2 to 127, and positive demands - * with at least one non-unit demand. It detects overloads without pruning - * bounds; other task shapes retain the existing propagation. - * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -4037,6 +4028,11 @@ namespace Gecode { * resources in O(kn log n). In I. P. Gent, editor, CP, volume 5732 of LNCS, * pages 802-816. Springer, 2009. * + * and + * + * Samuel Cloutier and Claude-Guy Quimper, Augmenting the Cumulative + * Overload Check with Integral Resource Usage Reasoning, CP, 2026. + * * - Throws an exception of type Int::ArgumentSizeMismatch, if \a s, * \a p, \a u, or \a m are of different size. * - Throws an exception of type Int::OutOfLimits, if \a p, \a u, or \a c diff --git a/gecode/int/cumulative.hh b/gecode/int/cumulative.hh index 3b5f85e412..45606adcd5 100644 --- a/gecode/int/cumulative.hh +++ b/gecode/int/cumulative.hh @@ -48,6 +48,8 @@ * Cumulative Resources, CP-AI-OR, 2009. * Petr Vilím, Edge Finding Filtering Algorithm for Discrete * Cumulative Resources in O(kn log n), CP, 2009. + * Samuel Cloutier and Claude-Guy Quimper, Augmenting the Cumulative + * Overload Check with Integral Resource Usage Reasoning, CP, 2026. * * \brief %Scheduling for cumulative resources */ @@ -683,7 +685,7 @@ namespace Gecode { namespace Int { namespace Cumulative { template ExecStatus overload(Space& home, int c, TaskArray& t); - /// Bounded knapsack-augmented overload check (unsupported views are no-op) + /// Perform knapsack-augmented overload checking template forceinline ExecStatus knapsack_overload(Space&, int, TaskArray&) { @@ -739,7 +741,7 @@ namespace Gecode { namespace Int { namespace Cumulative { /// Constructor for cloning \a p ManProp(Space& home, ManProp& p); public: - /// Return propagation cost, including bounded quadratic KAOC work + /// Return propagation cost virtual PropCost cost(const Space& home, const ModEventDelta& med) const; /// Perform copying during cloning @@ -769,7 +771,7 @@ namespace Gecode { namespace Int { namespace Cumulative { /// Constructor for cloning \a p OptProp(Space& home, OptProp& p); public: - /// Return propagation cost, including bounded quadratic KAOC work + /// Return propagation cost virtual PropCost cost(const Space& home, const ModEventDelta& med) const; /// Perform copying during cloning diff --git a/gecode/int/cumulative/knapsack-overload.hpp b/gecode/int/cumulative/knapsack-overload.hpp index ca5c90b621..cbdead3814 100644 --- a/gecode/int/cumulative/knapsack-overload.hpp +++ b/gecode/int/cumulative/knapsack-overload.hpp @@ -31,14 +31,9 @@ * */ -// Knapsack-augmented overload checking from Cloutier and Quimper, -// "Augmenting the Cumulative Overload Check with Integral Resource Usage -// Reasoning", CP 2026, https://doi.org/10.4230/LIPIcs.CP.2026.13. -// Task-count and two-word capacity limits bound the quadratic work and -// transient Region storage; unsupported shapes retain existing propagation. - namespace Gecode { namespace Int { namespace Cumulative { + // Knapsack-augmented overload checking namespace Kaoc { struct Bits { From 90c97cb225517cad007bf360d77082d18515caed Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Sat, 3 Oct 2026 08:17:32 +0200 Subject: [PATCH 3/8] Simplify KAOC changelog entry and cite source paper --- changelog.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/changelog.in b/changelog.in index 798a9cd439..7bf30eb658 100755 --- a/changelog.in +++ b/changelog.in @@ -79,9 +79,10 @@ What: performance Rank: major [DESCRIPTION] Advanced cumulative propagation uses knapsack-augmented overload checking -to detect conflicts missed by ordinary overload checking. The bounded checker -handles 4 to 64 currently mandatory fixed-processing tasks with positive -demands and resource capacities from 2 to 127. +for fixed-processing tasks to detect conflicts missed by ordinary overload +checking. The algorithm is from Samuel Cloutier and Claude-Guy Quimper, +Augmenting the Cumulative Overload Check with Integral Resource Usage +Reasoning, CP 2026 (https://doi.org/10.4230/LIPIcs.CP.2026.13). [RELEASE] Version: 6.4.0 From 184f76dd6266b31d187b153d4771fe240cafe218 Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Sat, 3 Oct 2026 08:19:15 +0200 Subject: [PATCH 4/8] Match existing changelog citation style for KAOC --- changelog.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.in b/changelog.in index 7bf30eb658..36e8df1317 100755 --- a/changelog.in +++ b/changelog.in @@ -80,9 +80,9 @@ Rank: major [DESCRIPTION] Advanced cumulative propagation uses knapsack-augmented overload checking for fixed-processing tasks to detect conflicts missed by ordinary overload -checking. The algorithm is from Samuel Cloutier and Claude-Guy Quimper, -Augmenting the Cumulative Overload Check with Integral Resource Usage -Reasoning, CP 2026 (https://doi.org/10.4230/LIPIcs.CP.2026.13). +checking. The algorithm is described in: +S. Cloutier, C.-G. Quimper, Augmenting the Cumulative Overload Check +with Integral Resource Usage Reasoning, CP 2026. [RELEASE] Version: 6.4.0 From 7bd8aa8cb75ffb1efe2582caa4e8406470d5e6d1 Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Sun, 4 Oct 2026 15:09:26 +0200 Subject: [PATCH 5/8] Restrict knapsack overload checking to fixed durations --- changelog.in | 6 +-- gecode/int.hh | 32 +++++++++++++-- gecode/int/cumulative/knapsack-overload.hpp | 15 ++++++- test/int/cumulative.cpp | 43 ++++++++++++++++++--- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/changelog.in b/changelog.in index 36e8df1317..f54708f43d 100755 --- a/changelog.in +++ b/changelog.in @@ -78,9 +78,9 @@ Module: int What: performance Rank: major [DESCRIPTION] -Advanced cumulative propagation uses knapsack-augmented overload checking -for fixed-processing tasks to detect conflicts missed by ordinary overload -checking. The algorithm is described in: +Advanced cumulative propagation uses bounded knapsack-augmented overload +checking for fixed-processing tasks to detect conflicts missed by ordinary +overload checking. The algorithm is described in: S. Cloutier, C.-G. Quimper, Augmenting the Cumulative Overload Check with Integral Resource Usage Reasoning, CP 2026. diff --git a/gecode/int.hh b/gecode/int.hh index b79a3f03b0..7604f13c68 100755 --- a/gecode/int.hh +++ b/gecode/int.hh @@ -3844,11 +3844,17 @@ namespace Gecode { * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. * - If \a IPL_ADVANCED is set, the propagator performs overload checking, - * edge finding, and knapsack-augmented overload checking for + * edge finding, and bounded knapsack-augmented overload checking for * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * + * The knapsack check runs for 4 to 64 participating tasks when the + * current capacity upper bound is between 2 and 127. Each task must have + * a fixed processing time. Each demand must be positive and at most that + * bound, with at least one demand above 1. + * Outside these limits, only the knapsack check is skipped. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3909,11 +3915,17 @@ namespace Gecode { * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. * - If \a IPL_ADVANCED is set, the propagator performs overload checking, - * edge finding, and knapsack-augmented overload checking for + * edge finding, and bounded knapsack-augmented overload checking for * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * + * The knapsack check considers only currently mandatory tasks. It runs + * for 4 to 64 such tasks when the current capacity upper bound is between + * 2 and 127. Each task must have a fixed processing time. Each demand must + * be positive and at most that bound, with at least one demand above 1. + * Outside these limits, only the knapsack check is skipped. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -3960,11 +3972,17 @@ namespace Gecode { * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. * - If \a IPL_ADVANCED is set, the propagator performs overload checking, - * edge finding, and knapsack-augmented overload checking for + * edge finding, and bounded knapsack-augmented overload checking for * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * + * The knapsack check runs for 4 to 64 participating tasks when the + * current capacity upper bound is between 2 and 127. Each task must have + * a fixed processing time. Each demand must be positive and at most that + * bound, with at least one demand above 1. + * Outside these limits, only the knapsack check is skipped. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative @@ -4011,11 +4029,17 @@ namespace Gecode { * - If \a IPL_BASIC is set, the propagator performs overload checking * and time-tabling propagation. * - If \a IPL_ADVANCED is set, the propagator performs overload checking, - * edge finding, and knapsack-augmented overload checking for + * edge finding, and bounded knapsack-augmented overload checking for * fixed-processing tasks. * - If both flags are combined, all the above listed propagation is * performed. * + * The knapsack check considers only currently mandatory tasks. It runs + * for 4 to 64 such tasks when the current capacity upper bound is between + * 2 and 127. Each task must have a fixed processing time. Each demand must + * be positive and at most that bound, with at least one demand above 1. + * Outside these limits, only the knapsack check is skipped. + * * The propagator uses algorithms taken from: * * Petr Vilím, Max Energy Filtering Algorithm for Discrete Cumulative diff --git a/gecode/int/cumulative/knapsack-overload.hpp b/gecode/int/cumulative/knapsack-overload.hpp index cbdead3814..6947f0e54c 100644 --- a/gecode/int/cumulative/knapsack-overload.hpp +++ b/gecode/int/cumulative/knapsack-overload.hpp @@ -83,8 +83,9 @@ namespace Gecode { namespace Int { namespace Cumulative { return bit == 63 ? ~0ULL : (1ULL << (bit+1))-1ULL; } + /// Return the greatest reachable subset demand at most \a residual forceinline int - available(const Bits& bits, int residual) { + max_reachable(const Bits& bits, int residual) { if (residual <= 0) return 0; residual = (std::min)(residual,127); @@ -108,6 +109,10 @@ namespace Gecode { namespace Int { namespace Cumulative { return false; bool non_unit = false; for (int i=0; i(tasks[i].ect())-tasks[i].est()) != + (static_cast(tasks[i].lct())-tasks[i].lst())) + return false; if ((tasks[i].c() <= 0) || (tasks[i].c() > capacity)) return false; non_unit = non_unit || (tasks[i].c() != 1); @@ -138,6 +143,7 @@ namespace Gecode { namespace Int { namespace Cumulative { if (events < 2) return false; + // Compulsory demand from all tasks, independent of the current prefix. int* fixed = region.alloc(events); int* required = region.alloc(events); Bits* bits = region.alloc(events); @@ -154,6 +160,9 @@ namespace Gecode { namespace Int { namespace Cumulative { return true; } + // Extend the prefix in deadline order. At each event, bits contains + // reachable demands of prefix tasks outside their compulsory parts; + // required records their earliest-start demand outside those parts. int earliest = tasks[order[0]].est(); for (int prefix=0; prefix= finish)) continue; const int right = (std::min)(times[point+1],finish); - const int usable = available(bits[point],capacity-fixed[point]); + const int usable = max_reachable(bits[point],capacity-fixed[point]); overflow = (std::max)(0LL,overflow+ (static_cast(right)-left) * static_cast(required[point]-usable)); diff --git a/test/int/cumulative.cpp b/test/int/cumulative.cpp index ce2267279c..a1e8dd07b5 100755 --- a/test/int/cumulative.cpp +++ b/test/int/cumulative.cpp @@ -662,10 +662,41 @@ namespace Test { namespace Int { return clone->status() == Gecode::SS_FAILED; } + static bool fixed_end_feasible(void) { + class FixedEndFixture : public Gecode::Space { + public: + Gecode::IntVarArray starts; + FixedEndFixture(void) : starts(*this,4) { + Gecode::IntArgs ends({10,20,30,40}); + Gecode::TaskTypeArgs types(4); + for (int i=0; i<4; i++) { + starts[i] = Gecode::IntVar(*this,0,ends[i]-1); + types[i] = Gecode::TT_FIXE; + } + Gecode::cumulative(*this,4,types,starts,ends, + Gecode::IntArgs({2,2,2,2}),Gecode::IPL_ADVANCED); + } + FixedEndFixture(FixedEndFixture& fixture) : Gecode::Space(fixture) { + starts.update(*this,fixture.starts); + } + virtual Gecode::Space* copy(void) { + return new FixedEndFixture(*this); + } + }; + + FixedEndFixture fixture; + if (fixture.status() == Gecode::SS_FAILED) + return false; + // Each task can run for one unit immediately before its fixed end. + for (int i=0; i<4; i++) + Gecode::rel(fixture,fixture.starts[i],Gecode::IRT_EQ,10*(i+1)-1); + return fixture.status() != Gecode::SS_FAILED; + } + static bool bit_boundaries(void) { using Gecode::Int::Cumulative::Kaoc::Bits; using Gecode::Int::Cumulative::Kaoc::add; - using Gecode::Int::Cumulative::Kaoc::available; + using Gecode::Int::Cumulative::Kaoc::max_reachable; const int capacities[] = {63,64,65,127}; for (int capacity : capacities) { for (int first=1; first<=capacity; first+=7) { @@ -675,7 +706,7 @@ namespace Test { namespace Int { add(bits,demand,capacity); demands.push_back(demand); for (int residual=0; residual<=capacity; residual++) - if (available(bits,residual) != + if (max_reachable(bits,residual) != scalar_available(demands,residual)) return false; } @@ -684,7 +715,7 @@ namespace Test { namespace Int { Bits gap = {1ULL,0ULL}; add(gap,4,9); add(gap,6,9); - return available(gap,9) == 6; + return max_reachable(gap,9) == 6; } static bool gates_and_optional_subset(void) { @@ -752,17 +783,19 @@ namespace Test { namespace Int { const bool boundaries = bit_boundaries(); const bool parity = reference_parity(); const bool variable = variable_capacity_rechecks(); + const bool fixed_end = fixed_end_feasible(); const bool gates = gates_and_optional_subset(); const bool basic_ok = basic.status() != Gecode::SS_FAILED; const bool advanced_ok = advanced.status() == Gecode::SS_FAILED; - if (!(boundaries && parity && variable && gates && + if (!(boundaries && parity && variable && fixed_end && gates && basic_ok && advanced_ok)) std::cerr << "kaoc boundaries=" << boundaries << " parity=" << parity << " variable=" << variable + << " fixed_end=" << fixed_end << " gates=" << gates << " basic=" << basic_ok << " advanced=" << advanced_ok << "\n"; - return boundaries && parity && variable && gates && + return boundaries && parity && variable && fixed_end && gates && basic_ok && advanced_ok; } }; From 6d13928aacd93ca2cb0e0d085c681c40739fe60e Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Mon, 5 Oct 2026 08:27:51 +0200 Subject: [PATCH 6/8] Track knapsack cumulative headers in Autoconf dependencies --- Makefile.dep | 184 +++++++++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 86 deletions(-) diff --git a/Makefile.dep b/Makefile.dep index 1f26262fd6..f698e5c428 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -3901,76 +3901,76 @@ gecode/int/cumulative$(OBJSUFFIX) gecode/int/cumulative$(SBJSUFFIX): \ ./gecode/int/branch.hpp ./gecode/int/branch/action.hpp ./gecode/int/branch/afc.hpp \ ./gecode/int/branch/assign.hpp ./gecode/int/branch/chb.hpp ./gecode/int/branch/traits.hpp \ ./gecode/int/branch/val.hpp ./gecode/int/branch/var.hpp ./gecode/int/channel.hpp \ - ./gecode/int/cumulative.hh ./gecode/int/cumulative/edge-finding.hpp ./gecode/int/cumulative/limits.hpp \ - ./gecode/int/cumulative/man-prop.hpp ./gecode/int/cumulative/opt-prop.hpp ./gecode/int/cumulative/overload.hpp \ - ./gecode/int/cumulative/post.hpp ./gecode/int/cumulative/subsumption.hpp ./gecode/int/cumulative/task-view.hpp \ - ./gecode/int/cumulative/task.hpp ./gecode/int/cumulative/time-tabling.hpp ./gecode/int/cumulative/tree.hpp \ - ./gecode/int/div.hh ./gecode/int/div.hpp ./gecode/int/exception.hpp \ - ./gecode/int/extensional.hpp ./gecode/int/extensional/dfa.hpp ./gecode/int/extensional/tuple-set.hpp \ - ./gecode/int/int-set-1.hpp ./gecode/int/int-set-2.hpp ./gecode/int/ipl.hpp \ - ./gecode/int/irt.hpp ./gecode/int/limits.hpp ./gecode/int/propagator.hpp \ - ./gecode/int/reify.hpp ./gecode/int/task.hh ./gecode/int/task/array.hpp \ - ./gecode/int/task/event.hpp ./gecode/int/task/fwd-to-bwd.hpp ./gecode/int/task/iter.hpp \ - ./gecode/int/task/man-to-opt.hpp ./gecode/int/task/prop.hpp ./gecode/int/task/purge.hpp \ - ./gecode/int/task/sort.hpp ./gecode/int/task/tree.hpp ./gecode/int/trace.hpp \ - ./gecode/int/trace/bool-delta.hpp ./gecode/int/trace/bool-trace-view.hpp ./gecode/int/trace/int-delta.hpp \ - ./gecode/int/trace/int-trace-view.hpp ./gecode/int/trace/traits.hpp ./gecode/int/unary.hh \ - ./gecode/int/unary/detectable.hpp ./gecode/int/unary/edge-finding.hpp ./gecode/int/unary/man-prop.hpp \ - ./gecode/int/unary/not-first-not-last.hpp ./gecode/int/unary/opt-prop.hpp ./gecode/int/unary/overload.hpp \ - ./gecode/int/unary/post.hpp ./gecode/int/unary/subsumption.hpp ./gecode/int/unary/task-view.hpp \ - ./gecode/int/unary/task.hpp ./gecode/int/unary/time-tabling.hpp ./gecode/int/unary/tree.hpp \ - ./gecode/int/var-imp.hpp ./gecode/int/var-imp/bool.hpp ./gecode/int/var-imp/delta.hpp \ - ./gecode/int/var-imp/int.hpp ./gecode/int/var/bool.hpp ./gecode/int/var/int.hpp \ - ./gecode/int/var/print.hpp ./gecode/int/view.hpp ./gecode/int/view/bool-test.hpp \ - ./gecode/int/view/bool.hpp ./gecode/int/view/cached.hpp ./gecode/int/view/constint.hpp \ - ./gecode/int/view/int.hpp ./gecode/int/view/iter.hpp ./gecode/int/view/minus.hpp \ - ./gecode/int/view/neg-bool.hpp ./gecode/int/view/offset.hpp ./gecode/int/view/print.hpp \ - ./gecode/int/view/rel-test.hpp ./gecode/int/view/scale.hpp ./gecode/int/view/zero.hpp \ - ./gecode/iter.hh ./gecode/iter/ranges-add.hpp ./gecode/iter/ranges-append.hpp \ - ./gecode/iter/ranges-array.hpp ./gecode/iter/ranges-cache.hpp ./gecode/iter/ranges-compl.hpp \ - ./gecode/iter/ranges-diff.hpp ./gecode/iter/ranges-empty.hpp ./gecode/iter/ranges-inter.hpp \ - ./gecode/iter/ranges-list.hpp ./gecode/iter/ranges-map.hpp ./gecode/iter/ranges-minmax.hpp \ - ./gecode/iter/ranges-minus.hpp ./gecode/iter/ranges-negative.hpp ./gecode/iter/ranges-offset.hpp \ - ./gecode/iter/ranges-operations.hpp ./gecode/iter/ranges-positive.hpp ./gecode/iter/ranges-rangelist.hpp \ - ./gecode/iter/ranges-scale.hpp ./gecode/iter/ranges-singleton-append.hpp ./gecode/iter/ranges-singleton.hpp \ - ./gecode/iter/ranges-size.hpp ./gecode/iter/ranges-union.hpp ./gecode/iter/ranges-values.hpp \ - ./gecode/iter/values-array.hpp ./gecode/iter/values-bitset.hpp ./gecode/iter/values-bitsetoffset.hpp \ - ./gecode/iter/values-inter.hpp ./gecode/iter/values-list.hpp ./gecode/iter/values-map.hpp \ - ./gecode/iter/values-minus.hpp ./gecode/iter/values-negative.hpp ./gecode/iter/values-offset.hpp \ - ./gecode/iter/values-positive.hpp ./gecode/iter/values-ranges.hpp ./gecode/iter/values-singleton.hpp \ - ./gecode/iter/values-union.hpp ./gecode/iter/values-unique.hpp ./gecode/kernel.hh \ - ./gecode/kernel/archive.hpp ./gecode/kernel/branch/action.hpp ./gecode/kernel/branch/afc.hpp \ - ./gecode/kernel/branch/chb.hpp ./gecode/kernel/branch/filter.hpp ./gecode/kernel/branch/merit.hpp \ - ./gecode/kernel/branch/print.hpp ./gecode/kernel/branch/tiebreak.hpp ./gecode/kernel/branch/traits.hpp \ - ./gecode/kernel/branch/val-commit.hpp ./gecode/kernel/branch/val-sel-commit.hpp ./gecode/kernel/branch/val-sel.hpp \ - ./gecode/kernel/branch/val.hpp ./gecode/kernel/branch/var.hpp ./gecode/kernel/branch/view-sel.hpp \ - ./gecode/kernel/branch/view-val.hpp ./gecode/kernel/branch/view.hpp ./gecode/kernel/core.hpp \ - ./gecode/kernel/data/array.hpp ./gecode/kernel/data/rnd.hpp ./gecode/kernel/data/shared-array.hpp \ - ./gecode/kernel/data/shared-data.hpp ./gecode/kernel/exception.hpp ./gecode/kernel/gpi.hpp \ - ./gecode/kernel/macros.hpp ./gecode/kernel/memory/allocators.hpp ./gecode/kernel/memory/config.hpp \ - ./gecode/kernel/memory/manager.hpp ./gecode/kernel/memory/region.hpp ./gecode/kernel/modevent.hpp \ - ./gecode/kernel/propagator/advisor.hpp ./gecode/kernel/propagator/pattern.hpp ./gecode/kernel/propagator/subscribed.hpp \ - ./gecode/kernel/propagator/wait.hpp ./gecode/kernel/range-list.hpp ./gecode/kernel/shared-object.hpp \ - ./gecode/kernel/shared-space-data.hpp ./gecode/kernel/trace/filter.hpp ./gecode/kernel/trace/general.hpp \ - ./gecode/kernel/trace/print.hpp ./gecode/kernel/trace/recorder.hpp ./gecode/kernel/trace/tracer.hpp \ - ./gecode/kernel/trace/traits.hpp gecode/kernel/var-imp.hpp gecode/kernel/var-type.hpp \ - ./gecode/kernel/var.hpp ./gecode/kernel/view.hpp ./gecode/search.hh \ - ./gecode/search/bab.hpp ./gecode/search/base.hpp ./gecode/search/build.hpp \ - ./gecode/search/cutoff.hpp ./gecode/search/dfs.hpp ./gecode/search/engine.hpp \ - ./gecode/search/exception.hpp ./gecode/search/lds.hpp ./gecode/search/options.hpp \ - ./gecode/search/pbs.hpp ./gecode/search/rbs.hpp ./gecode/search/sebs.hpp \ - ./gecode/search/seq/dead.hh ./gecode/search/statistics.hpp ./gecode/search/stop.hpp \ - ./gecode/search/support.hh ./gecode/search/trace-recorder.hpp ./gecode/search/tracer.hpp \ - ./gecode/search/traits.hpp ./gecode/support.hh ./gecode/support/allocator.hpp \ - ./gecode/support/auto-link.hpp ./gecode/support/bitset-base.hpp ./gecode/support/bitset-offset.hpp \ - ./gecode/support/bitset.hpp ./gecode/support/block-allocator.hpp ./gecode/support/cast.hpp \ - ./gecode/support/config.hpp ./gecode/support/dynamic-array.hpp ./gecode/support/dynamic-queue.hpp \ - ./gecode/support/dynamic-stack.hpp ./gecode/support/exception.hpp ./gecode/support/hash.hpp \ - ./gecode/support/heap.hpp ./gecode/support/hw-rnd.hpp ./gecode/support/int-type.hpp \ - ./gecode/support/macros.hpp ./gecode/support/marked-pointer.hpp ./gecode/support/random.hpp \ - ./gecode/support/ref-count.hpp ./gecode/support/run-jobs.hpp ./gecode/support/sort.hpp \ - ./gecode/support/static-stack.hpp ./gecode/support/thread.hpp ./gecode/support/thread/thread.hpp \ - ./gecode/support/timer.hpp + ./gecode/int/cumulative.hh ./gecode/int/cumulative/edge-finding.hpp ./gecode/int/cumulative/knapsack-overload.hpp \ + ./gecode/int/cumulative/limits.hpp ./gecode/int/cumulative/man-prop.hpp ./gecode/int/cumulative/opt-prop.hpp \ + ./gecode/int/cumulative/overload.hpp ./gecode/int/cumulative/post.hpp ./gecode/int/cumulative/subsumption.hpp \ + ./gecode/int/cumulative/task-view.hpp ./gecode/int/cumulative/task.hpp ./gecode/int/cumulative/time-tabling.hpp \ + ./gecode/int/cumulative/tree.hpp ./gecode/int/div.hh ./gecode/int/div.hpp \ + ./gecode/int/exception.hpp ./gecode/int/extensional.hpp ./gecode/int/extensional/dfa.hpp \ + ./gecode/int/extensional/tuple-set.hpp ./gecode/int/int-set-1.hpp ./gecode/int/int-set-2.hpp \ + ./gecode/int/ipl.hpp ./gecode/int/irt.hpp ./gecode/int/limits.hpp \ + ./gecode/int/propagator.hpp ./gecode/int/reify.hpp ./gecode/int/task.hh \ + ./gecode/int/task/array.hpp ./gecode/int/task/event.hpp ./gecode/int/task/fwd-to-bwd.hpp \ + ./gecode/int/task/iter.hpp ./gecode/int/task/man-to-opt.hpp ./gecode/int/task/prop.hpp \ + ./gecode/int/task/purge.hpp ./gecode/int/task/sort.hpp ./gecode/int/task/tree.hpp \ + ./gecode/int/trace.hpp ./gecode/int/trace/bool-delta.hpp ./gecode/int/trace/bool-trace-view.hpp \ + ./gecode/int/trace/int-delta.hpp ./gecode/int/trace/int-trace-view.hpp ./gecode/int/trace/traits.hpp \ + ./gecode/int/unary.hh ./gecode/int/unary/detectable.hpp ./gecode/int/unary/edge-finding.hpp \ + ./gecode/int/unary/man-prop.hpp ./gecode/int/unary/not-first-not-last.hpp ./gecode/int/unary/opt-prop.hpp \ + ./gecode/int/unary/overload.hpp ./gecode/int/unary/post.hpp ./gecode/int/unary/subsumption.hpp \ + ./gecode/int/unary/task-view.hpp ./gecode/int/unary/task.hpp ./gecode/int/unary/time-tabling.hpp \ + ./gecode/int/unary/tree.hpp ./gecode/int/var-imp.hpp ./gecode/int/var-imp/bool.hpp \ + ./gecode/int/var-imp/delta.hpp ./gecode/int/var-imp/int.hpp ./gecode/int/var/bool.hpp \ + ./gecode/int/var/int.hpp ./gecode/int/var/print.hpp ./gecode/int/view.hpp \ + ./gecode/int/view/bool-test.hpp ./gecode/int/view/bool.hpp ./gecode/int/view/cached.hpp \ + ./gecode/int/view/constint.hpp ./gecode/int/view/int.hpp ./gecode/int/view/iter.hpp \ + ./gecode/int/view/minus.hpp ./gecode/int/view/neg-bool.hpp ./gecode/int/view/offset.hpp \ + ./gecode/int/view/print.hpp ./gecode/int/view/rel-test.hpp ./gecode/int/view/scale.hpp \ + ./gecode/int/view/zero.hpp ./gecode/iter.hh ./gecode/iter/ranges-add.hpp \ + ./gecode/iter/ranges-append.hpp ./gecode/iter/ranges-array.hpp ./gecode/iter/ranges-cache.hpp \ + ./gecode/iter/ranges-compl.hpp ./gecode/iter/ranges-diff.hpp ./gecode/iter/ranges-empty.hpp \ + ./gecode/iter/ranges-inter.hpp ./gecode/iter/ranges-list.hpp ./gecode/iter/ranges-map.hpp \ + ./gecode/iter/ranges-minmax.hpp ./gecode/iter/ranges-minus.hpp ./gecode/iter/ranges-negative.hpp \ + ./gecode/iter/ranges-offset.hpp ./gecode/iter/ranges-operations.hpp ./gecode/iter/ranges-positive.hpp \ + ./gecode/iter/ranges-rangelist.hpp ./gecode/iter/ranges-scale.hpp ./gecode/iter/ranges-singleton-append.hpp \ + ./gecode/iter/ranges-singleton.hpp ./gecode/iter/ranges-size.hpp ./gecode/iter/ranges-union.hpp \ + ./gecode/iter/ranges-values.hpp ./gecode/iter/values-array.hpp ./gecode/iter/values-bitset.hpp \ + ./gecode/iter/values-bitsetoffset.hpp ./gecode/iter/values-inter.hpp ./gecode/iter/values-list.hpp \ + ./gecode/iter/values-map.hpp ./gecode/iter/values-minus.hpp ./gecode/iter/values-negative.hpp \ + ./gecode/iter/values-offset.hpp ./gecode/iter/values-positive.hpp ./gecode/iter/values-ranges.hpp \ + ./gecode/iter/values-singleton.hpp ./gecode/iter/values-union.hpp ./gecode/iter/values-unique.hpp \ + ./gecode/kernel.hh ./gecode/kernel/archive.hpp ./gecode/kernel/branch/action.hpp \ + ./gecode/kernel/branch/afc.hpp ./gecode/kernel/branch/chb.hpp ./gecode/kernel/branch/filter.hpp \ + ./gecode/kernel/branch/merit.hpp ./gecode/kernel/branch/print.hpp ./gecode/kernel/branch/tiebreak.hpp \ + ./gecode/kernel/branch/traits.hpp ./gecode/kernel/branch/val-commit.hpp ./gecode/kernel/branch/val-sel-commit.hpp \ + ./gecode/kernel/branch/val-sel.hpp ./gecode/kernel/branch/val.hpp ./gecode/kernel/branch/var.hpp \ + ./gecode/kernel/branch/view-sel.hpp ./gecode/kernel/branch/view-val.hpp ./gecode/kernel/branch/view.hpp \ + ./gecode/kernel/core.hpp ./gecode/kernel/data/array.hpp ./gecode/kernel/data/rnd.hpp \ + ./gecode/kernel/data/shared-array.hpp ./gecode/kernel/data/shared-data.hpp ./gecode/kernel/exception.hpp \ + ./gecode/kernel/gpi.hpp ./gecode/kernel/macros.hpp ./gecode/kernel/memory/allocators.hpp \ + ./gecode/kernel/memory/config.hpp ./gecode/kernel/memory/manager.hpp ./gecode/kernel/memory/region.hpp \ + ./gecode/kernel/modevent.hpp ./gecode/kernel/propagator/advisor.hpp ./gecode/kernel/propagator/pattern.hpp \ + ./gecode/kernel/propagator/subscribed.hpp ./gecode/kernel/propagator/wait.hpp ./gecode/kernel/range-list.hpp \ + ./gecode/kernel/shared-object.hpp ./gecode/kernel/shared-space-data.hpp ./gecode/kernel/trace/filter.hpp \ + ./gecode/kernel/trace/general.hpp ./gecode/kernel/trace/print.hpp ./gecode/kernel/trace/recorder.hpp \ + ./gecode/kernel/trace/tracer.hpp ./gecode/kernel/trace/traits.hpp ./gecode/kernel/var-imp.hpp \ + ./gecode/kernel/var-type.hpp ./gecode/kernel/var.hpp ./gecode/kernel/view.hpp \ + ./gecode/search.hh ./gecode/search/bab.hpp ./gecode/search/base.hpp \ + ./gecode/search/build.hpp ./gecode/search/cutoff.hpp ./gecode/search/dfs.hpp \ + ./gecode/search/engine.hpp ./gecode/search/exception.hpp ./gecode/search/lds.hpp \ + ./gecode/search/options.hpp ./gecode/search/pbs.hpp ./gecode/search/rbs.hpp \ + ./gecode/search/sebs.hpp ./gecode/search/seq/dead.hh ./gecode/search/statistics.hpp \ + ./gecode/search/stop.hpp ./gecode/search/support.hh ./gecode/search/trace-recorder.hpp \ + ./gecode/search/tracer.hpp ./gecode/search/traits.hpp ./gecode/support.hh \ + ./gecode/support/allocator.hpp ./gecode/support/auto-link.hpp ./gecode/support/bitset-base.hpp \ + ./gecode/support/bitset-offset.hpp ./gecode/support/bitset.hpp ./gecode/support/block-allocator.hpp \ + ./gecode/support/cast.hpp gecode/support/config.hpp ./gecode/support/dynamic-array.hpp \ + ./gecode/support/dynamic-queue.hpp ./gecode/support/dynamic-stack.hpp ./gecode/support/exception.hpp \ + ./gecode/support/failpoint.hpp ./gecode/support/hash.hpp ./gecode/support/heap.hpp \ + ./gecode/support/hw-rnd.hpp ./gecode/support/int-type.hpp ./gecode/support/macros.hpp \ + ./gecode/support/marked-pointer.hpp ./gecode/support/random.hpp ./gecode/support/ref-count.hpp \ + ./gecode/support/run-jobs.hpp ./gecode/support/sort.hpp ./gecode/support/static-stack.hpp \ + ./gecode/support/thread.hpp ./gecode/support/thread/thread.hpp ./gecode/support/timer.hpp gecode/int/cumulatives$(OBJSUFFIX) gecode/int/cumulatives$(SBJSUFFIX): \ ./gecode/int.hh ./gecode/int/array-traits.hpp ./gecode/int/array.hpp \ ./gecode/int/branch.hpp ./gecode/int/branch/action.hpp ./gecode/int/branch/afc.hpp \ @@ -21279,13 +21279,25 @@ test/int/cumulative$(OBJSUFFIX) test/int/cumulative$(SBJSUFFIX): \ ./gecode/int/array.hpp ./gecode/int/branch.hpp ./gecode/int/branch/action.hpp \ ./gecode/int/branch/afc.hpp ./gecode/int/branch/assign.hpp ./gecode/int/branch/chb.hpp \ ./gecode/int/branch/traits.hpp ./gecode/int/branch/val.hpp ./gecode/int/branch/var.hpp \ - ./gecode/int/channel.hpp ./gecode/int/div.hh ./gecode/int/div.hpp \ - ./gecode/int/exception.hpp ./gecode/int/extensional.hpp ./gecode/int/extensional/dfa.hpp \ - ./gecode/int/extensional/tuple-set.hpp ./gecode/int/int-set-1.hpp ./gecode/int/int-set-2.hpp \ - ./gecode/int/ipl.hpp ./gecode/int/irt.hpp ./gecode/int/limits.hpp \ - ./gecode/int/propagator.hpp ./gecode/int/reify.hpp ./gecode/int/trace.hpp \ - ./gecode/int/trace/bool-delta.hpp ./gecode/int/trace/bool-trace-view.hpp ./gecode/int/trace/int-delta.hpp \ - ./gecode/int/trace/int-trace-view.hpp ./gecode/int/trace/traits.hpp ./gecode/int/var-imp.hpp \ + ./gecode/int/channel.hpp ./gecode/int/cumulative.hh ./gecode/int/cumulative/edge-finding.hpp \ + ./gecode/int/cumulative/knapsack-overload.hpp ./gecode/int/cumulative/limits.hpp ./gecode/int/cumulative/man-prop.hpp \ + ./gecode/int/cumulative/opt-prop.hpp ./gecode/int/cumulative/overload.hpp ./gecode/int/cumulative/post.hpp \ + ./gecode/int/cumulative/subsumption.hpp ./gecode/int/cumulative/task-view.hpp ./gecode/int/cumulative/task.hpp \ + ./gecode/int/cumulative/time-tabling.hpp ./gecode/int/cumulative/tree.hpp ./gecode/int/div.hh \ + ./gecode/int/div.hpp ./gecode/int/exception.hpp ./gecode/int/extensional.hpp \ + ./gecode/int/extensional/dfa.hpp ./gecode/int/extensional/tuple-set.hpp ./gecode/int/int-set-1.hpp \ + ./gecode/int/int-set-2.hpp ./gecode/int/ipl.hpp ./gecode/int/irt.hpp \ + ./gecode/int/limits.hpp ./gecode/int/propagator.hpp ./gecode/int/reify.hpp \ + ./gecode/int/task.hh ./gecode/int/task/array.hpp ./gecode/int/task/event.hpp \ + ./gecode/int/task/fwd-to-bwd.hpp ./gecode/int/task/iter.hpp ./gecode/int/task/man-to-opt.hpp \ + ./gecode/int/task/prop.hpp ./gecode/int/task/purge.hpp ./gecode/int/task/sort.hpp \ + ./gecode/int/task/tree.hpp ./gecode/int/trace.hpp ./gecode/int/trace/bool-delta.hpp \ + ./gecode/int/trace/bool-trace-view.hpp ./gecode/int/trace/int-delta.hpp ./gecode/int/trace/int-trace-view.hpp \ + ./gecode/int/trace/traits.hpp ./gecode/int/unary.hh ./gecode/int/unary/detectable.hpp \ + ./gecode/int/unary/edge-finding.hpp ./gecode/int/unary/man-prop.hpp ./gecode/int/unary/not-first-not-last.hpp \ + ./gecode/int/unary/opt-prop.hpp ./gecode/int/unary/overload.hpp ./gecode/int/unary/post.hpp \ + ./gecode/int/unary/subsumption.hpp ./gecode/int/unary/task-view.hpp ./gecode/int/unary/task.hpp \ + ./gecode/int/unary/time-tabling.hpp ./gecode/int/unary/tree.hpp ./gecode/int/var-imp.hpp \ ./gecode/int/var-imp/bool.hpp ./gecode/int/var-imp/delta.hpp ./gecode/int/var-imp/int.hpp \ ./gecode/int/var/bool.hpp ./gecode/int/var/int.hpp ./gecode/int/var/print.hpp \ ./gecode/int/view.hpp ./gecode/int/view/bool-test.hpp ./gecode/int/view/bool.hpp \ @@ -21320,7 +21332,7 @@ test/int/cumulative$(OBJSUFFIX) test/int/cumulative$(SBJSUFFIX): \ ./gecode/kernel/range-list.hpp ./gecode/kernel/shared-object.hpp ./gecode/kernel/shared-space-data.hpp \ ./gecode/kernel/trace/filter.hpp ./gecode/kernel/trace/general.hpp ./gecode/kernel/trace/print.hpp \ ./gecode/kernel/trace/recorder.hpp ./gecode/kernel/trace/tracer.hpp ./gecode/kernel/trace/traits.hpp \ - gecode/kernel/var-imp.hpp gecode/kernel/var-type.hpp ./gecode/kernel/var.hpp \ + ./gecode/kernel/var-imp.hpp ./gecode/kernel/var-type.hpp ./gecode/kernel/var.hpp \ ./gecode/kernel/view.hpp ./gecode/minimodel.hh ./gecode/minimodel/aliases.hpp \ ./gecode/minimodel/bool-expr.hpp ./gecode/minimodel/channel.hpp ./gecode/minimodel/exception.hpp \ ./gecode/minimodel/float-expr.hpp ./gecode/minimodel/float-rel.hpp ./gecode/minimodel/int-expr.hpp \ @@ -21346,15 +21358,15 @@ test/int/cumulative$(OBJSUFFIX) test/int/cumulative$(SBJSUFFIX): \ ./gecode/set/view/print.hpp ./gecode/set/view/set.hpp ./gecode/set/view/singleton.hpp \ ./gecode/support.hh ./gecode/support/allocator.hpp ./gecode/support/auto-link.hpp \ ./gecode/support/bitset-base.hpp ./gecode/support/bitset-offset.hpp ./gecode/support/bitset.hpp \ - ./gecode/support/block-allocator.hpp ./gecode/support/cast.hpp ./gecode/support/config.hpp \ + ./gecode/support/block-allocator.hpp ./gecode/support/cast.hpp gecode/support/config.hpp \ ./gecode/support/dynamic-array.hpp ./gecode/support/dynamic-queue.hpp ./gecode/support/dynamic-stack.hpp \ - ./gecode/support/exception.hpp ./gecode/support/hash.hpp ./gecode/support/heap.hpp \ - ./gecode/support/hw-rnd.hpp ./gecode/support/int-type.hpp ./gecode/support/macros.hpp \ - ./gecode/support/marked-pointer.hpp ./gecode/support/random.hpp ./gecode/support/ref-count.hpp \ - ./gecode/support/run-jobs.hpp ./gecode/support/sort.hpp ./gecode/support/static-stack.hpp \ - ./gecode/support/thread.hpp ./gecode/support/thread/thread.hpp ./gecode/support/timer.hpp \ - ./test/int.hh ./test/int.hpp ./test/test.hh \ - ./test/test.hpp + ./gecode/support/exception.hpp ./gecode/support/failpoint.hpp ./gecode/support/hash.hpp \ + ./gecode/support/heap.hpp ./gecode/support/hw-rnd.hpp ./gecode/support/int-type.hpp \ + ./gecode/support/macros.hpp ./gecode/support/marked-pointer.hpp ./gecode/support/random.hpp \ + ./gecode/support/ref-count.hpp ./gecode/support/run-jobs.hpp ./gecode/support/sort.hpp \ + ./gecode/support/static-stack.hpp ./gecode/support/thread.hpp ./gecode/support/thread/thread.hpp \ + ./gecode/support/timer.hpp ./test/int.hh ./test/int.hpp \ + ./test/test.hh ./test/test.hpp test/int/cumulatives$(OBJSUFFIX) test/int/cumulatives$(SBJSUFFIX): \ ./gecode/float.hh ./gecode/float/array-traits.hpp ./gecode/float/array.hpp \ ./gecode/float/branch.hpp ./gecode/float/branch/action.hpp ./gecode/float/branch/afc.hpp \ From 36c72c7242c304727fc92d98b91c22173f2d026f Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Mon, 5 Oct 2026 17:27:13 +0200 Subject: [PATCH 7/8] Declare each variable separately --- test/int/cumulative.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/int/cumulative.cpp b/test/int/cumulative.cpp index a1e8dd07b5..8a7d5a08fa 100755 --- a/test/int/cumulative.cpp +++ b/test/int/cumulative.cpp @@ -492,7 +492,10 @@ namespace Test { namespace Int { class KnapsackAugmentedOverload : public Test::Base { private: struct Task { - int e, l, p, d; + int e; + int l; + int p; + int d; int est(void) const { return e; } int lst(void) const { return l; } int ect(void) const { return e+p; } From 207c6676bb6e02f4f4058c882b989a2e17ceaf55 Mon Sep 17 00:00:00 2001 From: Mikael Zayenz Lagerkvist Date: Mon, 5 Oct 2026 20:18:26 +0200 Subject: [PATCH 8/8] Simplify cumulative task ordering with pair comparisons --- gecode/int/cumulative/knapsack-overload.hpp | 7 ++++--- test/int/cumulative.cpp | 7 +++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gecode/int/cumulative/knapsack-overload.hpp b/gecode/int/cumulative/knapsack-overload.hpp index 6947f0e54c..320cd2cc4a 100644 --- a/gecode/int/cumulative/knapsack-overload.hpp +++ b/gecode/int/cumulative/knapsack-overload.hpp @@ -31,6 +31,8 @@ * */ +#include + namespace Gecode { namespace Int { namespace Cumulative { // Knapsack-augmented overload checking @@ -131,9 +133,8 @@ namespace Gecode { namespace Int { namespace Cumulative { times[4*i+3] = tasks[i].lct(); } std::sort(order,order+n,[&](int left, int right) { - if (tasks[left].lct() != tasks[right].lct()) - return tasks[left].lct() < tasks[right].lct(); - return left < right; + return std::make_pair(tasks[left].lct(),left) < + std::make_pair(tasks[right].lct(),right); }); std::sort(times,times+4*n); int events = 0; diff --git a/test/int/cumulative.cpp b/test/int/cumulative.cpp index 8a7d5a08fa..e03c775883 100755 --- a/test/int/cumulative.cpp +++ b/test/int/cumulative.cpp @@ -37,6 +37,7 @@ #include #include +#include #include namespace Test { namespace Int { @@ -531,10 +532,8 @@ namespace Test { namespace Int { times.push_back(tasks[i].lct()); } std::sort(order.begin(),order.end(),[&](int a, int b) { - return tasks[static_cast(a)].lct() != - tasks[static_cast(b)].lct() ? - tasks[static_cast(a)].lct() < - tasks[static_cast(b)].lct() : a < b; + return std::make_pair(tasks[static_cast(a)].lct(),a) < + std::make_pair(tasks[static_cast(b)].lct(),b); }); std::sort(times.begin(),times.end()); times.erase(std::unique(times.begin(),times.end()),times.end());