Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2e9cba5
Initial implementation of consistency checkers
maartenflippo Feb 27, 2026
aacd712
Run the consistency checkers when enabled
maartenflippo Feb 27, 2026
ece98c7
Implement bound consistency checker
maartenflippo Feb 27, 2026
5013527
Give access to domains in witness generator
maartenflippo Feb 27, 2026
c7a3b9c
Implement checker for absolute value
maartenflippo Feb 27, 2026
5fbad25
Remove redundant min
maartenflippo Feb 27, 2026
fd04f2e
Include the value to support in linear witness generator
maartenflippo Feb 27, 2026
0e7329e
Don't add to supported values of the domain being witnessed
maartenflippo Feb 27, 2026
5c7a9d1
Proper mechanism to add to the scope
maartenflippo Feb 27, 2026
8b143be
Update todo notes
maartenflippo Feb 27, 2026
4c5eda3
Implement Witness generator for multiplication
maartenflippo Mar 2, 2026
348779d
Transform consistency checker interface.
maartenflippo Mar 3, 2026
5fd33cb
Implement new interface
maartenflippo Mar 3, 2026
0c5afe2
Implement weak consistency checkers
maartenflippo Mar 3, 2026
9a528c3
Remove the dedicated concept of Scope
maartenflippo Mar 3, 2026
43a80a2
Proper witness generator for linear
maartenflippo Mar 3, 2026
7b4bab9
Add documentation to strong consistency checker
maartenflippo Mar 4, 2026
6998a47
Proper witness generator for multiplication bound consistency
maartenflippo Mar 4, 2026
7ec48e0
Remove unused import
maartenflippo Mar 4, 2026
c295d0c
Implement witness generator for maximum
maartenflippo Mar 5, 2026
360c961
No consistency checking for multiplication
maartenflippo Mar 5, 2026
d545f47
Add circuit and witness generator for element
maartenflippo Mar 5, 2026
7088788
Fixup element propagator
maartenflippo Mar 5, 2026
380e2e0
Disable circuit due to consistency bugs
maartenflippo Mar 5, 2026
b4eeb11
Separate flags for consistency and inference checking
maartenflippo Mar 6, 2026
91ef2ea
Implement consistency checking for reified
maartenflippo Mar 9, 2026
1615dee
Filter checkers and fix reified checker
maartenflippo Mar 10, 2026
96c6ae5
Fix propagator checker filter cli
maartenflippo Mar 10, 2026
09eec3d
Enable filtering of checker types
maartenflippo Mar 10, 2026
d5ac88c
Add circuit propagator
maartenflippo Mar 12, 2026
c47ab88
Get the final propagators in
maartenflippo Mar 12, 2026
dca7515
More bug fixes
maartenflippo Mar 13, 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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --release --no-fail-fast --features pumpkin-solver/check-propagations
- run: cargo test --release --no-fail-fast --features pumpkin-solver/all-propagator-checks

