Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5bd5a6e
Add ordinary and reified GCD propagators
zayenz Aug 12, 2026
35116c7
Add reified divides propagator
zayenz Aug 12, 2026
0c91934
Add n-ary product propagators
zayenz Aug 12, 2026
76c6911
Add fixed-modulus product propagators
zayenz Aug 12, 2026
2541899
Use bounds propagation for n-ary product
zayenz Aug 12, 2026
4b369b8
Plan variable-modulus product propagators
zayenz Aug 12, 2026
4f90aaa
Add variable-modulus product propagator
zayenz Aug 12, 2026
7a352c9
Add reified variable-modulus product propagator
zayenz Aug 12, 2026
6e477c8
Plan multiplication special-case propagation
zayenz Aug 12, 2026
929f086
Plan removal of support enumeration
zayenz Aug 12, 2026
e7f9aec
Strengthen fixed product-mod propagation
zayenz Aug 12, 2026
07130b9
Strengthen variable product-mod propagation
zayenz Aug 12, 2026
40d08ec
Clarify enumeration-free GCD and divides
zayenz Aug 12, 2026
560944e
Complete zero-aware product bounds
zayenz Aug 12, 2026
018a663
Simplify product signs and units
zayenz Aug 12, 2026
c86f9e2
Exploit product powers and aliases
zayenz Aug 12, 2026
677261d
Remove propagator support enumeration
zayenz Aug 12, 2026
14eaa62
Correct GCD propagation documentation
zayenz Aug 15, 2026
d76bc6b
Strengthen enumeration-free number theory propagation
zayenz Aug 24, 2026
c3ca1cd
Strengthen variable product-mod bounds
zayenz Sep 8, 2026
44f39b4
Fix arithmetic review findings and record release readiness
zayenz Sep 8, 2026
ef5ee27
Exercise arithmetic activation cloning and audit checks
zayenz Sep 8, 2026
32cc34d
Check number theory limits with independent identities
zayenz Sep 8, 2026
88dc85d
Recognize reified product identities and harden arithmetic tests
zayenz Sep 8, 2026
e322a3f
Record readiness validation and product scaling measurements
zayenz Sep 8, 2026
d2a1dce
Build audit test target and include number theory in CI checks
zayenz Sep 8, 2026
00cea8f
Run propagator checks directly through Gecode test framework
zayenz Sep 8, 2026
9035f4a
Use normal test integration for integer arithmetic propagators
zayenz Sep 9, 2026
746353c
Remove development records before squash merge
zayenz Sep 9, 2026
1c81475
Reuse product grouping across bounds propagation
zayenz Sep 10, 2026
4b4e67e
Rewrite small products using existing arithmetic and equality propaga…
zayenz Sep 10, 2026
5fce5ca
Keep fixpoint checks for ordinary GCD and modular products
zayenz Sep 10, 2026
c013ac3
Report arithmetic regression scenarios and remove obsolete cutoff tests
zayenz Sep 10, 2026
cb3b108
Document arithmetic actor state and lifecycle declarations
zayenz Sep 10, 2026
576b39d
Remove PR-only review and benchmark artifacts before merge
zayenz Sep 10, 2026
06dd756
Fix modular product disposal and sparse modulus rescheduling
zayenz Sep 22, 2026
d49ced1
Strengthen number-theory filtering and streamline product propagation
zayenz Sep 22, 2026
c6813e9
Reuse multiple-bound filtering across arithmetic constraints
zayenz Oct 4, 2026
70daf6f
Declare each variable separately
zayenz Oct 5, 2026
3dfab2b
Declare example variables separately
zayenz Oct 5, 2026
8fa7ca5
Keep number theory documentation in the API and propagators
Oct 6, 2026
7e0291b
Use a checksum-verified mirror for the Autoconf CI bootstrap
Oct 6, 2026
c2f3120
Preserve changelog entries and worker-control statistics
zayenz Oct 8, 2026
941bad2
Merge branch 'main' into feature/gcd
zayenz Oct 8, 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
13 changes: 13 additions & 0 deletions changelog.in
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ engines owned by RBS and PBS. Callers can redistribute a fixed worker budget
without rebuilding the engines. Requesting zero pauses an engine without
discarding its search state or holding a PBS round open.

[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
What: performance
Expand Down
114 changes: 114 additions & 0 deletions gecode/int.hh
Original file line number Diff line number Diff line change
Expand Up @@ -3058,6 +3058,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