From 21c9a3c4a3d225491170886e1f6bd35957b557b0 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Mon, 24 Aug 2026 17:22:10 +0200 Subject: [PATCH 1/4] [graphics] corrected bug with random colors --- src/core/contractors/codac2_CtcQInter.h | 1 + src/core/separators/codac2_SepQInter.h | 1 + src/graphics/styles/codac2_Color.h | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/contractors/codac2_CtcQInter.h b/src/core/contractors/codac2_CtcQInter.h index f626705cc..edf2d0952 100644 --- a/src/core/contractors/codac2_CtcQInter.h +++ b/src/core/contractors/codac2_CtcQInter.h @@ -26,6 +26,7 @@ namespace codac2 assert_release(!c.empty()); Index n = size_of(c.front()); for(const auto& s : c) { + (void)s; assert_release(size_of(s) == n && "all contractors must be of same size"); } return n; diff --git a/src/core/separators/codac2_SepQInter.h b/src/core/separators/codac2_SepQInter.h index 342bd6a88..5f0b7488e 100644 --- a/src/core/separators/codac2_SepQInter.h +++ b/src/core/separators/codac2_SepQInter.h @@ -25,6 +25,7 @@ namespace codac2 assert_release(!c.empty()); Index n = size_of(c.front()); for(const auto& s : c) { + (void)s; assert_release(size_of(s) == n && "all separators must be of same size"); } return n; diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index e6e2fb556..b4f5b1554 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -162,7 +162,7 @@ namespace codac2 */ static Color random(float alpha = 1.) { - return Color({(float)Interval(0,360).rand(),100,100, (float)(alpha * 255.)}, Model::HSV); + return Color({(float)Interval(0,360).rand(),100,100, (float)(alpha * 100.)}, Model::HSV); }; #define DEFINE_COLOR(NAME, R, G, B) \ From ff4fe623a057e5e5e0dc726d16cce8d3d4b52d5a Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Mon, 24 Aug 2026 19:05:33 +0200 Subject: [PATCH 2/4] [ctc] added CtcWrapper(Y&& y) constructor --- src/core/contractors/codac2_CtcWrapper.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/contractors/codac2_CtcWrapper.h b/src/core/contractors/codac2_CtcWrapper.h index 278e6ef93..028b09736 100644 --- a/src/core/contractors/codac2_CtcWrapper.h +++ b/src/core/contractors/codac2_CtcWrapper.h @@ -26,6 +26,10 @@ namespace codac2 : Ctc,X>(y.size()), _y(y) { } + CtcWrapper(Y&& y) + : Ctc,X>(y.size()), _y(std::move(y)) + { } + void contract(X& x) const { assert_release(x.size() == this->size()); From b134a18a3882918319df136d3b2c114d5d46814a Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 25 Aug 2026 17:08:18 +0200 Subject: [PATCH 3/4] [ctc] minor improvment in CtcUnion --- src/core/contractors/codac2_CtcUnion.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/core/contractors/codac2_CtcUnion.h b/src/core/contractors/codac2_CtcUnion.h index d7182c79f..e901f2cf0 100644 --- a/src/core/contractors/codac2_CtcUnion.h +++ b/src/core/contractors/codac2_CtcUnion.h @@ -65,7 +65,9 @@ namespace codac2 void contract(X&... x) const { - auto result = std::tuple(x...); + const auto input = std::tuple(x...); + + auto result = input; std::apply([](auto&... xi) { (xi.set_empty(), ...); @@ -78,7 +80,7 @@ namespace codac2 for(const auto& ci : _ctcs) { - auto saved = std::tuple(x...); + auto saved = input; std::apply([&](auto&... xi) { @@ -86,6 +88,12 @@ namespace codac2 }, saved); accumulate_union(saved, std::index_sequence_for{}); + + // Each contractor is contractant, hence every remaining branch + // can only return a subset of input. Once the accumulated union + // has reached input, the final result is already known. + if(result == input) + return; } std::tie(x...) = result; From 4c9af64380bb52ae499d29c083701fdd1994b8f2 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 27 Aug 2026 09:45:09 +0200 Subject: [PATCH 4/4] [qinter] Invert q-relaxed intersection convention to count allowed violations --- examples/13_qinter/main.cpp | 2 +- examples/13_qinter/main.py | 2 +- src/core/contractors/codac2_CtcInter.h | 1 + src/core/contractors/codac2_CtcQInter.cpp | 5 ++-- src/core/contractors/codac2_CtcQInter.h | 4 +++- src/core/contractors/codac2_CtcUnion.h | 1 + src/core/proj/codac2_qinter.cpp | 28 ++++++++++++++++------- src/core/proj/codac2_qinter.h | 8 +++---- src/core/separators/codac2_SepQInter.cpp | 7 +++--- src/core/separators/codac2_SepQInter.h | 4 +++- 10 files changed, 41 insertions(+), 21 deletions(-) diff --git a/examples/13_qinter/main.cpp b/examples/13_qinter/main.cpp index 49d33c07b..3a791c3c9 100644 --- a/examples/13_qinter/main.cpp +++ b/examples/13_qinter/main.cpp @@ -23,7 +23,7 @@ int main() DefaultFigure::set_axes(axis(0,{-6,6}), axis(1,{-6,6})); - int q = 2; + int q = 1; DefaultFigure::pave( {{-6,6},{-6,6}}, SepQInter(q, s1,s2,s3), diff --git a/examples/13_qinter/main.py b/examples/13_qinter/main.py index 39493c29f..9d2503e76 100644 --- a/examples/13_qinter/main.py +++ b/examples/13_qinter/main.py @@ -20,7 +20,7 @@ def create_sep(b, d): DefaultFigure.set_axes(axis(0, Interval(-6,6)), axis(1, Interval(-6,6))) -q = 2 +q = 1 DefaultFigure.pave( [[-6,6],[-6,6]], SepQInter(q, s1,s2,s3), diff --git a/src/core/contractors/codac2_CtcInter.h b/src/core/contractors/codac2_CtcInter.h index 8b0b5e9e5..7011843a0 100644 --- a/src/core/contractors/codac2_CtcInter.h +++ b/src/core/contractors/codac2_CtcInter.h @@ -116,6 +116,7 @@ namespace codac2 { for(const auto& ci : _ctcs) { + (void)ci; assert_release(ci->size() == this->size()); } } diff --git a/src/core/contractors/codac2_CtcQInter.cpp b/src/core/contractors/codac2_CtcQInter.cpp index 82271857b..fab25ceb5 100644 --- a/src/core/contractors/codac2_CtcQInter.cpp +++ b/src/core/contractors/codac2_CtcQInter.cpp @@ -21,7 +21,8 @@ namespace codac2 void CtcQInter::contract(IntervalVector& x) const { - if(_q == 0) + // If all constraints may be violated, no contraction can be performed. + if(_q == _ctcs.size()) return; std::list l; @@ -35,4 +36,4 @@ namespace codac2 x = qinter(_q, l); } -} \ No newline at end of file +} diff --git a/src/core/contractors/codac2_CtcQInter.h b/src/core/contractors/codac2_CtcQInter.h index edf2d0952..d0095dc6b 100644 --- a/src/core/contractors/codac2_CtcQInter.h +++ b/src/core/contractors/codac2_CtcQInter.h @@ -21,6 +21,7 @@ namespace codac2 { public: + // q is the maximum number of constraints that may be violated. CtcQInter(unsigned int q, const Collection>& c) : Ctc([&c]() { assert_release(!c.empty()); @@ -35,6 +36,7 @@ namespace codac2 assert_release(q <= c.size()); } + // q is the maximum number of constraints that may be violated. explicit CtcQInter(unsigned int q, Index n, const Collection>& ctcs = {}) : Ctc(n), _q(q), _ctcs(ctcs) { @@ -65,4 +67,4 @@ namespace codac2 size_t _q; Collection> _ctcs; }; -} \ No newline at end of file +} diff --git a/src/core/contractors/codac2_CtcUnion.h b/src/core/contractors/codac2_CtcUnion.h index e901f2cf0..614b39698 100644 --- a/src/core/contractors/codac2_CtcUnion.h +++ b/src/core/contractors/codac2_CtcUnion.h @@ -48,6 +48,7 @@ namespace codac2 { for(const auto& ci : _ctcs) { + (void)ci; assert_release(ci->size() == this->size()); } } diff --git a/src/core/proj/codac2_qinter.cpp b/src/core/proj/codac2_qinter.cpp index 86b72f3ac..441792803 100644 --- a/src/core/proj/codac2_qinter.cpp +++ b/src/core/proj/codac2_qinter.cpp @@ -20,9 +20,6 @@ namespace codac2 { assert(!l.empty()); Index n = l.begin()->size(); - - if(q > l.size()) - return IntervalVector::empty(n); assert(([&l,n](){ for(const auto& xi : l) { @@ -33,18 +30,33 @@ namespace codac2 return true; }())); + if(q > l.size()) + return IntervalVector::empty(n); + + // q is the maximum number of boxes that may be violated. + // Hence, at least l.size()-q boxes must contain the point. + const size_t min_satisfied = l.size()-q; + + if(min_satisfied == 0) + return IntervalVector(n); + unsigned int p = 0; for(const auto& li : l) if(!li.is_empty()) p++; + // Empty boxes cannot be satisfied. + if(min_satisfied > p) + return IntervalVector::empty(n); + IntervalVector res(n); std::vector> b(2*p); - // Main loop: solve the q-inter independently on each dimension, and return the Cartesian product + // Main loop: solve the q-relaxed intersection independently on each dimension, + // and return the Cartesian product for(Index i = 0 ; i < n ; i++) { - // Solve the q-inter for dimension i + // Solve the q-relaxed intersection for dimension i int j = 0; for(const auto& xj : l) @@ -64,7 +76,7 @@ namespace codac2 for(unsigned int k = 0 ; k < 2*p ; k++) { (b[k].second == ProjBound::LEFT) ? c++ : c--; - if(c == (int)q) + if(c == static_cast(min_satisfied)) { lb0 = b[k].first; break; @@ -82,7 +94,7 @@ namespace codac2 for(int k = 2*p-1 ; k >= 0 ; k--) { (b[k].second == ProjBound::RIGHT) ? c++ : c--; - if(c == (int)q) + if(c == static_cast(min_satisfied)) { rb0 = b[k].first; break; @@ -94,4 +106,4 @@ namespace codac2 return res; } -} \ No newline at end of file +} diff --git a/src/core/proj/codac2_qinter.h b/src/core/proj/codac2_qinter.h index eba50f89a..53fadd55e 100644 --- a/src/core/proj/codac2_qinter.h +++ b/src/core/proj/codac2_qinter.h @@ -14,9 +14,9 @@ namespace codac2 { - // Approximate Q-intersection, using Luc Jaulin's algorithm + // Approximate q-relaxed intersection, using Luc Jaulin's algorithm // Author: Clement Carbonnel, Benoit Desrochers, Simon Rohou - // The q-intersection of n boxes corresponds to the set of all elements - // which belong to at least q of these boxes. + // The q-relaxed intersection of n boxes corresponds to the set of all elements + // which belong to at least n-q of these boxes, i.e. which violate at most q boxes. IntervalVector qinter(unsigned int q, const std::list& l); -} \ No newline at end of file +} diff --git a/src/core/separators/codac2_SepQInter.cpp b/src/core/separators/codac2_SepQInter.cpp index d9ddadcd5..af2018fc5 100644 --- a/src/core/separators/codac2_SepQInter.cpp +++ b/src/core/separators/codac2_SepQInter.cpp @@ -22,7 +22,8 @@ namespace codac2 BoxPair SepQInter::separate(const IntervalVector& x) const { - if(_q == 0) + // If all constraints may be violated, the represented set is the whole space. + if(_q == _seps.size()) return { IntervalVector::empty(x.size()), x }; std::list l_inner, l_outer; @@ -34,11 +35,11 @@ namespace codac2 } BoxPair x_sep { - qinter(_seps.size()-_q+1, l_inner), + qinter(_seps.size()-_q-1, l_inner), qinter(_q, l_outer) }; assert((x_sep.inner | x_sep.outer) == x); return x_sep; } -} \ No newline at end of file +} diff --git a/src/core/separators/codac2_SepQInter.h b/src/core/separators/codac2_SepQInter.h index 5f0b7488e..7f8b46ee7 100644 --- a/src/core/separators/codac2_SepQInter.h +++ b/src/core/separators/codac2_SepQInter.h @@ -20,6 +20,7 @@ namespace codac2 { public: + // q is the maximum number of constraints that may be violated. SepQInter(unsigned int q, const Collection& c) : Sep([&c]() { assert_release(!c.empty()); @@ -34,6 +35,7 @@ namespace codac2 assert_release(q <= c.size()); } + // q is the maximum number of constraints that may be violated. explicit SepQInter(unsigned int q, Index n, const Collection& sep = {}) : Sep(n), _q(q), _seps(sep) { @@ -63,4 +65,4 @@ namespace codac2 size_t _q; Collection _seps; }; -} \ No newline at end of file +}