Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
47efe7b
Add ordinary and reified GCD propagators
zayenz Aug 12, 2026
ac2bf84
Add reified divides propagator
zayenz Aug 12, 2026
e2302d2
Add n-ary product propagators
zayenz Aug 12, 2026
379e436
Add fixed-modulus product propagators
zayenz Aug 12, 2026
d743d30
Use bounds propagation for n-ary product
zayenz Aug 12, 2026
f544ce4
Plan variable-modulus product propagators
zayenz Aug 12, 2026
d74327c
Add variable-modulus product propagator
zayenz Aug 12, 2026
6688970
Add reified variable-modulus product propagator
zayenz Aug 12, 2026
2bf1efb
Plan multiplication special-case propagation
zayenz Aug 12, 2026
838e3fd
Plan removal of support enumeration
zayenz Aug 12, 2026
f6f821d
Strengthen fixed product-mod propagation
zayenz Aug 12, 2026
78ab331
Strengthen variable product-mod propagation
zayenz Aug 12, 2026
c4ce30a
Clarify enumeration-free GCD and divides
zayenz Aug 12, 2026
b5e36ce
Complete zero-aware product bounds
zayenz Aug 12, 2026
300ce54
Simplify product signs and units
zayenz Aug 12, 2026
2ffffaa
Exploit product powers and aliases
zayenz Aug 12, 2026
5662326
Remove propagator support enumeration
zayenz Aug 12, 2026
f7ebd89
Correct GCD propagation documentation
zayenz Aug 15, 2026
bf109af
Strengthen enumeration-free number theory propagation
zayenz Aug 24, 2026
06a6851
Strengthen variable product-mod bounds
zayenz Sep 8, 2026
7888795
Fix arithmetic review findings and record release readiness
zayenz Sep 8, 2026
94b2829
Exercise arithmetic activation cloning and audit checks
zayenz Sep 8, 2026
143fcaa
Check number theory limits with independent identities
zayenz Sep 8, 2026
70c81ea
Recognize reified product identities and harden arithmetic tests
zayenz Sep 8, 2026
00d8d06
Merge remote-tracking branch 'origin/main' into feature/gcd
zayenz Sep 8, 2026
8c132a6
Record readiness validation and product scaling measurements
zayenz Sep 8, 2026
0b69d37
Build audit test target and include number theory in CI checks
zayenz Sep 8, 2026
778ec06
Run propagator checks directly through Gecode test framework
zayenz Sep 8, 2026
829b1a6
Use normal test integration for integer arithmetic propagators
zayenz Sep 9, 2026
e671332
Remove development records before squash merge
zayenz Sep 9, 2026
11cc8c3
Reuse product grouping across bounds propagation
zayenz Sep 10, 2026
672f0f2
Rewrite small products using existing arithmetic and equality propaga…
zayenz Sep 10, 2026
4820e52
Keep fixpoint checks for ordinary GCD and modular products
zayenz Sep 10, 2026
4052487
Report arithmetic regression scenarios and remove obsolete cutoff tests
zayenz Sep 10, 2026
6b3e1e7
Document arithmetic actor state and lifecycle declarations
zayenz Sep 10, 2026
3d0fbd0
Remove PR-only review and benchmark artifacts before merge
zayenz Sep 10, 2026
bbaa1c7
Fix modular product disposal and sparse modulus rescheduling
zayenz Sep 22, 2026
9268c65
Strengthen number-theory filtering and streamline product propagation
zayenz Sep 22, 2026
87e8d23
Reuse multiple-bound filtering across arithmetic constraints
zayenz Oct 4, 2026
ca3a0c2
Declare each variable separately
zayenz Oct 5, 2026
9d0db8f
Declare example variables separately
zayenz Oct 5, 2026
ade1287
Keep number theory documentation in the API and propagators
Oct 6, 2026
1e6eb1a
Merge main after worker control integration
Oct 6, 2026
6855df8
Merge current main and restore documentation statistics generation
Oct 6, 2026
91e78ad
Use a checksum-verified mirror for the Autoconf CI bootstrap
Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/ci/generated-source-freshness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,13 @@ ensure_autoconf() {
mkdir -p "$tools_root"
autoconf_build_root=$(mktemp -d "$temp_root/gecode-autoconf-build.XXXXXX")
archive="$autoconf_build_root/autoconf-$autoconf_version.tar.gz"
curl --fail --silent --show-error --location --retry 3 \
--output "$archive" \
"https://ftp.gnu.org/gnu/autoconf/autoconf-$autoconf_version.tar.gz"
if ! curl --fail --silent --show-error --location --retry 3 \
--connect-timeout 15 --max-time 120 --output "$archive" \
"https://mirrors.kernel.org/gnu/autoconf/autoconf-$autoconf_version.tar.gz"; then
curl --fail --silent --show-error --location --retry 3 \
--connect-timeout 15 --max-time 120 --output "$archive" \
"https://ftp.gnu.org/gnu/autoconf/autoconf-$autoconf_version.tar.gz"
fi
if command -v shasum >/dev/null 2>&1; then
printf '%s %s\n' "$autoconf_sha256" "$archive" | shasum -a 256 -c -
else
Expand Down
18 changes: 18 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,8 @@ gecode/int/count$(OBJSUFFIX) gecode/int/count$(SBJSUFFIX): \
./gecode/support/sort.hpp ./gecode/support/static-stack.hpp ./gecode/support/thread.hpp \
./gecode/support/thread/thread.hpp ./gecode/support/timer.hpp
gecode/int/arithmetic$(OBJSUFFIX) gecode/int/arithmetic$(SBJSUFFIX): \
./gecode/int/arithmetic/gcd.hpp ./gecode/int/arithmetic/divides.hpp \
./gecode/int/arithmetic/product.hpp ./gecode/int/arithmetic/product-mod.hpp \
./gecode/int.hh ./gecode/int/arithmetic.hh ./gecode/int/arithmetic/abs.hpp \
./gecode/int/arithmetic/argmax.hpp ./gecode/int/arithmetic/divmod.hpp ./gecode/int/arithmetic/max.hpp \
./gecode/int/arithmetic/mult.hpp ./gecode/int/arithmetic/nroot.hpp ./gecode/int/arithmetic/pow-ops.hpp \
Expand Down Expand Up @@ -4441,6 +4443,8 @@ gecode/int/branch/chb$(OBJSUFFIX) gecode/int/branch/chb$(SBJSUFFIX): \
./gecode/support/sort.hpp ./gecode/support/static-stack.hpp ./gecode/support/thread.hpp \
./gecode/support/thread/thread.hpp ./gecode/support/timer.hpp
gecode/int/arithmetic/mult$(OBJSUFFIX) gecode/int/arithmetic/mult$(SBJSUFFIX): \
./gecode/int/arithmetic/gcd.hpp ./gecode/int/arithmetic/divides.hpp \
./gecode/int/arithmetic/product.hpp ./gecode/int/arithmetic/product-mod.hpp \
./gecode/int.hh ./gecode/int/arithmetic.hh ./gecode/int/arithmetic/abs.hpp \
./gecode/int/arithmetic/argmax.hpp ./gecode/int/arithmetic/divmod.hpp ./gecode/int/arithmetic/max.hpp \
./gecode/int/arithmetic/mult.hpp ./gecode/int/arithmetic/nroot.hpp ./gecode/int/arithmetic/pow-ops.hpp \
Expand Down Expand Up @@ -19260,6 +19264,20 @@ test/int/channel$(OBJSUFFIX) test/int/channel$(SBJSUFFIX): \
./test/int.hh ./test/int.hpp ./test/test.hh \
./test/test.hpp
test/int/arithmetic$(OBJSUFFIX) test/int/arithmetic$(SBJSUFFIX): \
./gecode/int/arithmetic.hh ./gecode/int/arithmetic/abs.hpp ./gecode/int/arithmetic/argmax.hpp \
./gecode/int/arithmetic/divides.hpp ./gecode/int/arithmetic/divmod.hpp ./gecode/int/arithmetic/gcd.hpp \
./gecode/int/arithmetic/max.hpp ./gecode/int/arithmetic/mult.hpp ./gecode/int/arithmetic/nroot.hpp \
./gecode/int/arithmetic/pow-ops.hpp ./gecode/int/arithmetic/pow.hpp ./gecode/int/arithmetic/product-mod.hpp \
./gecode/int/arithmetic/product.hpp ./gecode/int/bool.hh ./gecode/int/bool/base.hpp \
./gecode/int/bool/clause.hpp ./gecode/int/bool/eq.hpp ./gecode/int/bool/eqv.hpp \
./gecode/int/bool/ite.hpp ./gecode/int/bool/lq.hpp ./gecode/int/bool/or.hpp \
./gecode/int/idx-view.hh ./gecode/int/idx-view.hpp ./gecode/int/linear.hh \
./gecode/int/linear/bool-int.hpp ./gecode/int/linear/bool-scale.hpp ./gecode/int/linear/bool-view.hpp \
./gecode/int/linear/int-bin.hpp ./gecode/int/linear/int-dom.hpp ./gecode/int/linear/int-nary.hpp \
./gecode/int/linear/int-noview.hpp ./gecode/int/linear/int-ter.hpp ./gecode/int/linear/post.hpp \
./gecode/int/rel.hh ./gecode/int/rel/eq.hpp ./gecode/int/rel/lex.hpp \
./gecode/int/rel/lq-le.hpp ./gecode/int/rel/nq.hpp ./gecode/int/support-values.hh \
./gecode/int/support-values.hpp \
./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 \
./gecode/float/branch/assign.hpp ./gecode/float/branch/chb.hpp ./gecode/float/branch/traits.hpp \
Expand Down
3 changes: 2 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ INTHDR0 = \
idx-view.hh idx-view.hpp div.hh div.hpp \
exec.hh exec/when.hpp \
arithmetic/abs.hpp arithmetic/max.hpp arithmetic/argmax.hpp \
arithmetic/mult.hpp arithmetic/divmod.hpp \
arithmetic/mult.hpp arithmetic/gcd.hpp arithmetic/divides.hpp \
arithmetic/product.hpp arithmetic/product-mod.hpp arithmetic/divmod.hpp \
arithmetic/pow-ops.hpp arithmetic/pow.hpp arithmetic/nroot.hpp \
bool/or.hpp bool/eq.hpp bool/lq.hpp bool/eqv.hpp bool/base.hpp \
bool/clause.hpp bool/ite.hpp \
Expand Down
14 changes: 14 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ Date: unreleased
[DESCRIPTION]
This is the development changelog for the next Gecode release.

[ENTRY]
Module: int
What: new
Rank: major
[DESCRIPTION]
Add ordinary and reified gcd, n-ary product, and n-ary product_mod
constraints, and reified divides. GCD uses nonnegative results and
gcd(0,0)=0; zero divides zero. Modular products accept a fixed positive
modulus or a variable modulus and use nonnegative Euclidean residues,
including for negative products. All reification modes are supported.
Propagation uses bounds and algebraic reasoning; the propagation-level
argument does not select different consistency strengths.

[ENTRY]

Module: int
Expand All @@ -85,6 +98,7 @@ overload checking. The algorithm is described in:
S. Cloutier, C.-G. Quimper, Augmenting the Cumulative Overload Check
with Integral Resource Usage Reasoning, CP 2026.

[ENTRY]
Module: search
What: new
Rank: major
Expand Down
114 changes: 114 additions & 0 deletions gecode/int.hh
Original file line number Diff line number Diff line change
Expand Up @@ -3031,6 +3031,120 @@ namespace Gecode {
mult(Home home, IntVar x0, IntVar x1, IntVar x2,
IntPropLevel ipl=IPL_DEF);

/** \brief Post propagator for \f$\gcd(x_0,x_1)=x_2\f$
*
* The greatest common divisor is nonnegative, with
* \f$\gcd(0,0)=0\f$. Negative operands are interpreted by absolute
* value. Uses sound bounds and algebraic propagation; bounds consistency
* is not guaranteed. The propagation level \a ipl is currently ignored.
*/
GECODE_INT_EXPORT void
gcd(Home home, IntVar x0, IntVar x1, IntVar x2,
IntPropLevel ipl=IPL_DEF);

/** \brief Post propagator for
* \f$(\gcd(x_0,x_1)=x_2)\leftrightarrow r\f$
*
* Supports all reification modes. The greatest common divisor is
* nonnegative, with \f$\gcd(0,0)=0\f$. Uses conservative algebraic
* entailment and disentailment tests. The propagation level \a ipl is
* currently ignored.
*/
GECODE_INT_EXPORT void
gcd(Home home, IntVar x0, IntVar x1, IntVar x2, Reify r,
IntPropLevel ipl=IPL_DEF);

/** \brief Reify whether \a divisor divides \a dividend
*
* Divisibility means that an integer \f$k\f$ exists such that
* \f$dividend=divisor\cdot k\f$. Consequently, zero divides zero, but
* zero does not divide a nonzero integer. Supports all reification modes.
* Uses bounds and conservative algebraic propagation; bounds consistency
* is not guaranteed. The propagation level \a ipl is currently ignored.
*/
GECODE_INT_EXPORT void
divides(Home home, IntVar divisor, IntVar dividend, Reify r,
IntPropLevel ipl=IPL_DEF);

/** \brief Constrain \a y to the exact product of the variables in \a x
*
* The product of an empty array is one.
* Uses bounds and algebraic propagation, without guaranteeing bounds
* consistency. The propagation level \a ipl is currently ignored.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product(Home home, const IntVarArgs& x, IntVar y,
IntPropLevel ipl=IPL_DEF);

/** \brief Reify whether \a y is the exact product of the variables in \a x
*
* The product of an empty array is one.
* Supports all reification modes using conservative algebraic tests.
* The propagation level \a ipl is currently ignored.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product(Home home, const IntVarArgs& x, IntVar y, Reify r,
IntPropLevel ipl=IPL_DEF);

/** \brief Constrain \a y to the product of \a x modulo \a m
*
* The modulus \a m must be positive. The result uses the canonical
* Euclidean residue in the range zero through \a m minus one. The product
* of an empty array is one.
* Unlike mod(), a negative product still has a nonnegative residue.
* Uses bounds and algebraic propagation, without guaranteeing bounds
* consistency. The propagation level \a ipl is currently ignored.
* Throws Int::OutOfLimits if \a m is nonpositive or exceeds Int::Limits::max.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product_mod(Home home, const IntVarArgs& x, int m, IntVar y,
IntPropLevel ipl=IPL_DEF);

/** \brief Reify whether \a y is the product of \a x modulo \a m
*
* The modulus \a m must be positive. The result uses the canonical
* Euclidean residue in the range zero through \a m minus one. The product
* of an empty array is one.
* Supports all reification modes using conservative algebraic tests,
* without guaranteeing bounds consistency; \a ipl is currently ignored.
* Throws Int::OutOfLimits if \a m is nonpositive or exceeds Int::Limits::max,
* even for an inactive implication.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product_mod(Home home, const IntVarArgs& x, int m, IntVar y, Reify r,
IntPropLevel ipl=IPL_DEF);

/** \brief Constrain \a y to the product of \a x modulo \a m
*
* The variable modulus \a m is constrained to be positive and \a y uses
* the canonical Euclidean residue, so that \f$0\leq y<m\f$. The product
* of an empty array is one.
* Uses bounds and algebraic propagation, without guaranteeing bounds
* consistency. The propagation level \a ipl is currently ignored.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product_mod(Home home, const IntVarArgs& x, IntVar m, IntVar y,
IntPropLevel ipl=IPL_DEF);

/** \brief Reify whether \a y is the product of \a x modulo \a m
*
* The reified proposition includes \f$m>0\f$, the canonical range
* \f$0\leq y<m\f$, and congruence with the product. The product of an
* empty array is one.
* Supports all reification modes using conservative algebraic tests,
* without guaranteeing bounds consistency; \a ipl is currently ignored.
* An inactive implication does not constrain the modulus or result.
* \ingroup TaskModelInt
*/
GECODE_INT_EXPORT void
product_mod(Home home, const IntVarArgs& x, IntVar m, IntVar y, Reify r,
IntPropLevel ipl=IPL_DEF);

/** \brief Post propagator for \f$x_0\ \mathrm{div}\ x_1=x_2 \land x_0\ \mathrm{mod}\ x_1 = x_3\f$
*
* Supports bounds consistency (\a ipl = IPL_BND, default).
Expand Down
150 changes: 150 additions & 0 deletions gecode/int/arithmetic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,156 @@ namespace Gecode {
}
}

void
gcd(Home home, IntVar x0, IntVar x1, IntVar x2, IntPropLevel) {
using namespace Int;
GECODE_POST;
GECODE_ES_FAIL(Arithmetic::Gcd::post(home,x0,x1,x2));
}

void
gcd(Home home, IntVar x0, IntVar x1, IntVar x2, Reify r,
IntPropLevel) {
using namespace Int;
GECODE_POST;
switch (r.mode()) {
case RM_EQV:
GECODE_ES_FAIL((Arithmetic::ReGcd<RM_EQV>
::post(home,x0,x1,x2,r.var())));
break;
case RM_IMP:
GECODE_ES_FAIL((Arithmetic::ReGcd<RM_IMP>
::post(home,x0,x1,x2,r.var())));
break;
case RM_PMI:
GECODE_ES_FAIL((Arithmetic::ReGcd<RM_PMI>
::post(home,x0,x1,x2,r.var())));
break;
default: GECODE_NEVER;
}
}

void
divides(Home home, IntVar divisor, IntVar dividend, Reify r,
IntPropLevel) {
using namespace Int;
GECODE_POST;
switch (r.mode()) {
case RM_EQV:
GECODE_ES_FAIL((Arithmetic::ReDivides<RM_EQV>
::post(home,divisor,dividend,r.var())));
break;
case RM_IMP:
GECODE_ES_FAIL((Arithmetic::ReDivides<RM_IMP>
::post(home,divisor,dividend,r.var())));
break;
case RM_PMI:
GECODE_ES_FAIL((Arithmetic::ReDivides<RM_PMI>
::post(home,divisor,dividend,r.var())));
break;
default: GECODE_NEVER;
}
}

void
product(Home home, const IntVarArgs& x, IntVar y, IntPropLevel) {
using namespace Int;
GECODE_POST;
ViewArray<IntView> xv(home,x);
GECODE_ES_FAIL(Arithmetic::Product::post(home,xv,y));
}

void
product(Home home, const IntVarArgs& x, IntVar y, Reify r,
IntPropLevel) {
using namespace Int;
GECODE_POST;
ViewArray<IntView> xv(home,x);
switch (r.mode()) {
case RM_EQV:
GECODE_ES_FAIL((Arithmetic::ReProduct<RM_EQV>
::post(home,xv,y,r.var())));
break;
case RM_IMP:
GECODE_ES_FAIL((Arithmetic::ReProduct<RM_IMP>
::post(home,xv,y,r.var())));
break;
case RM_PMI:
GECODE_ES_FAIL((Arithmetic::ReProduct<RM_PMI>
::post(home,xv,y,r.var())));
break;
default: GECODE_NEVER;
}
}

void
product_mod(Home home, const IntVarArgs& x, int m, IntVar y,
IntPropLevel) {
using namespace Int;
Limits::positive(m,"Int::product_mod");
GECODE_POST;
IntView yv(y);
ViewArray<IntView> xv(home,x);
GECODE_ES_FAIL(Arithmetic::ProductMod::post(home,xv,m,yv));
}

void
product_mod(Home home, const IntVarArgs& x, int m, IntVar y, Reify r,
IntPropLevel) {
using namespace Int;
Limits::positive(m,"Int::product_mod");
GECODE_POST;
IntView yv(y);
ViewArray<IntView> xv(home,x);
switch (r.mode()) {
case RM_EQV:
GECODE_ES_FAIL((Arithmetic::ReProductMod<RM_EQV>
::post(home,xv,m,yv,r.var())));
break;
case RM_IMP:
GECODE_ES_FAIL((Arithmetic::ReProductMod<RM_IMP>
::post(home,xv,m,yv,r.var())));
break;
case RM_PMI:
GECODE_ES_FAIL((Arithmetic::ReProductMod<RM_PMI>
::post(home,xv,m,yv,r.var())));
break;
default: GECODE_NEVER;
}
}

void
product_mod(Home home, const IntVarArgs& x, IntVar m, IntVar y,
IntPropLevel) {
using namespace Int;
GECODE_POST;
ViewArray<IntView> xv(home,x);
GECODE_ES_FAIL(Arithmetic::ProductModVar::post(home,xv,m,y));
}

void
product_mod(Home home, const IntVarArgs& x, IntVar m, IntVar y, Reify r,
IntPropLevel) {
using namespace Int;
GECODE_POST;
ViewArray<IntView> xv(home,x);
switch (r.mode()) {
case RM_EQV:
GECODE_ES_FAIL((Arithmetic::ReProductModVar<RM_EQV>
::post(home,xv,m,y,r.var())));
break;
case RM_IMP:
GECODE_ES_FAIL((Arithmetic::ReProductModVar<RM_IMP>
::post(home,xv,m,y,r.var())));
break;
case RM_PMI:
GECODE_ES_FAIL((Arithmetic::ReProductModVar<RM_PMI>
::post(home,xv,m,y,r.var())));
break;
default: GECODE_NEVER;
}
}


void
divmod(Home home, IntVar x0, IntVar x1, IntVar x2, IntVar x3,
Expand Down
Loading
Loading