wasm-test:
name: Test Suite for pumpkin-core in WebAssembly
Expand Down
109 changes: 106 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [

"./pumpkin-crates/*", # Core libraries of the solver
"./pumpkin-solver", # The solver binary
"./pumpkin-proof-processor", # The proof processor
"./pumpkin-checker", # The uncertified proof checker
"./pumpkin-solver-py", # The python interface
"./pumpkin-macros", # Proc-macros used by the pumpkin source (unpublished)
Expand Down
2 changes: 2 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
allowed-duplicate-crates = [
"hashbrown",
"windows-sys",
"regex-syntax",
"regex-automata",
]
5 changes: 5 additions & 0 deletions minizinc/lib/fzn_circuit.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
predicate pumpkin_circuit(array[int] of var int: next);

predicate fzn_circuit(array[int] of var int: next) =
pumpkin_circuit(next);

4 changes: 2 additions & 2 deletions pumpkin-checker/src/inferences/linear.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use pumpkin_checking::InferenceChecker;
use pumpkin_checking::VariableState;
use pumpkin_propagators::arithmetic::LinearLessOrEqualInferenceChecker;
use pumpkin_propagators::arithmetic::LinearLessOrEqualChecker;

use crate::inferences::Fact;
use crate::inferences::InvalidInference;
Expand Down Expand Up @@ -52,7 +52,7 @@ fn verify_linear_inference(
fact: &Fact,
state: VariableState<Atomic>,
) -> Result<(), InvalidInference> {
let checker = LinearLessOrEqualInferenceChecker::new(linear.terms.clone().into(), linear.bound);
let checker = LinearLessOrEqualChecker::new(linear.terms.clone().into(), linear.bound);

if checker.check(state, &fact.premises, fact.consequent.as_ref()) {
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion pumpkin-checker/src/inferences/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub enum InvalidInference {
UndefinedConstraint,

/// The inference does not state which constraint generated it.
#[error("missing constraint hint")]
#[error("the constraint hint points to an unknown constraint ID")]
MissingConstraint,

/// The premises of the inference are inconsistent.
Expand Down
27 changes: 27 additions & 0 deletions pumpkin-crates/checking/src/atomic_constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,30 @@ impl AtomicConstraint for TestAtomic {
}
}
}

#[macro_export]
macro_rules! test_atom {
[@to_comparison ==] => {
$crate::Comparison::Equal
};

[@to_comparison !=] => {
$crate::Comparison::NotEqual
};

[@to_comparison >=] => {
$crate::Comparison::GreaterEqual
};

[@to_comparison <=] => {
$crate::Comparison::LessEqual
};

[$name:ident $token:tt $bound:expr] => {
$crate::TestAtomic {
name: stringify!($name),
comparison: test_atom!(@to_comparison $token),
value: $bound,
}
};
}
5 changes: 4 additions & 1 deletion pumpkin-crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ once_cell = "1.19.0"
downcast-rs = "1.2.1"
drcp-format = { version = "0.3.1", path = "../../drcp-format" }
convert_case = "0.8.0"
itertools = "0.13.0"
itertools = "0.14.0"
bitfield-struct = "0.9.2"
num = "0.4.3"
enum-map = "2.7.3"
Expand All @@ -40,5 +40,8 @@ wasm-bindgen-test = "0.3"

[features]
check-propagations = []
check-consistency = []
all-propagator-checks = ["check-propagations", "check-consistency"]

debug-checks = []
clap = ["dep:clap"]
1 change: 1 addition & 0 deletions pumpkin-crates/core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub mod state {
//! See [`State`] for more information.
pub use crate::api::solver::PropagatorHandle;
pub use crate::basic_types::PropagatorConflict;
pub use crate::engine::CheckersToRun;
pub use crate::engine::Conflict;
pub use crate::engine::EmptyDomain;
pub use crate::engine::EmptyDomainConflict;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use crate::propagation::HasAssignments;
use crate::propagators::nogoods::NogoodChecker;
use crate::propagators::nogoods::NogoodPropagator;
use crate::pumpkin_assert_eq_simple;
use crate::state::EmptyDomain;
use crate::state::PropagatorHandle;

/// Used during conflict analysis to provide the necessary information.
Expand Down Expand Up @@ -70,8 +69,9 @@ impl ConflictAnalysisContext<'_> {
/// Returns `true` if a change to a domain occured, and `false` if the given [`Predicate`] was
/// already true.
///
/// If a domain becomes empty due to this operation, an [`EmptyDomain`] error is returned.
pub fn post(&mut self, predicate: Predicate) -> Result<bool, EmptyDomain> {
/// If a domain becomes empty due to this operation, an [`EmptyDomainConflict`] error is
/// returned.
pub fn post(&mut self, predicate: Predicate) -> Result<bool, EmptyDomainConflict> {
self.state.post(predicate)
}

Expand Down Expand Up @@ -272,13 +272,16 @@ impl ConflictAnalysisContext<'_> {
reason_buffer: &mut (impl Extend<Predicate> + AsRef<[Predicate]>),
state: &mut State,
) {
let trail_index = state.get_propagation_reason(predicate, reason_buffer, current_nogood);
let inference_code = state.get_propagation_reason(predicate, reason_buffer, current_nogood);

if let Some(trail_index) = trail_index {
if inference_code.is_some() {
let trail_index = state.trail_position(predicate).expect(
"an inference code is only present if the propagated predicate is on the trail",
);
let trail_entry = state.assignments.get_trail_entry(trail_index);
let (reason_ref, inference_code) = trail_entry
.reason
.expect("Cannot be a null reason for propagation.");
let Some((reason_ref, inference_code)) = trail_entry.reason else {
return;
};

let propagator_id = state.reason_store.get_propagator(reason_ref);

Expand Down Expand Up @@ -338,7 +341,7 @@ impl ConflictAnalysisContext<'_> {
// The reason for changing the bound cannot be a decision, so we can safely unwrap.
let mut empty_domain_reason: Vec<Predicate> = vec![];
let _ = self.state.reason_store.get_or_compute(
conflict.trigger_reason,
conflict.trigger_reason.expect("in conflict analysis the empty domain conflict is always triggered by a propagation"),
ExplanationContext::without_working_nogood(
&self.state.assignments,
self.state.assignments.num_trail_entries(), // Note that we do not do a
Expand All @@ -353,7 +356,7 @@ impl ConflictAnalysisContext<'_> {
// We also need to log this last propagation to the proof log as an inference.
let _ = self.proof_log.log_inference(
&mut self.state.constraint_tags,
conflict.trigger_inference_code,
conflict.trigger_inference_code.expect("in conflict analysis the empty domain conflict is always triggered by a propagation"),
empty_domain_reason.iter().copied(),
Some(conflict.trigger_predicate),
&self.state.variable_names,
Expand Down
11 changes: 11 additions & 0 deletions pumpkin-crates/core/src/containers/keyed_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ impl<Key: StorageKey, Value> KeyedVec<Key, Value> {
self.elements.get(key.index())
}

pub fn get_mut(&mut self, key: Key) -> Option<&mut Value> {
self.elements.get_mut(key.index())
}

pub fn pop(&mut self) -> Option<(Key, Value)> {
self.elements.pop().map(|value| {
let key = Key::create_from_index(self.elements.len());
(key, value)
})
}

pub fn len(&self) -> usize {
self.elements.len()
}
Expand Down
Loading
Loading