├── pumpkin-solver ├── .gitignore ├── tests │ ├── cnf │ │ ├── empty.cnf │ │ ├── unit0.cnf │ │ ├── unit1.cnf │ │ ├── regr000.cnf │ │ ├── full1.cnf │ │ ├── trivially_false.cnf │ │ ├── unit2.cnf │ │ ├── unit3.cnf │ │ ├── sub0.cnf │ │ ├── unit4.cnf │ │ ├── full2.cnf │ │ ├── sat0.cnf │ │ ├── sat1.cnf │ │ ├── sat2.cnf │ │ ├── sat3.cnf │ │ ├── sat4.cnf │ │ ├── unit6.cnf │ │ ├── .gitignore │ │ ├── unit7.cnf │ │ ├── block0.cnf │ │ ├── unit5.cnf │ │ ├── ph2.cnf │ │ ├── full3.cnf │ │ ├── sat10.cnf │ │ ├── sat11.cnf │ │ ├── sat12.cnf │ │ ├── sat13.cnf │ │ ├── sat5.cnf │ │ ├── sat6.cnf │ │ ├── sat7.cnf │ │ ├── sat8.cnf │ │ ├── sat9.cnf │ │ ├── elimclash.cnf │ │ ├── elimredundant.cnf │ │ ├── README.md │ │ ├── full4.cnf │ │ ├── ph3.cnf │ │ ├── checkers │ │ │ ├── io.h │ │ │ └── time.h │ │ ├── full5.cnf │ │ ├── ph4.cnf │ │ ├── prime4.cnf │ │ ├── ph5.cnf │ │ └── full6.cnf │ ├── mzn_search │ │ ├── .gitignore │ │ ├── int_warm_start_array.template │ │ ├── int_warm_start.expected │ │ ├── int_warm_start.template │ │ ├── int_warm_start_array.expected │ │ ├── bool_warm_start.expected │ │ ├── bool_warm_start.template │ │ ├── bool_warm_start_array.expected │ │ ├── bool_search_provided_directly.fzn │ │ ├── search_over_ints_no_propagators.fzn │ │ ├── search_annotation_does_not_fix_all_variables.fzn │ │ ├── bool_warm_start_array.template │ │ ├── search_over_bools_no_propagators.fzn │ │ ├── search_over_ints_no_propagators.expected │ │ ├── int_warm_start_array.fzn │ │ ├── int_warm_start.fzn │ │ ├── seq_search_1.fzn │ │ ├── search_with_constants_in_search.expected │ │ ├── bool_search_provided_directly.expected │ │ ├── search_over_bools_no_propagators.expected │ │ ├── bool_warm_start_array.fzn │ │ ├── bool_warm_start.fzn │ │ └── search_annotation_does_not_fix_all_variables.expected │ ├── wcnf │ │ ├── simple.wcnf │ │ ├── .gitignore │ │ ├── normalized_g2x2.wcnf │ │ ├── normalized_g9x3.wcnf │ │ └── checkers │ │ │ └── stream_utils.h │ ├── mzn_constraints │ │ ├── .gitignore │ │ ├── set_in_set.expected │ │ ├── bool2int_set.expected │ │ ├── set_in.expected │ │ ├── bool2int_mix.expected │ │ ├── set_in.fzn │ │ ├── bool2int.expected │ │ ├── binary_int_lin_eq.expected │ │ ├── bool_not.expected │ │ ├── bool_xor.expected │ │ ├── set_in_set.fzn │ │ ├── bool_not.fzn │ │ ├── int_eq.fzn │ │ ├── int_le.fzn │ │ ├── int_lt.fzn │ │ ├── int_ne.fzn │ │ ├── bool2int.fzn │ │ ├── int_abs.fzn │ │ ├── bool_clause.fzn │ │ ├── bool2int_set.fzn │ │ ├── bool_xor.fzn │ │ ├── bool_xor.template │ │ ├── table.expected │ │ ├── int_eq.expected │ │ ├── int_lin_ne.fzn │ │ ├── int_lt.expected │ │ ├── int_lin_le.fzn │ │ ├── set_in_reif_interval.fzn │ │ ├── set_in_reif_sparse.fzn │ │ ├── binary_int_lin_eq.fzn │ │ ├── int_max.fzn │ │ ├── int_min.fzn │ │ ├── int_plus.fzn │ │ ├── int_times.fzn │ │ ├── bool_clause.expected │ │ ├── bool_xor_reif.template │ │ ├── int_eq_reif.fzn │ │ ├── int_le_reif.fzn │ │ ├── int_lt_reif.fzn │ │ ├── int_ne_reif.fzn │ │ ├── int_div.fzn │ │ ├── bool_xor_reif.fzn │ │ ├── array_int_maximum.fzn │ │ ├── array_int_minimum.fzn │ │ ├── int_lin_eq.fzn │ │ ├── int_lin_ne_reif.fzn │ │ ├── unbounded_integer.fzn │ │ ├── cumulative.fzn │ │ ├── int_lin_le_reif.fzn │ │ ├── table.fzn │ │ ├── bool2int_mix.fzn │ │ ├── disjunctive_strict.fzn │ │ ├── int_lin_ne_reif.expected │ │ ├── table.template │ │ ├── all_different.fzn │ │ ├── int_lin_eq_reif.fzn │ │ ├── bool_lin_le.fzn │ │ ├── int_lin_eq.expected │ │ ├── table_reif.fzn │ │ ├── int_le.expected │ │ ├── int_ne.expected │ │ ├── table_reif.template │ │ ├── bool_lin_eq.fzn │ │ ├── bool_xor_reif.expected │ │ ├── disjunctive_strict.template │ │ ├── all_different.template │ │ ├── int_abs.expected │ │ ├── bool_lin_eq.expected │ │ ├── bool_lin_le.expected │ │ ├── set_in_reif_sparse.expected │ │ ├── set_in_reif_interval.expected │ │ ├── cumulative.template │ │ ├── int_le_reif.expected │ │ ├── int_ne_reif.expected │ │ ├── int_eq_reif.expected │ │ ├── int_lt_reif.expected │ │ ├── int_lin_ne.expected │ │ ├── int_mod.fzn │ │ ├── generate_expectations.sh │ │ ├── all_different.expected │ │ ├── int_times.expected │ │ └── unbounded_integer.expected │ ├── mzn_optimization │ │ ├── constant_objective.expected │ │ ├── .gitignore │ │ ├── constant_objective.fzn │ │ ├── unconstrained_objective_maximise.expected │ │ ├── unconstrained_objective_minimise.expected │ │ ├── unfixed_objective.expected │ │ ├── maximise_1.expected │ │ ├── minimise_1.expected │ │ ├── unconstrained_objective_maximise.fzn │ │ ├── unconstrained_objective_minimise.fzn │ │ ├── unfixed_objective.fzn │ │ ├── rcpsp_bl2006.expected │ │ ├── maximise_1.fzn │ │ ├── minimise_1.fzn │ │ ├── ghoulomb_3_5_11.expected │ │ ├── rcpsp_00.expected │ │ └── rcpsp_j60_1_6.expected │ ├── mzn_infeasible │ │ ├── .gitignore │ │ ├── connected.template │ │ └── prop_stress.fzn │ ├── mzn_infeasible_test.rs │ ├── mzn_search_test.rs │ ├── mzn_optimization_test.rs │ └── wcnf_test.rs ├── src │ └── bin │ │ └── pumpkin-solver │ │ ├── parsers │ │ └── mod.rs │ │ ├── maxsat │ │ ├── optimisation │ │ │ ├── mod.rs │ │ │ ├── stopwatch.rs │ │ │ └── optimisation_result.rs │ │ └── encoders │ │ │ ├── weighted_literal.rs │ │ │ └── mod.rs │ │ ├── file_format.rs │ │ ├── flatzinc │ │ ├── compiler │ │ │ ├── reserve_constraint_tags.rs │ │ │ ├── handle_set_in.rs │ │ │ ├── mod.rs │ │ │ └── create_objective.rs │ │ └── error.rs │ │ ├── result.rs │ │ └── os_signal_termination.rs └── Cargo.toml ├── .gitignore ├── pumpkin-crates └── core │ ├── src │ ├── engine │ │ ├── constraint_tag.rs │ │ ├── cp │ │ │ └── trailed │ │ │ │ ├── trailed_change.rs │ │ │ │ ├── mod.rs │ │ │ │ └── trailed_integer.rs │ │ ├── conflict_analysis │ │ │ ├── resolvers │ │ │ │ ├── mod.rs │ │ │ │ └── no_learning_resolver.rs │ │ │ ├── minimisers │ │ │ │ ├── mod.rs │ │ │ │ └── minimiser.rs │ │ │ └── mod.rs │ │ ├── notifications │ │ │ ├── predicate_notification │ │ │ │ └── mod.rs │ │ │ └── domain_event_notification │ │ │ │ ├── mod.rs │ │ │ │ ├── opaque_domain_event.rs │ │ │ │ └── domain_events.rs │ │ ├── termination │ │ │ ├── indefinite.rs │ │ │ ├── combinator.rs │ │ │ ├── time_budget.rs │ │ │ └── mod.rs │ │ ├── variables │ │ │ ├── mod.rs │ │ │ ├── transformable_variable.rs │ │ │ ├── domain_generator_iterator.rs │ │ │ ├── propositional_variable_generator_iterator.rs │ │ │ └── propositional_variable.rs │ │ ├── variable_names.rs │ │ ├── predicates │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── literal_block_distance.rs │ ├── math │ │ ├── mod.rs │ │ └── num_ext.rs │ ├── branching │ │ ├── branchers │ │ │ ├── alternating │ │ │ │ ├── mod.rs │ │ │ │ └── strategies │ │ │ │ │ └── other_only.rs │ │ │ └── mod.rs │ │ ├── variable_selection │ │ │ ├── mod.rs │ │ │ └── dynamic_variable_selector.rs │ │ ├── tie_breaking │ │ │ └── tie_breaker.rs │ │ └── value_selection │ │ │ ├── mod.rs │ │ │ ├── out_domain_max.rs │ │ │ ├── out_domain_min.rs │ │ │ ├── in_domain_min.rs │ │ │ ├── in_domain_max.rs │ │ │ └── dynamic_value_selector.rs │ ├── propagation │ │ ├── contexts │ │ │ └── mod.rs │ │ ├── propagator_var_id.rs │ │ ├── propagator_id.rs │ │ └── local_id.rs │ ├── basic_types │ │ ├── sequence_generators │ │ │ ├── sequence_generator.rs │ │ │ ├── mod.rs │ │ │ ├── constant_sequence.rs │ │ │ └── sequence_generator_type.rs │ │ ├── csp_solver_execution_flag.rs │ │ ├── predicate_id_generators │ │ │ └── mod.rs │ │ ├── moving_averages │ │ │ ├── mod.rs │ │ │ └── moving_average.rs │ │ ├── time.rs │ │ ├── propagation_status_cp.rs │ │ ├── constraint_operation_error.rs │ │ ├── mod.rs │ │ ├── stored_conflict_info.rs │ │ └── function.rs │ ├── propagators │ │ ├── arithmetic │ │ │ ├── binary │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ ├── cumulative │ │ │ ├── time_table │ │ │ │ ├── per_point_incremental_propagator │ │ │ │ │ └── mod.rs │ │ │ │ └── over_interval_incremental_propagator │ │ │ │ │ └── mod.rs │ │ │ └── utils │ │ │ │ ├── mod.rs │ │ │ │ └── structs │ │ │ │ ├── mod.rs │ │ │ │ ├── updated_task_info.rs │ │ │ │ └── resource_profile.rs │ │ ├── disjunctive │ │ │ ├── mod.rs │ │ │ └── disjunctive_task.rs │ │ ├── nogoods │ │ │ ├── mod.rs │ │ │ ├── nogood_id.rs │ │ │ └── nogood_info.rs │ │ └── mod.rs │ ├── constraints │ │ ├── element.rs │ │ └── all_different.rs │ ├── containers │ │ ├── key_generator.rs │ │ └── mod.rs │ ├── optimisation │ │ ├── solution_callback.rs │ │ └── mod.rs │ ├── lib.rs │ └── statistics │ │ └── statistic_logger.rs │ ├── clippy.toml │ └── Cargo.toml ├── rust-toolchain.toml ├── instances ├── simple.wcnf ├── test1.cnf └── unsat-sample.cnf ├── clippy.toml ├── .dockerignore ├── pumpkin-solver-py ├── build.rs ├── tests │ ├── test_constraint_tags.py │ ├── test_optimisation.py │ └── test_assumptions.py ├── pyproject.toml ├── Cargo.toml ├── src │ ├── optimisation.rs │ ├── lib.rs │ ├── result.rs │ └── constraints │ │ └── arguments.rs ├── .gitignore ├── README.md └── examples │ └── nqueens.py ├── .release-please-manifest.json ├── scripts ├── documentation.sh ├── deny.sh ├── fmt.sh └── clippy.sh ├── .cargo └── config.toml ├── minizinc ├── lib │ ├── fzn_all_different_int.mzn │ ├── fzn_table_int.mzn │ ├── fzn_table_int_reif.mzn │ └── fzn_disjunctive_strict.mzn ├── README.md └── Dockerfile ├── .githooks └── pre-commit ├── fzn-rs ├── src │ └── typed │ │ ├── constraint.rs │ │ ├── mod.rs │ │ └── flatzinc_constraint.rs └── Cargo.toml ├── drcp-format ├── Cargo.toml ├── src │ └── reader │ │ └── error.rs └── CHANGELOG.md ├── drcp-debugger └── Cargo.toml ├── fzn-rs-derive ├── Cargo.toml ├── tests │ └── utils.rs └── src │ └── common.rs ├── pumpkin-checker ├── Cargo.toml └── src │ ├── main.rs │ └── inferences │ ├── nogood.rs │ └── time_table.rs ├── pumpkin-macros └── Cargo.toml ├── .github └── workflows │ ├── release-please.yml │ └── reset_reviewed_status.yml ├── release-please-config.json ├── rustfmt.toml └── LICENSE-MIT /pumpkin-solver/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .vscode/ 3 | .idea/ 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/empty.cnf: -------------------------------------------------------------------------------- 1 | p cnf 0 0 2 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/constraint_tag.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit0.cnf: -------------------------------------------------------------------------------- 1 | p cnf 1 1 2 | 1 0 3 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit1.cnf: -------------------------------------------------------------------------------- 1 | p cnf 1 1 2 | -1 0 3 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | -------------------------------------------------------------------------------- /instances/simple.wcnf: -------------------------------------------------------------------------------- 1 | p wcnf 1 2 2 2 | 1 1 0 3 | 2 -1 0 4 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/math/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod num_ext; 2 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/regr000.cnf: -------------------------------------------------------------------------------- 1 | p cnf 10 1 2 | 10 0 3 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full1.cnf: -------------------------------------------------------------------------------- 1 | p cnf 1 2 2 | 1 0 3 | -1 0 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/trivially_false.cnf: -------------------------------------------------------------------------------- 1 | p cnf 0 1 2 | 0 3 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit2.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 2 2 | 1 0 3 | -1 2 0 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit3.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 2 2 | 1 -2 0 3 | -1 0 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sub0.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 2 2 | 1 2 3 0 3 | 1 2 0 4 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | allowed-duplicate-crates = ["regex-automata", "regex-syntax"] 2 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit4.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 3 2 | -1 0 3 | 1 2 0 4 | 1 -2 0 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.err 3 | *.proof 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf/simple.wcnf: -------------------------------------------------------------------------------- 1 | p wcnf 1 2 2 2 | 1 1 0 3 | 2 -1 0 4 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/parsers/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod dimacs; 2 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.err 3 | *.proof 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full2.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 4 2 | 1 2 0 3 | -1 2 0 4 | 1 -2 0 5 | -1 -2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat0.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 4 2 | -1 -2 0 3 | -1 2 0 4 | 1 -2 0 5 | 1 2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat1.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 3 2 | c-1 -2 0 3 | -1 2 0 4 | 1 -2 0 5 | 1 2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat2.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 3 2 | -1 -2 0 3 | c-1 2 0 4 | 1 -2 0 5 | 1 2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat3.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 3 2 | -1 -2 0 3 | -1 2 0 4 | c1 -2 0 5 | 1 2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat4.cnf: -------------------------------------------------------------------------------- 1 | p cnf 2 3 2 | -1 -2 0 3 | -1 2 0 4 | 1 -2 0 5 | c1 2 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit6.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 4 2 | 1 2 3 0 3 | 1 2 -3 0 4 | 1 -2 0 5 | -1 0 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/constant_objective.expected: -------------------------------------------------------------------------------- 1 | ---------- 2 | ========== -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # IDE Files 2 | .vscode/ 3 | .idea/ 4 | 5 | # Build Artifacts 6 | target/ 7 | 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_set.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | ---------- 3 | ========== 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore test artefacts 2 | *.proof 3 | *.err 4 | *.log 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore test artefacts 2 | *.proof 3 | *.drcp 4 | *.err 5 | *.log 6 | -------------------------------------------------------------------------------- /pumpkin-solver-py/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | pyo3_build_config::add_extension_module_link_args(); 3 | } 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit7.cnf: -------------------------------------------------------------------------------- 1 | p cnf 4 5 2 | 1 2 3 -4 0 3 | 1 2 3 4 0 4 | 1 2 -3 0 5 | 1 -2 0 6 | -1 0 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int_set.expected: -------------------------------------------------------------------------------- 1 | l = true; 2 | x1 = 1; 3 | ---------- 4 | ========== 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_infeasible/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.err 3 | *.proof 4 | *.drcp.gz 5 | *.drcp 6 | *.lits 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.err 3 | *.proof 4 | *.drcp.gz 5 | *.drcp 6 | *.lits 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/constant_objective.fzn: -------------------------------------------------------------------------------- 1 | int: objective = 10; 2 | 3 | solve maximize objective; -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/block0.cnf: -------------------------------------------------------------------------------- 1 | c --no-subsume 2 | c --eliminit=0 3 | p cnf 3 3 4 | -1 2 0 5 | -1 3 0 6 | 1 -2 -3 0 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | ---------- 3 | x = 3; 4 | ---------- 5 | ========== 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int_mix.expected: -------------------------------------------------------------------------------- 1 | l = true; 2 | x1 = 1; 3 | x2 = 1; 4 | ---------- 5 | ========== 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unconstrained_objective_maximise.expected: -------------------------------------------------------------------------------- 1 | objective = 5; 2 | ---------- 3 | ========== 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unconstrained_objective_minimise.expected: -------------------------------------------------------------------------------- 1 | objective = 1; 2 | ---------- 3 | ========== 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unfixed_objective.expected: -------------------------------------------------------------------------------- 1 | objective = 3; 2 | other = 1; 3 | ---------- 4 | ========== 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/unit5.cnf: -------------------------------------------------------------------------------- 1 | p cnf 6 7 2 | -1 2 0 3 | -1 3 0 4 | -2 -3 4 0 5 | -4 5 0 6 | -4 6 0 7 | -5 -6 -1 0 8 | 1 0 9 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "pumpkin-solver": "0.2.2", 3 | "drcp-format": "0.3.0", 4 | "pumpkin-crates/core": "0.2.2" 5 | } 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in.fzn: -------------------------------------------------------------------------------- 1 | var 1..4: x :: output_var; 2 | 3 | constraint set_in(x, {1, 3}); 4 | 5 | solve satisfy; 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/maximise_1.expected: -------------------------------------------------------------------------------- 1 | x = 5; 2 | y = 5; 3 | z = 7; 4 | objective = 5; 5 | ---------- 6 | ========== 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/minimise_1.expected: -------------------------------------------------------------------------------- 1 | x = 5; 2 | y = 5; 3 | z = 7; 4 | objective = 7; 5 | ---------- 6 | ========== 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unconstrained_objective_maximise.fzn: -------------------------------------------------------------------------------- 1 | var 1..5: objective :: output_var; 2 | 3 | solve maximize objective; 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unconstrained_objective_minimise.fzn: -------------------------------------------------------------------------------- 1 | var 1..5: objective :: output_var; 2 | 3 | solve minimize objective; 4 | -------------------------------------------------------------------------------- /scripts/documentation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | rustup component add rust-docs 6 | RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -------------------------------------------------------------------------------- /instances/test1.cnf: -------------------------------------------------------------------------------- 1 | p cnf 4 10 2 | -3 -2 0 3 | 4 1 0 4 | -3 -1 0 5 | 1 3 0 6 | -3 1 0 7 | 1 -2 0 8 | 1 -3 0 9 | 4 -1 0 10 | -3 2 0 11 | 1 -4 0 -------------------------------------------------------------------------------- /instances/unsat-sample.cnf: -------------------------------------------------------------------------------- 1 | p cnf 4 8 2 | 1 2 -3 0 3 | -1 -2 3 0 4 | 2 3 -4 0 5 | -2 -3 4 0 6 | 1 3 4 0 7 | -1 -3 -4 0 8 | -1 2 4 0 9 | 1 -2 -4 0 -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int.expected: -------------------------------------------------------------------------------- 1 | l = false; 2 | x1 = 0; 3 | ---------- 4 | l = true; 5 | x1 = 1; 6 | ---------- 7 | ========== 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/binary_int_lin_eq.expected: -------------------------------------------------------------------------------- 1 | x1 = 1; 2 | x2 = 2; 3 | ---------- 4 | x1 = 2; 5 | x2 = 3; 6 | ---------- 7 | ========== 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_not.expected: -------------------------------------------------------------------------------- 1 | x = true; 2 | y = false; 3 | ---------- 4 | x = false; 5 | y = true; 6 | ---------- 7 | ========== 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor.expected: -------------------------------------------------------------------------------- 1 | x = true; 2 | y = false; 3 | ---------- 4 | x = false; 5 | y = true; 6 | ---------- 7 | ========== 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_set.fzn: -------------------------------------------------------------------------------- 1 | var {0, 1, 4}: x :: output_var; 2 | 3 | constraint set_in(x, {1, 3}); 4 | 5 | solve satisfy; 6 | 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/ph2.cnf: -------------------------------------------------------------------------------- 1 | p cnf 6 9 2 | -1 -3 0 3 | -1 -5 0 4 | -3 -5 0 5 | -2 -4 0 6 | -2 -6 0 7 | -4 -6 0 8 | 2 1 0 9 | 4 3 0 10 | 6 5 0 11 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-Ctarget-cpu=native"] 3 | 4 | [target.wasm32-unknown-unknown] 5 | rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full3.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 8 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat10.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | c1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat11.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | c1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat12.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | c1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat13.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | c1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat5.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 8 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat6.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | c-1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat7.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | c-1 -2 3 0 4 | -1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat8.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | c-1 2 -3 0 5 | -1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/sat9.cnf: -------------------------------------------------------------------------------- 1 | p cnf 3 7 2 | -1 -2 -3 0 3 | -1 -2 3 0 4 | -1 2 -3 0 5 | c-1 2 3 0 6 | 1 -2 -3 0 7 | 1 -2 3 0 8 | 1 2 -3 0 9 | 1 2 3 0 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_not.fzn: -------------------------------------------------------------------------------- 1 | var bool: x :: output_var; 2 | var bool: y :: output_var; 3 | 4 | constraint bool_not(x, y); 5 | 6 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_eq.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | 4 | constraint int_eq(x, y); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_le.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | 4 | constraint int_le(x, y); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lt.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | 4 | constraint int_lt(x, y); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_ne.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | 4 | constraint int_ne(x, y); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int.fzn: -------------------------------------------------------------------------------- 1 | var bool: l :: output_var; 2 | var 0..3: x1 :: output_var; 3 | 4 | constraint bool2int(l, x1); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_abs.fzn: -------------------------------------------------------------------------------- 1 | var -3..3: a :: output_var; 2 | var -3..3: b :: output_var; 3 | 4 | constraint int_abs(a, b); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_clause.fzn: -------------------------------------------------------------------------------- 1 | var bool: x :: output_var; 2 | var bool: y :: output_var; 3 | 4 | constraint bool_clause([x], [y]); 5 | 6 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/branchers/alternating/mod.rs: -------------------------------------------------------------------------------- 1 | mod alternating_brancher; 2 | mod strategies; 3 | 4 | pub use alternating_brancher::*; 5 | pub use strategies::*; 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int_set.fzn: -------------------------------------------------------------------------------- 1 | var bool: l :: output_var; 2 | var {1, 3}: x1 :: output_var; 3 | 4 | constraint bool2int(l, x1); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor.fzn: -------------------------------------------------------------------------------- 1 | var bool: x :: output_var; 2 | var bool: y :: output_var; 3 | 4 | constraint pumpkin_bool_xor(x, y); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor.template: -------------------------------------------------------------------------------- 1 | var bool: x:: output_var; 2 | var bool: y:: output_var; 3 | 4 | constraint bool_xor(x, y, true); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/table.expected: -------------------------------------------------------------------------------- 1 | x1 = 2; 2 | x2 = 4; 3 | x3 = 6; 4 | ---------- 5 | x1 = 1; 6 | x2 = 3; 7 | x3 = 10; 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagation/contexts/mod.rs: -------------------------------------------------------------------------------- 1 | mod explanation_context; 2 | mod propagation_context; 3 | 4 | pub use explanation_context::*; 5 | pub use propagation_context::*; 6 | -------------------------------------------------------------------------------- /minizinc/lib/fzn_all_different_int.mzn: -------------------------------------------------------------------------------- 1 | predicate fzn_all_different_int(array[int] of var int: x) = pumpkin_all_different(x); 2 | predicate pumpkin_all_different(array[int] of var int: x); 3 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_eq.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 1; 3 | ---------- 4 | x = 2; 5 | y = 2; 6 | ---------- 7 | x = 3; 8 | y = 3; 9 | ---------- 10 | ========== 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_ne.fzn: -------------------------------------------------------------------------------- 1 | var 0..3: x :: output_var; 2 | var -2..3: y :: output_var; 3 | 4 | constraint int_lin_ne([1, 2], [x, y], 3); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lt.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 2; 3 | ---------- 4 | x = 1; 5 | y = 3; 6 | ---------- 7 | x = 2; 8 | y = 3; 9 | ---------- 10 | ========== 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start_array.template: -------------------------------------------------------------------------------- 1 | var 0..3: x; 2 | var 0..3: y; 3 | 4 | solve :: warm_start_array([warm_start([x], [1]), warm_start([y], [2])]) maximize x + y; 5 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/sequence_generators/sequence_generator.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub(crate) trait SequenceGenerator: Debug { 4 | fn next(&mut self) -> i64; 5 | } 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_le.fzn: -------------------------------------------------------------------------------- 1 | var 0..10: x1 :: output_var; 2 | var 0..10: x2 :: output_var; 3 | 4 | constraint int_lin_le([1, -1], [x1, x2], 0); 5 | 6 | solve satisfy; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/elimclash.cnf: -------------------------------------------------------------------------------- 1 | c --subsume=0 2 | c --eliminit=0 3 | p cnf 5 8 4 | -2 1 0 5 | 2 1 0 6 | -3 -1 0 7 | 3 -1 0 8 | 1 4 5 0 9 | -1 4 5 0 10 | 1 -4 -5 0 11 | -1 -4 -5 0 12 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/elimredundant.cnf: -------------------------------------------------------------------------------- 1 | c --subsume=0 2 | c --eliminit=0 3 | p cnf 5 8 4 | -2 1 0 5 | 2 1 0 6 | -3 1 0 7 | 3 1 0 8 | 1 4 5 0 9 | -1 4 5 0 10 | 1 -4 -5 0 11 | -1 -4 -5 0 12 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_reif_interval.fzn: -------------------------------------------------------------------------------- 1 | var bool : reif :: output_var; 2 | 3 | var 1..7 : x ::output_var; 4 | 5 | constraint set_in_reif(x, 1..3, reif); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_reif_sparse.fzn: -------------------------------------------------------------------------------- 1 | var bool : reif :: output_var; 2 | 3 | var 1..7 : x ::output_var; 4 | 5 | constraint set_in_reif(x, {1, 3}, reif); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | ./scripts/fmt.sh --pre-commit 6 | ./scripts/clippy.sh --pre-commit 7 | ./scripts/documentation.sh --pre-commit 8 | ./scripts/deny.sh --pre-commit 9 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/maxsat/optimisation/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod linear_search; 2 | pub(crate) mod optimisation_result; 3 | pub(crate) mod optimisation_solver; 4 | pub(crate) mod stopwatch; 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/binary_int_lin_eq.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x1 :: output_var; 2 | var 1..3: x2 :: output_var; 3 | 4 | constraint int_lin_eq([-1, 1], [x1, x2], 1); 5 | 6 | solve satisfy; 7 | 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_max.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x1 :: output_var; 2 | var 5..10: x2 :: output_var; 3 | var 1..20: x3 :: output_var; 4 | 5 | constraint int_max(x1, x2, x3); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_min.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x1 :: output_var; 2 | var 5..10: x2 :: output_var; 3 | var 1..20: x3 :: output_var; 4 | 5 | constraint int_min(x1, x2, x3); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_plus.fzn: -------------------------------------------------------------------------------- 1 | var -3..3: a :: output_var; 2 | var -3..3: b :: output_var; 3 | var -3..3: c :: output_var; 4 | 5 | constraint int_plus(a, b, c); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_times.fzn: -------------------------------------------------------------------------------- 1 | var -3..3: a :: output_var; 2 | var -3..3: b :: output_var; 3 | var -3..3: c :: output_var; 4 | 5 | constraint int_times(a, b, c); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 2; 3 | X_INTRODUCED_0_ = 3; 4 | ---------- 5 | x = 3; 6 | y = 3; 7 | X_INTRODUCED_0_ = 6; 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start.template: -------------------------------------------------------------------------------- 1 | var 0..3: x; 2 | var 0..3: y; 3 | 4 | array[1..2] of var int: variables = [x, y]; 5 | 6 | solve :: warm_start(variables, [1, 2]) maximize x + y; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/file_format.rs: -------------------------------------------------------------------------------- 1 | #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] 2 | pub(crate) enum FileFormat { 3 | CnfDimacsPLine, 4 | WcnfDimacsPLine, 5 | FlatZinc, 6 | } 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_clause.expected: -------------------------------------------------------------------------------- 1 | x = false; 2 | y = false; 3 | ---------- 4 | x = true; 5 | y = false; 6 | ---------- 7 | x = true; 8 | y = true; 9 | ---------- 10 | ========== -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor_reif.template: -------------------------------------------------------------------------------- 1 | var bool: r:: output_var; 2 | var bool: x:: output_var; 3 | var bool: y:: output_var; 4 | 5 | constraint bool_xor(x,y,r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_eq_reif.fzn: -------------------------------------------------------------------------------- 1 | var bool: r :: output_var; 2 | var 1..3: x :: output_var; 3 | var 1..3: y :: output_var; 4 | 5 | constraint int_eq_reif(x, y, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_le_reif.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | var bool: r :: output_var; 4 | 5 | constraint int_le_reif(x, y, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lt_reif.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | var bool: r :: output_var; 4 | 5 | constraint int_lt_reif(x, y, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_ne_reif.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x :: output_var; 2 | var 1..3: y :: output_var; 3 | var bool: r :: output_var; 4 | 5 | constraint int_ne_reif(x, y, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start_array.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 2; 3 | X_INTRODUCED_0_ = 3; 4 | ---------- 5 | x = 3; 6 | y = 3; 7 | X_INTRODUCED_0_ = 6; 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/csp_solver_execution_flag.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] 2 | pub enum CSPSolverExecutionFlag { 3 | Feasible, 4 | Infeasible, 5 | Timeout, 6 | } 7 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/arithmetic/binary/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod binary_equals; 2 | pub(crate) mod binary_not_equals; 3 | 4 | pub(crate) use binary_equals::*; 5 | pub(crate) use binary_not_equals::*; 6 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_div.fzn: -------------------------------------------------------------------------------- 1 | var -3..3: a :: output_var; 2 | var {-3, -2, -1, 1, 2, 3}: b :: output_var; 3 | var -3..3: c :: output_var; 4 | 5 | constraint int_div(a, b, c); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start.expected: -------------------------------------------------------------------------------- 1 | x = true; 2 | y = false; 3 | X_INTRODUCED_0_ = 1; 4 | ---------- 5 | x = true; 6 | y = true; 7 | X_INTRODUCED_0_ = 2; 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start.template: -------------------------------------------------------------------------------- 1 | var bool: x; 2 | var bool: y; 3 | 4 | array[1..2] of var bool: variables = [x, y]; 5 | 6 | solve :: warm_start(variables, [true, false]) maximize x + y; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor_reif.fzn: -------------------------------------------------------------------------------- 1 | var bool: r :: output_var; 2 | var bool: x :: output_var; 3 | var bool: y :: output_var; 4 | 5 | constraint pumpkin_bool_xor_reif(x, y, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/time_table/per_point_incremental_propagator/mod.rs: -------------------------------------------------------------------------------- 1 | mod synchronisation; 2 | mod time_table_per_point_incremental; 3 | 4 | pub(crate) use time_table_per_point_incremental::*; 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/README.md: -------------------------------------------------------------------------------- 1 | # DIMACS CNF Tests 2 | These are the test instances for the CNF functionality of the solver. The tests 3 | are taken from the [CaDiCaL](https://github.com/arminbiere/cadical) repository. 4 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start_array.expected: -------------------------------------------------------------------------------- 1 | x = true; 2 | y = false; 3 | X_INTRODUCED_0_ = 1; 4 | ---------- 5 | x = true; 6 | y = true; 7 | X_INTRODUCED_0_ = 2; 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/array_int_maximum.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x1 :: output_var; 2 | var 5..10: x2 :: output_var; 3 | var 1..20: x3 :: output_var; 4 | 5 | constraint array_int_maximum(x3, [x1, x2]); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/array_int_minimum.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x1 :: output_var; 2 | var 5..10: x2 :: output_var; 3 | var 1..20: x3 :: output_var; 4 | 5 | constraint array_int_minimum(x3, [x1, x2]); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_eq.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: x1 :: output_var; 2 | var 1..3: x2 :: output_var; 3 | var 1..3: x3 :: output_var; 4 | 5 | constraint int_lin_eq([-1, 1, 2], [x1, x2, x3], 5); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_ne_reif.fzn: -------------------------------------------------------------------------------- 1 | var bool: r :: output_var; 2 | var 0..0: x :: output_var; 3 | var -1..1: y :: output_var; 4 | 5 | constraint int_lin_ne_reif([1, 1], [x, y], 0, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /minizinc/lib/fzn_table_int.mzn: -------------------------------------------------------------------------------- 1 | predicate pumpkin_table_int(array[int] of var int: x, array[int] of int: t); 2 | 3 | predicate fzn_table_int(array[int] of var int: x, array[int, int] of int: t) = pumpkin_table_int(x, array1d(t)); 4 | 5 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/unbounded_integer.fzn: -------------------------------------------------------------------------------- 1 | var int: x:: output_var; 2 | var -2..2: y:: output_var; 3 | var -2..2: z:: output_var; 4 | 5 | constraint int_le(z,x); 6 | constraint int_le(x,y); 7 | 8 | solve satisfy; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_search_provided_directly.fzn: -------------------------------------------------------------------------------- 1 | var bool: x1 :: output_var; 2 | var bool: x2 :: output_var; 3 | var bool: x3 :: output_var; 4 | 5 | solve :: bool_search([x1, x2, x3], input_order, indomain_max) satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_over_ints_no_propagators.fzn: -------------------------------------------------------------------------------- 1 | var 1..2: x1 :: output_var; 2 | var 2..2: x2 :: output_var; 3 | var 1..2: x3 :: output_var; 4 | 5 | solve :: int_search([x1, x2, x3], input_order, indomain_max) satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/cumulative.fzn: -------------------------------------------------------------------------------- 1 | var 1..5: x :: output_var; 2 | var 3..5: y :: output_var; 3 | var 1..10: z :: output_var; 4 | 5 | constraint pumpkin_cumulative([x, y, z], [1, 2, 3], [1, 2, 1], 2); 6 | 7 | solve satisfy; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_le_reif.fzn: -------------------------------------------------------------------------------- 1 | var 0..10: x1 :: output_var; 2 | var 0..10: x2 :: output_var; 3 | var bool: r :: output_var; 4 | 5 | constraint int_lin_le_reif([1, -1], [x1, x2], 0, r); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/table.fzn: -------------------------------------------------------------------------------- 1 | var 1..10: x1 :: output_var; 2 | var 1..10: x2 :: output_var; 3 | var 1..10: x3 :: output_var; 4 | 5 | constraint pumpkin_table_int([x1, x2, x3], [2, 4, 6, 1, 3, 10]); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/cp/trailed/trailed_change.rs: -------------------------------------------------------------------------------- 1 | use super::TrailedInteger; 2 | 3 | #[derive(Debug, Clone)] 4 | pub(crate) struct TrailedChange { 5 | pub(crate) old_value: i64, 6 | pub(crate) reference: TrailedInteger, 7 | } 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool2int_mix.fzn: -------------------------------------------------------------------------------- 1 | var bool: l :: output_var; 2 | var {1, 3}: x1 :: output_var; 3 | var -10..10: x2 :: output_var; 4 | 5 | constraint bool2int(l, x1); 6 | constraint bool2int(l, x2); 7 | 8 | solve satisfy; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/disjunctive_strict.fzn: -------------------------------------------------------------------------------- 1 | var 0..8: x :: output_var; 2 | var 0..8: y :: output_var; 3 | var 0..8: z :: output_var; 4 | 5 | constraint pumpkin_disjunctive_strict([x, y, z], [2, 3, 5]); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_ne_reif.expected: -------------------------------------------------------------------------------- 1 | r = false; 2 | x = 0; 3 | y = 0; 4 | ---------- 5 | r = true; 6 | x = 0; 7 | y = -1; 8 | ---------- 9 | r = true; 10 | x = 0; 11 | y = 1; 12 | ---------- 13 | ========== 14 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/table.template: -------------------------------------------------------------------------------- 1 | var 1..10: x1 :: output_var; 2 | var 1..10: x2 :: output_var; 3 | var 1..10: x3 :: output_var; 4 | 5 | constraint gecode_table_int([x1, x2, x3], [2, 4, 6, 1, 3, 10]); 6 | 7 | solve satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_annotation_does_not_fix_all_variables.fzn: -------------------------------------------------------------------------------- 1 | var 1..3 : x1 :: output_var; 2 | var 1..3 : x2 :: output_var; 3 | var 1..3 : x3 :: output_var; 4 | 5 | solve :: int_search([x3], input_order, indomain_min) satisfy; -------------------------------------------------------------------------------- /pumpkin-solver-py/tests/test_constraint_tags.py: -------------------------------------------------------------------------------- 1 | from pumpkin_solver import Model 2 | 3 | 4 | def test_constraint_tags_are_created_in_order(): 5 | model = Model() 6 | 7 | t1 = model.new_constraint_tag() 8 | 9 | assert int(t1) == 1 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start_array.template: -------------------------------------------------------------------------------- 1 | var bool: x; 2 | var bool: y; 3 | 4 | array[1..2] of var bool: variables = [x, y]; 5 | 6 | solve :: warm_start_array([warm_start([x], [true]), warm_start([y], [false])]) maximize x + y; 7 | 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/cp/trailed/mod.rs: -------------------------------------------------------------------------------- 1 | mod trailed_change; 2 | mod trailed_integer; 3 | mod trailed_values; 4 | pub(crate) use trailed_change::TrailedChange; 5 | pub use trailed_integer::TrailedInteger; 6 | pub(crate) use trailed_values::TrailedValues; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/all_different.fzn: -------------------------------------------------------------------------------- 1 | var 1..4: x1 :: output_var; 2 | var 1..4: x2 :: output_var; 3 | var 1..4: x3 :: output_var; 4 | var 1..4: x4 :: output_var; 5 | 6 | constraint pumpkin_all_different([x1, x2, x3, x4]); 7 | 8 | solve satisfy; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/unfixed_objective.fzn: -------------------------------------------------------------------------------- 1 | var 1..3: objective :: output_var; 2 | var 1..2: other :: output_var; 3 | 4 | constraint int_lin_le([1, -1], [other, objective], -1); 5 | 6 | solve :: int_search([other], smallest, indomain_min) maximize objective; -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_eq_reif.fzn: -------------------------------------------------------------------------------- 1 | var bool: reif :: output_var; 2 | 3 | var 1..3: x1 :: output_var; 4 | var 1..3: x2 :: output_var; 5 | var 1..3: x3 :: output_var; 6 | 7 | constraint int_lin_eq_reif([-1, 1, 2], [x1, x2, x3], 5, reif); 8 | 9 | solve satisfy; -------------------------------------------------------------------------------- /minizinc/lib/fzn_table_int_reif.mzn: -------------------------------------------------------------------------------- 1 | predicate pumpkin_table_int_reif(array[int] of var int: x, array[int] of int: t, var bool: b); 2 | 3 | predicate fzn_table_int_reif(array[int] of var int: x, array[int, int] of int: t, var bool: b) = pumpkin_table_int_reif(x, array1d(t), b); 4 | 5 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/conflict_analysis/resolvers/mod.rs: -------------------------------------------------------------------------------- 1 | mod conflict_resolver; 2 | mod no_learning_resolver; 3 | mod resolution_resolver; 4 | 5 | pub(crate) use conflict_resolver::*; 6 | pub(crate) use no_learning_resolver::*; 7 | pub(crate) use resolution_resolver::*; 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/disjunctive/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::declare_inference_label; 2 | 3 | pub(crate) mod disjunctive_propagator; 4 | pub(crate) mod disjunctive_task; 5 | mod theta_lambda_tree; 6 | mod theta_tree; 7 | 8 | declare_inference_label!(DisjunctiveEdgeFinding); 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_lin_le.fzn: -------------------------------------------------------------------------------- 1 | array [1..3] of int: X_INTRODUCED_0_ = [-1,2,3]; 2 | var bool: x1:: output_var; 3 | var bool: x2:: output_var; 4 | var bool: x3:: output_var; 5 | 6 | constraint bool_lin_le(X_INTRODUCED_0_,[x1,x2,x3],2); 7 | 8 | solve satisfy; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_over_bools_no_propagators.fzn: -------------------------------------------------------------------------------- 1 | var bool: x1 :: output_var; 2 | var bool: x2 :: output_var; 3 | var bool: x3 :: output_var; 4 | 5 | array [1..3] of var bool: xs = [x1,x2,x3]; 6 | 7 | solve :: bool_search(xs, input_order, indomain_max) satisfy; 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/notifications/predicate_notification/mod.rs: -------------------------------------------------------------------------------- 1 | mod predicate_assignments; 2 | mod predicate_notifier; 3 | mod predicate_tracker_for_domain; 4 | mod predicate_trackers; 5 | 6 | pub(crate) use predicate_assignments::*; 7 | pub(crate) use predicate_notifier::*; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_eq.expected: -------------------------------------------------------------------------------- 1 | x1 = 1; 2 | x2 = 2; 3 | x3 = 2; 4 | ---------- 5 | x1 = 2; 6 | x2 = 3; 7 | x3 = 2; 8 | ---------- 9 | x1 = 2; 10 | x2 = 1; 11 | x3 = 3; 12 | ---------- 13 | x1 = 3; 14 | x2 = 2; 15 | x3 = 3; 16 | ---------- 17 | ========== 18 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/rcpsp_bl2006.expected: -------------------------------------------------------------------------------- 1 | s = [0, 0, 0, 5, 2, 0, 0, 0, 4, 5, 6, 6, 10, 13, 10, 0, 14, 10, 11, 12]; 2 | objective = 17; 3 | ---------- 4 | s = [0, 0, 0, 12, 2, 0, 0, 0, 5, 7, 4, 7, 8, 12, 10, 0, 13, 8, 11, 8]; 5 | objective = 16; 6 | ---------- 7 | ========== 8 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/arithmetic/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod absolute_value; 2 | pub(crate) mod binary; 3 | pub(crate) mod integer_division; 4 | pub(crate) mod integer_multiplication; 5 | pub(crate) mod linear_less_or_equal; 6 | pub(crate) mod linear_not_equal; 7 | pub(crate) mod maximum; 8 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_over_ints_no_propagators.expected: -------------------------------------------------------------------------------- 1 | x1 = 2; 2 | x2 = 2; 3 | x3 = 2; 4 | ---------- 5 | x1 = 2; 6 | x2 = 2; 7 | x3 = 1; 8 | ---------- 9 | x1 = 1; 10 | x2 = 2; 11 | x3 = 2; 12 | ---------- 13 | x1 = 1; 14 | x2 = 2; 15 | x3 = 1; 16 | ---------- 17 | ========== -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/time_table/over_interval_incremental_propagator/mod.rs: -------------------------------------------------------------------------------- 1 | mod checks; 2 | mod debug; 3 | mod insertion; 4 | mod removal; 5 | mod synchronisation; 6 | mod time_table_over_interval_incremental; 7 | 8 | pub(crate) use time_table_over_interval_incremental::*; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/table_reif.fzn: -------------------------------------------------------------------------------- 1 | var 1..10: x1 :: output_var; 2 | var 1..10: x2 :: output_var; 3 | var 1..10: x3 :: output_var; 4 | 5 | var bool: reif :: output_var; 6 | 7 | constraint pumpkin_table_int_reif([x1, x2, x3], [2, 4, 6, 1, 3, 10], reif); 8 | 9 | solve satisfy; 10 | -------------------------------------------------------------------------------- /fzn-rs/src/typed/constraint.rs: -------------------------------------------------------------------------------- 1 | use crate::ast; 2 | 3 | /// A constraint that has annotations attached to it. 4 | #[derive(Clone, Debug)] 5 | pub struct AnnotatedConstraint { 6 | pub constraint: ast::Node, 7 | pub annotations: Vec>, 8 | } 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_le.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 1; 3 | ---------- 4 | x = 1; 5 | y = 2; 6 | ---------- 7 | x = 2; 8 | y = 2; 9 | ---------- 10 | x = 1; 11 | y = 3; 12 | ---------- 13 | x = 2; 14 | y = 3; 15 | ---------- 16 | x = 3; 17 | y = 3; 18 | ---------- 19 | ========== 20 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_ne.expected: -------------------------------------------------------------------------------- 1 | x = 2; 2 | y = 1; 3 | ---------- 4 | x = 3; 5 | y = 1; 6 | ---------- 7 | x = 1; 8 | y = 2; 9 | ---------- 10 | x = 3; 11 | y = 2; 12 | ---------- 13 | x = 1; 14 | y = 3; 15 | ---------- 16 | x = 2; 17 | y = 3; 18 | ---------- 19 | ========== 20 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/table_reif.template: -------------------------------------------------------------------------------- 1 | var 1..10: x1 :: output_var; 2 | var 1..10: x2 :: output_var; 3 | var 1..10: x3 :: output_var; 4 | 5 | var bool: reif :: output_var; 6 | 7 | constraint gecode_table_int_reif([x1, x2, x3], [2, 4, 6, 1, 3, 10], reif); 8 | 9 | solve satisfy; 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full4.cnf: -------------------------------------------------------------------------------- 1 | p cnf 4 16 2 | -1 -2 -3 -4 0 3 | -1 -2 -3 4 0 4 | -1 -2 3 -4 0 5 | -1 -2 3 4 0 6 | -1 2 -3 -4 0 7 | -1 2 -3 4 0 8 | -1 2 3 -4 0 9 | -1 2 3 4 0 10 | 1 -2 -3 -4 0 11 | 1 -2 -3 4 0 12 | 1 -2 3 -4 0 13 | 1 -2 3 4 0 14 | 1 2 -3 -4 0 15 | 1 2 -3 4 0 16 | 1 2 3 -4 0 17 | 1 2 3 4 0 18 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/branchers/mod.rs: -------------------------------------------------------------------------------- 1 | //! Provides several implementations of [`Brancher`]s. 2 | 3 | pub mod alternating; 4 | pub mod autonomous_search; 5 | pub mod dynamic_brancher; 6 | pub mod independent_variable_value_brancher; 7 | pub mod warm_start; 8 | #[cfg(doc)] 9 | use super::Brancher; 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/nogoods/mod.rs: -------------------------------------------------------------------------------- 1 | mod arena_allocator; 2 | mod learning_options; 3 | mod nogood_id; 4 | mod nogood_info; 5 | mod nogood_propagator; 6 | 7 | pub use learning_options::*; 8 | pub(crate) use nogood_id::*; 9 | pub(crate) use nogood_info::*; 10 | pub(crate) use nogood_propagator::*; 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_lin_eq.fzn: -------------------------------------------------------------------------------- 1 | array [1..3] of int: X_INTRODUCED_0_ = [-1,2,3]; 2 | var bool: x1:: output_var; 3 | var bool: x2:: output_var; 4 | var bool: x3:: output_var; 5 | var 1..3: eq:: output_var; 6 | 7 | constraint bool_lin_eq(X_INTRODUCED_0_,[x1,x2,x3],eq); 8 | 9 | solve satisfy; 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_xor_reif.expected: -------------------------------------------------------------------------------- 1 | r = false; 2 | x = false; 3 | y = false; 4 | ---------- 5 | r = true; 6 | x = true; 7 | y = false; 8 | ---------- 9 | r = true; 10 | x = false; 11 | y = true; 12 | ---------- 13 | r = false; 14 | x = true; 15 | y = true; 16 | ---------- 17 | ========== 18 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/predicate_id_generators/mod.rs: -------------------------------------------------------------------------------- 1 | mod deletable_predicate_id_generator; 2 | mod predicate_id_generator; 3 | 4 | pub(crate) use deletable_predicate_id_generator::DeletablePredicateIdGenerator; 5 | pub use predicate_id_generator::PredicateId; 6 | pub(crate) use predicate_id_generator::PredicateIdGenerator; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/ph3.cnf: -------------------------------------------------------------------------------- 1 | p cnf 12 22 2 | -1 -4 0 3 | -1 -7 0 4 | -1 -10 0 5 | -4 -7 0 6 | -4 -10 0 7 | -7 -10 0 8 | -2 -5 0 9 | -2 -8 0 10 | -2 -11 0 11 | -5 -8 0 12 | -5 -11 0 13 | -8 -11 0 14 | -3 -6 0 15 | -3 -9 0 16 | -3 -12 0 17 | -6 -9 0 18 | -6 -12 0 19 | -9 -12 0 20 | 3 2 1 0 21 | 6 5 4 0 22 | 9 8 7 0 23 | 12 11 10 0 24 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/disjunctive_strict.template: -------------------------------------------------------------------------------- 1 | predicate gecode_schedule_unary(array [int] of var int: x,array [int] of int: p); 2 | 3 | var 0..8: x :: output_var; 4 | var 0..8: y :: output_var; 5 | var 0..8: z :: output_var; 6 | 7 | constraint gecode_schedule_unary([x, y, z], [2, 3, 5]); 8 | 9 | solve satisfy; 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/conflict_analysis/minimisers/mod.rs: -------------------------------------------------------------------------------- 1 | mod minimisation_context; 2 | mod minimiser; 3 | mod recursive_minimiser; 4 | mod semantic_minimiser; 5 | 6 | pub(crate) use minimisation_context::*; 7 | pub(crate) use minimiser::*; 8 | pub(crate) use recursive_minimiser::*; 9 | pub(crate) use semantic_minimiser::*; 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/all_different.template: -------------------------------------------------------------------------------- 1 | predicate fzn_all_different_int(array [int] of var int: x); 2 | 3 | var 1..4: x1 :: output_var; 4 | var 1..4: x2 :: output_var; 5 | var 1..4: x3 :: output_var; 6 | var 1..4: x4 :: output_var; 7 | 8 | constraint fzn_all_different_int([x1, x2, x3, x4]); 9 | 10 | solve satisfy; 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_abs.expected: -------------------------------------------------------------------------------- 1 | a = 0; 2 | b = 0; 3 | ---------- 4 | a = -1; 5 | b = 1; 6 | ---------- 7 | a = 1; 8 | b = 1; 9 | ---------- 10 | a = -2; 11 | b = 2; 12 | ---------- 13 | a = 2; 14 | b = 2; 15 | ---------- 16 | a = -3; 17 | b = 3; 18 | ---------- 19 | a = 3; 20 | b = 3; 21 | ---------- 22 | ========== 23 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/maximise_1.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x :: output_var; 2 | var -3..15: y :: output_var; 3 | var 7..25: z :: output_var; 4 | var -10..30: objective :: output_var; 5 | 6 | constraint int_lin_eq([1, 1, 1], [x, y, z], 17); 7 | constraint array_int_minimum(objective, [x, y, z]); 8 | 9 | solve maximize objective; 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/minimise_1.fzn: -------------------------------------------------------------------------------- 1 | var 5..10: x :: output_var; 2 | var -3..15: y :: output_var; 3 | var 7..25: z :: output_var; 4 | var -10..30: objective :: output_var; 5 | 6 | constraint int_lin_eq([1, 1, 1], [x, y, z], 17); 7 | constraint array_int_maximum(objective, [x, y, z]); 8 | 9 | solve minimize objective; 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for propagators of the [Cumulative](https://sofdem.github.io/gccat/gccat/Ccumulative.html) 2 | //! constraint which are generalisable enough to be useful for different types of cumulative 3 | //! propagators 4 | 5 | mod structs; 6 | pub(crate) use structs::*; 7 | 8 | pub(crate) mod util; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/maxsat/encoders/weighted_literal.rs: -------------------------------------------------------------------------------- 1 | use pumpkin_solver::variables::Literal; 2 | 3 | #[derive(Copy, Clone, Debug)] 4 | /// A struct containing a literal, weight and (optionally) the bound which the literal represents 5 | pub(crate) struct WeightedLiteral { 6 | pub(crate) literal: Literal, 7 | pub(crate) weight: u64, 8 | } 9 | -------------------------------------------------------------------------------- /drcp-format/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drcp-format" 3 | version = "0.3.0" 4 | description = "Parse and write DRCP and literal definition files." 5 | license.workspace = true 6 | authors.workspace = true 7 | edition.workspace = true 8 | repository.workspace = true 9 | 10 | [lints] 11 | workspace = true 12 | 13 | [dependencies] 14 | thiserror = "2.0.12" 15 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/moving_averages/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod cumulative_moving_average; 2 | pub(crate) mod moving_average; 3 | pub(crate) mod windowed_moving_average; 4 | 5 | pub(crate) use cumulative_moving_average::CumulativeMovingAverage; 6 | pub(crate) use moving_average::MovingAverage; 7 | pub(crate) use windowed_moving_average::WindowedMovingAverage; 8 | -------------------------------------------------------------------------------- /fzn-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fzn-rs" 3 | version = "0.1.0" 4 | repository.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | authors.workspace = true 8 | 9 | [dependencies] 10 | chumsky = { version = "0.10.1" } 11 | thiserror = "2.0.12" 12 | fzn-rs-derive = { path = "../fzn-rs-derive/" } 13 | 14 | [lints] 15 | workspace = true 16 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_lin_eq.expected: -------------------------------------------------------------------------------- 1 | x1 = true; 2 | x2 = true; 3 | x3 = false; 4 | eq = 1; 5 | ---------- 6 | x1 = false; 7 | x2 = true; 8 | x3 = false; 9 | eq = 2; 10 | ---------- 11 | x1 = true; 12 | x2 = false; 13 | x3 = true; 14 | eq = 2; 15 | ---------- 16 | x1 = false; 17 | x2 = false; 18 | x3 = true; 19 | eq = 3; 20 | ---------- 21 | ========== 22 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start_array.fzn: -------------------------------------------------------------------------------- 1 | var 0..3: x:: output_var; 2 | var 0..3: y:: output_var; 3 | var 0..6: X_INTRODUCED_0_:: is_defined_var :: output_var; 4 | constraint int_lin_eq([1,1,-1],[x,y,X_INTRODUCED_0_],0):: defines_var(X_INTRODUCED_0_):: ctx_pos; 5 | solve :: warm_start_array([warm_start_int([x],[1]),warm_start_int([y],[2])]) maximize X_INTRODUCED_0_; 6 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/termination/indefinite.rs: -------------------------------------------------------------------------------- 1 | use super::TerminationCondition; 2 | 3 | /// A [`TerminationCondition`] which never triggers. The solver can search forever. 4 | #[derive(Clone, Copy, Debug)] 5 | pub struct Indefinite; 6 | 7 | impl TerminationCondition for Indefinite { 8 | fn should_stop(&mut self) -> bool { 9 | false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagation/propagator_var_id.rs: -------------------------------------------------------------------------------- 1 | use crate::propagation::LocalId; 2 | use crate::propagation::PropagatorId; 3 | 4 | /// A handle to a variable registered to a propagator. 5 | #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] 6 | pub(crate) struct PropagatorVarId { 7 | pub(crate) propagator: PropagatorId, 8 | pub(crate) variable: LocalId, 9 | } 10 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/int_warm_start.fzn: -------------------------------------------------------------------------------- 1 | var 0..3: x:: output_var; 2 | var 0..3: y:: output_var; 3 | var 0..6: X_INTRODUCED_0_:: is_defined_var :: output_var; 4 | array [1..2] of var int: variables = [x,y]; 5 | constraint int_lin_eq([1,1,-1],[x,y,X_INTRODUCED_0_],0):: defines_var(X_INTRODUCED_0_):: ctx_pos; 6 | solve :: warm_start_int(variables,[1,2]) maximize X_INTRODUCED_0_; 7 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/bool_lin_le.expected: -------------------------------------------------------------------------------- 1 | x1 = false; 2 | x2 = false; 3 | x3 = false; 4 | ---------- 5 | x1 = true; 6 | x2 = false; 7 | x3 = false; 8 | ---------- 9 | x1 = false; 10 | x2 = true; 11 | x3 = false; 12 | ---------- 13 | x1 = true; 14 | x2 = true; 15 | x3 = false; 16 | ---------- 17 | x1 = true; 18 | x2 = false; 19 | x3 = true; 20 | ---------- 21 | ========== 22 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/checkers/io.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef _WIN32 4 | int getc_unlocked(FILE *stream) { 5 | // On windows, I could not find a way to quickly implement this method 6 | // whilst avoiding locking. So, we lock. The performance will be 7 | // impacted slightly, so if it becomes an issue, this could be re-evaluated. 8 | return getc(stream); 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_reif_sparse.expected: -------------------------------------------------------------------------------- 1 | reif = false; 2 | x = 2; 3 | ---------- 4 | reif = false; 5 | x = 4; 6 | ---------- 7 | reif = false; 8 | x = 5; 9 | ---------- 10 | reif = false; 11 | x = 6; 12 | ---------- 13 | reif = false; 14 | x = 7; 15 | ---------- 16 | reif = true; 17 | x = 1; 18 | ---------- 19 | reif = true; 20 | x = 3; 21 | ---------- 22 | ========== 23 | -------------------------------------------------------------------------------- /drcp-debugger/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drcp-debugger" 3 | version = "0.1.0" 4 | repository.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | authors.workspace = true 8 | 9 | [dependencies] 10 | anyhow = "1.0.97" 11 | clap = { version = "4.5.31", features = ["derive"] } 12 | drcp-format = { path = "../drcp-format" } 13 | 14 | [lints] 15 | workspace = true 16 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/notifications/domain_event_notification/mod.rs: -------------------------------------------------------------------------------- 1 | mod domain_event_watch_list; 2 | pub(crate) mod domain_events; 3 | mod event_sink; 4 | pub(crate) mod opaque_domain_event; 5 | pub use domain_event_watch_list::DomainEvent; 6 | pub(crate) use domain_event_watch_list::WatchListDomainEvents; 7 | pub(crate) use domain_event_watch_list::Watchers; 8 | pub(crate) use event_sink::*; 9 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/set_in_reif_interval.expected: -------------------------------------------------------------------------------- 1 | reif = false; 2 | x = 4; 3 | ---------- 4 | reif = false; 5 | x = 5; 6 | ---------- 7 | reif = false; 8 | x = 6; 9 | ---------- 10 | reif = false; 11 | x = 7; 12 | ---------- 13 | reif = true; 14 | x = 1; 15 | ---------- 16 | reif = true; 17 | x = 2; 18 | ---------- 19 | reif = true; 20 | x = 3; 21 | ---------- 22 | ========== 23 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/ghoulomb_3_5_11.expected: -------------------------------------------------------------------------------- 1 | mark1 = array1d(1..3,[0, 1, 3]); 2 | mark2 = array1d(1..5,[0, 1, 3, 7, 12]); 3 | mark3 = array1d(1..11,[0, 1, 3, 7, 12, 20, 30, 44, 65, 80, 96]); 4 | ---------- 5 | mark1 = array1d(1..3,[0, 1, 3]); 6 | mark2 = array1d(1..5,[0, 1, 4, 9, 11]); 7 | mark3 = array1d(1..11,[0, 1, 3, 7, 12, 20, 30, 44, 65, 80, 96]); 8 | ---------- 9 | ========== 10 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/maxsat/encoders/mod.rs: -------------------------------------------------------------------------------- 1 | mod cardinality_networks_encoder; 2 | mod generalised_totaliser_encoder; 3 | mod pseudo_boolean_constraint_encoder; 4 | mod weighted_literal; 5 | 6 | pub(crate) use cardinality_networks_encoder::*; 7 | pub(crate) use generalised_totaliser_encoder::*; 8 | pub(crate) use pseudo_boolean_constraint_encoder::*; 9 | pub(crate) use weighted_literal::*; 10 | -------------------------------------------------------------------------------- /scripts/deny.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | if [ "$1" = "--pre-commit" ]; then 6 | # We don't install a new cargo-deny in pre-commit unless there isn't one. Update it yourself 7 | cargo deny -V || cargo install cargo-deny 8 | else 9 | # We ignore errors from install, specifically for the error when it's already up-to-date 10 | cargo install cargo-deny || true 11 | fi 12 | cargo deny check 13 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/utils/structs/mod.rs: -------------------------------------------------------------------------------- 1 | mod mandatory_part_adjustments; 2 | mod parameters; 3 | mod resource_profile; 4 | mod task; 5 | mod updatable_structures; 6 | mod updated_task_info; 7 | 8 | pub(crate) use mandatory_part_adjustments::*; 9 | pub(crate) use parameters::*; 10 | pub(crate) use resource_profile::*; 11 | pub(crate) use task::*; 12 | pub(crate) use updatable_structures::*; 13 | pub(crate) use updated_task_info::*; 14 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/nogoods/nogood_id.rs: -------------------------------------------------------------------------------- 1 | use crate::containers::StorageKey; 2 | 3 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)] 4 | pub(crate) struct NogoodId { 5 | pub(crate) id: u32, 6 | } 7 | 8 | impl StorageKey for NogoodId { 9 | fn index(&self) -> usize { 10 | self.id as usize 11 | } 12 | 13 | fn create_from_index(index: usize) -> Self { 14 | NogoodId { id: index as u32 } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/cumulative.template: -------------------------------------------------------------------------------- 1 | predicate gecode_cumulatives(array [int] of var int: start_times, 2 | array [int] of var int: durations, 3 | array [int] of var int: resource_requirements, 4 | var int: resource_capacity 5 | ); 6 | 7 | var 1..5: x:: output_var; 8 | var 3..5: y:: output_var; 9 | var 1..10: z:: output_var; 10 | 11 | constraint gecode_cumulatives([x, y, z], [1, 2, 3], [1, 2, 1], 2); 12 | 13 | solve satisfy; 14 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/seq_search_1.fzn: -------------------------------------------------------------------------------- 1 | var 1..10: x :: output_var; 2 | var 1..10: y :: output_var; 3 | var bool: p :: output_var; 4 | var bool: q :: output_var; 5 | 6 | constraint int_lin_ne([1,-1],[x,y],0); 7 | constraint int_le_reif(6,x,p):: defines_var(p); 8 | constraint int_le_reif(6,y,q):: defines_var(q); 9 | 10 | solve :: seq_search([bool_search([p,q],input_order,indomain_max,complete),int_search([x,y],input_order,indomain_min,complete)]) satisfy; 11 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/conflict_analysis/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains algorithms for conflict analysis, core extraction, and clause minimisation. 2 | //! The algorithms use resolution and implement the 1uip and all decision literal learning schemes 3 | 4 | mod conflict_analysis_context; 5 | mod minimisers; 6 | mod resolvers; 7 | 8 | pub(crate) use conflict_analysis_context::ConflictAnalysisContext; 9 | pub(crate) use minimisers::*; 10 | pub(crate) use resolvers::*; 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_with_constants_in_search.expected: -------------------------------------------------------------------------------- 1 | X_INTRODUCED_17_ = array1d(1..9,[1, 1, 2, 3, 3, 2, 3, 3, 2]); 2 | ---------- 3 | X_INTRODUCED_17_ = array1d(1..9,[1, 1, 2, 3, 2, 2, 3, 3, 3]); 4 | ---------- 5 | X_INTRODUCED_17_ = array1d(1..9,[1, 2, 2, 1, 3, 2, 3, 3, 3]); 6 | ---------- 7 | X_INTRODUCED_17_ = array1d(1..9,[1, 2, 2, 1, 2, 3, 3, 3, 3]); 8 | ---------- 9 | X_INTRODUCED_17_ = array1d(1..9,[1, 3, 2, 1, 3, 2, 3, 3, 2]); 10 | ---------- 11 | ========== -------------------------------------------------------------------------------- /minizinc/README.md: -------------------------------------------------------------------------------- 1 | # Pumpkin MiniZinc Files 2 | 3 | This directory contains the solver configuration file for Pumpkin, as well as 4 | the FlatZinc library. 5 | 6 | 7 | ## MiniZinc Challenge 8 | 9 | The `Dockerfile` in this directory is used to prepare the docker image for the 10 | MiniZinc challenge. To create the image, run the following command from the 11 | project root (aka the Cargo workspace root). 12 | 13 | ``` 14 | $ docker build -t : -f minizinc/Dockerfile . 15 | ``` 16 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/conflict_analysis/minimisers/minimiser.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::conflict_analysis::MinimisationContext; 2 | use crate::predicates::Predicate; 3 | 4 | /// A trait for the behaviour of nogood minimisation approaches. 5 | pub(crate) trait NogoodMinimiser: Default { 6 | /// Takes as input a nogood represented by a [`Vec`] of [`Predicate`]s and minimises the 7 | /// nogood. 8 | fn minimise(&mut self, context: MinimisationContext, nogood: &mut Vec); 9 | } 10 | -------------------------------------------------------------------------------- /pumpkin-crates/core/clippy.toml: -------------------------------------------------------------------------------- 1 | disallowed-types = [ 2 | { path = "std::collections::HashSet", reason = "use pumpkin_solver::containers::HashSet" }, 3 | { path = "std::collections::HashMap", reason = "use pumpkin_solver::containers::HashMap" }, 4 | { path = "rand::RngCore", reason = "use pumpkin_solver::basic_types::Random" }, 5 | { path = "rand::Rng", reason = "use pumpkin_solver::basic_types::Random" }, 6 | { path = "rand::SeedableRng", reason = "use pumpkin_solver::basic_types::Random" }, 7 | ] 8 | -------------------------------------------------------------------------------- /fzn-rs-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fzn-rs-derive" 3 | version = "0.1.0" 4 | repository.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | authors.workspace = true 8 | 9 | [lib] 10 | proc-macro = true 11 | 12 | [dependencies] 13 | convert_case = "0.8.0" 14 | proc-macro2 = "1.0.95" 15 | quote = "1.0.40" 16 | syn = { version = "2.0.104", features = ["extra-traits"] } 17 | 18 | [dev-dependencies] 19 | fzn-rs = { path = "../fzn-rs/" } 20 | 21 | [lints] 22 | workspace = true 23 | -------------------------------------------------------------------------------- /pumpkin-checker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pumpkin-checker" 3 | version = "0.1.0" 4 | repository.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | authors.workspace = true 8 | 9 | [dependencies] 10 | anyhow = "1.0.99" 11 | clap = { version = "4.5.47", features = ["derive"] } 12 | drcp-format = { version = "0.3.0", path = "../drcp-format" } 13 | flate2 = "1.1.2" 14 | fzn-rs = { version = "0.1.0", path = "../fzn-rs" } 15 | thiserror = "2.0.16" 16 | 17 | [lints] 18 | workspace = true 19 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/sequence_generators/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod constant_sequence; 2 | pub(crate) mod geometric_sequence; 3 | pub(crate) mod luby_sequence; 4 | pub(crate) mod sequence_generator; 5 | pub(crate) mod sequence_generator_type; 6 | 7 | pub(crate) use constant_sequence::ConstantSequence; 8 | pub(crate) use geometric_sequence::GeometricSequence; 9 | pub(crate) use luby_sequence::LubySequence; 10 | pub(crate) use sequence_generator::SequenceGenerator; 11 | pub use sequence_generator_type::SequenceGeneratorType; 12 | -------------------------------------------------------------------------------- /pumpkin-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pumpkin-macros" 3 | version = "0.1.0" 4 | description = "Procedural macros used by Pumpkin." 5 | repository.workspace = true 6 | edition.workspace = true 7 | license.workspace = true 8 | authors.workspace = true 9 | 10 | [lib] 11 | name = "pumpkin_macros" 12 | path = "src/lib.rs" 13 | proc-macro = true 14 | 15 | [dependencies] 16 | itertools = "0.13.0" 17 | proc-macro2 = "1.0.89" 18 | quote = "1.0.37" 19 | stringcase = "0.3.0" 20 | syn = "2.0.85" 21 | 22 | [lints] 23 | workspace = true 24 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_le_reif.expected: -------------------------------------------------------------------------------- 1 | x = 2; 2 | y = 1; 3 | r = false; 4 | ---------- 5 | x = 3; 6 | y = 1; 7 | r = false; 8 | ---------- 9 | x = 3; 10 | y = 2; 11 | r = false; 12 | ---------- 13 | x = 1; 14 | y = 1; 15 | r = true; 16 | ---------- 17 | x = 1; 18 | y = 2; 19 | r = true; 20 | ---------- 21 | x = 2; 22 | y = 2; 23 | r = true; 24 | ---------- 25 | x = 1; 26 | y = 3; 27 | r = true; 28 | ---------- 29 | x = 2; 30 | y = 3; 31 | r = true; 32 | ---------- 33 | x = 3; 34 | y = 3; 35 | r = true; 36 | ---------- 37 | ========== 38 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_ne_reif.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 1; 3 | r = false; 4 | ---------- 5 | x = 2; 6 | y = 2; 7 | r = false; 8 | ---------- 9 | x = 3; 10 | y = 3; 11 | r = false; 12 | ---------- 13 | x = 2; 14 | y = 1; 15 | r = true; 16 | ---------- 17 | x = 3; 18 | y = 1; 19 | r = true; 20 | ---------- 21 | x = 1; 22 | y = 2; 23 | r = true; 24 | ---------- 25 | x = 3; 26 | y = 2; 27 | r = true; 28 | ---------- 29 | x = 1; 30 | y = 3; 31 | r = true; 32 | ---------- 33 | x = 2; 34 | y = 3; 35 | r = true; 36 | ---------- 37 | ========== 38 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_eq_reif.expected: -------------------------------------------------------------------------------- 1 | r = false; 2 | x = 2; 3 | y = 1; 4 | ---------- 5 | r = false; 6 | x = 3; 7 | y = 1; 8 | ---------- 9 | r = false; 10 | x = 1; 11 | y = 2; 12 | ---------- 13 | r = false; 14 | x = 3; 15 | y = 2; 16 | ---------- 17 | r = false; 18 | x = 1; 19 | y = 3; 20 | ---------- 21 | r = false; 22 | x = 2; 23 | y = 3; 24 | ---------- 25 | r = true; 26 | x = 1; 27 | y = 1; 28 | ---------- 29 | r = true; 30 | x = 2; 31 | y = 2; 32 | ---------- 33 | r = true; 34 | x = 3; 35 | y = 3; 36 | ---------- 37 | ========== 38 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lt_reif.expected: -------------------------------------------------------------------------------- 1 | x = 1; 2 | y = 1; 3 | r = false; 4 | ---------- 5 | x = 2; 6 | y = 1; 7 | r = false; 8 | ---------- 9 | x = 3; 10 | y = 1; 11 | r = false; 12 | ---------- 13 | x = 2; 14 | y = 2; 15 | r = false; 16 | ---------- 17 | x = 3; 18 | y = 2; 19 | r = false; 20 | ---------- 21 | x = 3; 22 | y = 3; 23 | r = false; 24 | ---------- 25 | x = 1; 26 | y = 2; 27 | r = true; 28 | ---------- 29 | x = 1; 30 | y = 3; 31 | r = true; 32 | ---------- 33 | x = 2; 34 | y = 3; 35 | r = true; 36 | ---------- 37 | ========== 38 | -------------------------------------------------------------------------------- /pumpkin-solver-py/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.7,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pumpkin-solver" 7 | requires-python = ">=3.8" 8 | classifiers = [ 9 | "Programming Language :: Rust", 10 | "Programming Language :: Python :: Implementation :: CPython", 11 | "Programming Language :: Python :: Implementation :: PyPy", 12 | ] 13 | dynamic = ["version"] 14 | [project.optional-dependencies] 15 | tests = [ 16 | "pytest", 17 | ] 18 | [tool.maturin] 19 | features = ["pyo3/extension-module"] 20 | -------------------------------------------------------------------------------- /pumpkin-checker/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Parser; 4 | 5 | #[derive(Parser)] 6 | struct Cli { 7 | /// Path to the model file (.fzn). 8 | model_path: PathBuf, 9 | 10 | /// Path to the proof file. 11 | /// 12 | /// If the path ends in `.gz`, we assume it is GZipped and the checker will unzip the file 13 | /// on-the-fly. 14 | proof_path: PathBuf, 15 | } 16 | 17 | fn main() -> anyhow::Result<()> { 18 | let cli = Cli::parse(); 19 | 20 | pumpkin_checker::run_checker(cli.model_path, cli.proof_path) 21 | } 22 | -------------------------------------------------------------------------------- /scripts/fmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | if [ "$1" = "--pre-commit" ]; then 6 | # We don't install/update nightly in pre-commit unless there isn't one. If this command fails then please update fmt (e.g. by using `rustup update`). 7 | if ! rustup toolchain list | grep --silent 'nightly-[a-z]'; then 8 | rustup toolchain install --no-self-update --profile minimal --component rustfmt -- nightly 9 | fi 10 | else 11 | rustup toolchain install --no-self-update --profile minimal --component rustfmt -- nightly 12 | fi 13 | cargo +nightly fmt --check 14 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/cp/trailed/trailed_integer.rs: -------------------------------------------------------------------------------- 1 | use crate::containers::StorageKey; 2 | 3 | /// An integer whose value is automatically restored upon backtracking to its previous value at the 4 | /// checkpoint to which backtracking occurred. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct TrailedInteger { 7 | id: u32, 8 | } 9 | 10 | impl StorageKey for TrailedInteger { 11 | fn index(&self) -> usize { 12 | self.id as usize 13 | } 14 | 15 | fn create_from_index(index: usize) -> Self { 16 | Self { id: index as u32 } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_search_provided_directly.expected: -------------------------------------------------------------------------------- 1 | x1 = true; 2 | x2 = true; 3 | x3 = true; 4 | ---------- 5 | x1 = true; 6 | x2 = true; 7 | x3 = false; 8 | ---------- 9 | x1 = true; 10 | x2 = false; 11 | x3 = true; 12 | ---------- 13 | x1 = true; 14 | x2 = false; 15 | x3 = false; 16 | ---------- 17 | x1 = false; 18 | x2 = true; 19 | x3 = true; 20 | ---------- 21 | x1 = false; 22 | x2 = true; 23 | x3 = false; 24 | ---------- 25 | x1 = false; 26 | x2 = false; 27 | x3 = true; 28 | ---------- 29 | x1 = false; 30 | x2 = false; 31 | x3 = false; 32 | ---------- 33 | ========== -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_over_bools_no_propagators.expected: -------------------------------------------------------------------------------- 1 | x1 = true; 2 | x2 = true; 3 | x3 = true; 4 | ---------- 5 | x1 = true; 6 | x2 = true; 7 | x3 = false; 8 | ---------- 9 | x1 = true; 10 | x2 = false; 11 | x3 = true; 12 | ---------- 13 | x1 = true; 14 | x2 = false; 15 | x3 = false; 16 | ---------- 17 | x1 = false; 18 | x2 = true; 19 | x3 = true; 20 | ---------- 21 | x1 = false; 22 | x2 = true; 23 | x3 = false; 24 | ---------- 25 | x1 = false; 26 | x2 = false; 27 | x3 = true; 28 | ---------- 29 | x1 = false; 30 | x2 = false; 31 | x3 = false; 32 | ---------- 33 | ========== 34 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | permissions: 7 | contents: write 8 | pull-requests: write 9 | 10 | name: Release Please 11 | 12 | jobs: 13 | handle-releases: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Release Please 17 | id: release-please 18 | uses: googleapis/release-please-action@v4 19 | with: 20 | token: ${{ secrets.RELEASE_PLEASE_TOKEN }} 21 | config-file: release-please-config.json 22 | manifest-file: .release-please-manifest.json 23 | 24 | -------------------------------------------------------------------------------- /scripts/clippy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | if [ "$1" = "--pre-commit" ]; then 6 | # We don't install/update nightly in pre-commit unless there isn't one. If this command fails then please update clippy (e.g. by using `rustup update`). 7 | if ! rustup toolchain list | grep --silent 'nightly-[a-z]'; then 8 | rustup toolchain install --no-self-update --profile minimal --component clippy -- nightly 9 | fi 10 | else 11 | rustup toolchain install --no-self-update --profile minimal --component clippy -- nightly 12 | fi 13 | 14 | cargo +nightly clippy --all-targets -- -Dwarnings 15 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/moving_averages/moving_average.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub(crate) trait MovingAverage: Debug { 4 | fn add_term(&mut self, new_term: Term); 5 | 6 | /// Returns the moving average value; in case there are no terms, the convention is to return 0 7 | fn value(&self) -> f64; 8 | 9 | /// Adapts the internal data structures to take into account the given interval length; this 10 | /// makes sense for moving averages that consider the k previous points, e.g., windowed moving 11 | /// average 12 | fn adapt(&mut self, interval_length: u64); 13 | } 14 | -------------------------------------------------------------------------------- /fzn-rs/src/typed/mod.rs: -------------------------------------------------------------------------------- 1 | mod arrays; 2 | mod constraint; 3 | mod flatzinc_annotation; 4 | mod flatzinc_constraint; 5 | mod from_literal; 6 | mod instance; 7 | 8 | use std::rc::Rc; 9 | 10 | pub use arrays::*; 11 | pub use constraint::*; 12 | pub use flatzinc_annotation::*; 13 | pub use flatzinc_constraint::*; 14 | pub use from_literal::*; 15 | pub use instance::*; 16 | 17 | /// Models a variable in the FlatZinc AST. Since `var T` is a subtype of `T`, a variable can also 18 | /// be a constant. 19 | #[derive(Clone, Debug, PartialEq, Eq)] 20 | pub enum VariableExpr { 21 | Identifier(Rc), 22 | Constant(T), 23 | } 24 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/time.rs: -------------------------------------------------------------------------------- 1 | //! Platform-agnostic time types. 2 | //! 3 | //! On native platforms, this re-exports from `std::time`. 4 | //! On WASM, this re-exports from `web-time` which uses the browser's `Performance` API. 5 | //! 6 | //! All code in pumpkin-core should use these types instead of `std::time` directly. 7 | 8 | #[cfg(not(target_arch = "wasm32"))] 9 | pub use std::time::Duration; 10 | #[cfg(not(target_arch = "wasm32"))] 11 | pub use std::time::Instant; 12 | 13 | #[cfg(target_arch = "wasm32")] 14 | pub use web_time::Duration; 15 | #[cfg(target_arch = "wasm32")] 16 | pub use web_time::Instant; 17 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/checkers/time.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef _WIN32 4 | 5 | typedef long suseconds_t; 6 | 7 | struct timeval { 8 | time_t tv_sec; 9 | suseconds_t tv_usec; 10 | }; 11 | 12 | int gettimeofday(struct timeval *tv, void *unused) { 13 | time(&tv->tv_sec); 14 | 15 | // For now, we zero the number of microseconds. If we want more precision, 16 | // we should expand this function to correctly determine the number of 17 | // microseconds since the epoch - tv_sec. 18 | 19 | tv->tv_usec = 0; 20 | 21 | return 0; 22 | } 23 | 24 | #else 25 | 26 | #include 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "pumpkin-solver": { 4 | "release-type": "rust" 5 | }, 6 | "pumpkin-crates/core": { 7 | "release-type": "rust" 8 | }, 9 | "drcp-format": { 10 | "release-type": "rust" 11 | } 12 | }, 13 | "pull-request-title-pattern": "chore: release ${component} ${version}", 14 | "bump-minor-pre-major": true, 15 | "bump-patch-for-minor-pre-major": true, 16 | "draft": false, 17 | "prerelease": false, 18 | "separate-pull-requests": true, 19 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" 20 | } 21 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full5.cnf: -------------------------------------------------------------------------------- 1 | p cnf 5 32 2 | -5 -1 -2 -3 -4 0 3 | -5 -1 -2 -3 4 0 4 | -5 -1 -2 3 -4 0 5 | -5 -1 -2 3 4 0 6 | -5 -1 2 -3 -4 0 7 | -5 -1 2 -3 4 0 8 | -5 -1 2 3 -4 0 9 | -5 -1 2 3 4 0 10 | -5 1 -2 -3 -4 0 11 | -5 1 -2 -3 4 0 12 | -5 1 -2 3 -4 0 13 | -5 1 -2 3 4 0 14 | -5 1 2 -3 -4 0 15 | -5 1 2 -3 4 0 16 | -5 1 2 3 -4 0 17 | -5 1 2 3 4 0 18 | 5 -1 -2 -3 -4 0 19 | 5 -1 -2 -3 4 0 20 | 5 -1 -2 3 -4 0 21 | 5 -1 -2 3 4 0 22 | 5 -1 2 -3 -4 0 23 | 5 -1 2 -3 4 0 24 | 5 -1 2 3 -4 0 25 | 5 -1 2 3 4 0 26 | 5 1 -2 -3 -4 0 27 | 5 1 -2 -3 4 0 28 | 5 1 -2 3 -4 0 29 | 5 1 -2 3 4 0 30 | 5 1 2 -3 -4 0 31 | 5 1 2 -3 4 0 32 | 5 1 2 3 -4 0 33 | 5 1 2 3 4 0 34 | -------------------------------------------------------------------------------- /pumpkin-solver-py/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pumpkin-solver-py" 3 | version = "0.2.2" 4 | description = "The Python interface for the Pumpkin solver library." 5 | authors.workspace = true 6 | license.workspace = true 7 | edition.workspace = true 8 | repository.workspace = true 9 | 10 | 11 | [lib] 12 | name = "pumpkin_solver" 13 | crate-type = ["cdylib"] 14 | # Don't build cargo documentation for this crate. 15 | doc = false 16 | 17 | [dependencies] 18 | pyo3 = { version = "0.25.1", features= ["extension-module"] } 19 | pumpkin-solver = { version = "0.2.2", path = "../pumpkin-solver" } 20 | 21 | [build-dependencies] 22 | pyo3-build-config = "0.25.1" 23 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # imports are single line only to better work with line-based diffs like git 2 | imports_granularity = "Item" 3 | # imports are sorted to better work with line-based diffs like git 4 | group_imports = "StdExternalCrate" 5 | 6 | # wraps comments if they exceed `comment_width` 7 | wrap_comments = true 8 | # maximum length of comments 9 | comment_width = 120 10 | # also format the code in doc comments 11 | format_code_in_doc_comments = true 12 | # normalizes /* */ comments to // where possible 13 | normalize_comments = true 14 | # errors if the formatter is unable to get comments or string literals in the required width 15 | error_on_unformatted = true 16 | -------------------------------------------------------------------------------- /drcp-format/src/reader/error.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::num::NonZero; 3 | 4 | #[cfg(doc)] 5 | use super::ProofReader; 6 | 7 | /// The errors that can be encountered by the [`ProofReader`]. 8 | #[derive(Debug, thiserror::Error)] 9 | pub enum Error { 10 | #[error("failed to read from source: {0}")] 11 | IoError(#[from] io::Error), 12 | 13 | #[error("failed to parse proof line {line_nr} {span:?}: {reason}")] 14 | ParseError { 15 | line_nr: usize, 16 | reason: String, 17 | span: (usize, usize), 18 | }, 19 | 20 | #[error("undefined atomic {code} on line {line}")] 21 | UndefinedAtomic { line: usize, code: NonZero }, 22 | } 23 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/ph4.cnf: -------------------------------------------------------------------------------- 1 | p cnf 20 45 2 | -1 -5 0 3 | -1 -9 0 4 | -1 -13 0 5 | -1 -17 0 6 | -5 -9 0 7 | -5 -13 0 8 | -5 -17 0 9 | -9 -13 0 10 | -9 -17 0 11 | -13 -17 0 12 | -2 -6 0 13 | -2 -10 0 14 | -2 -14 0 15 | -2 -18 0 16 | -6 -10 0 17 | -6 -14 0 18 | -6 -18 0 19 | -10 -14 0 20 | -10 -18 0 21 | -14 -18 0 22 | -3 -7 0 23 | -3 -11 0 24 | -3 -15 0 25 | -3 -19 0 26 | -7 -11 0 27 | -7 -15 0 28 | -7 -19 0 29 | -11 -15 0 30 | -11 -19 0 31 | -15 -19 0 32 | -4 -8 0 33 | -4 -12 0 34 | -4 -16 0 35 | -4 -20 0 36 | -8 -12 0 37 | -8 -16 0 38 | -8 -20 0 39 | -12 -16 0 40 | -12 -20 0 41 | -16 -20 0 42 | 4 3 2 1 0 43 | 8 7 6 5 0 44 | 12 11 10 9 0 45 | 16 15 14 13 0 46 | 20 19 18 17 0 47 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/disjunctive/disjunctive_task.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | #[cfg(doc)] 4 | use crate::constraints; 5 | use crate::propagation::LocalId; 6 | 7 | /// Defines the input of the [`constraints::disjunctive_strict`] constraint. 8 | /// 9 | /// Each task has a variable starting time and a constant processing time. 10 | #[derive(Debug, Clone)] 11 | pub struct ArgDisjunctiveTask { 12 | pub start_time: Var, 13 | pub processing_time: i32, 14 | } 15 | 16 | #[derive(Clone, Debug)] 17 | pub(super) struct DisjunctiveTask { 18 | pub(crate) start_time: Var, 19 | pub(crate) processing_time: i32, 20 | pub(crate) id: LocalId, 21 | } 22 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variables/mod.rs: -------------------------------------------------------------------------------- 1 | //! A variable, in the context of the solver, is a view onto a domain. It may forward domain 2 | //! information unaltered, or apply transformations which can be performed without the need of 3 | //! constraints. 4 | 5 | mod affine_view; 6 | mod domain_generator_iterator; 7 | mod domain_id; 8 | mod integer_variable; 9 | mod literal; 10 | mod transformable_variable; 11 | 12 | pub use affine_view::AffineView; 13 | pub(crate) use domain_generator_iterator::DomainGeneratorIterator; 14 | pub use domain_id::DomainId; 15 | pub use integer_variable::IntegerVariable; 16 | pub use literal::Literal; 17 | pub use transformable_variable::TransformableVariable; 18 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start_array.fzn: -------------------------------------------------------------------------------- 1 | var bool: x:: output_var; 2 | var bool: y:: output_var; 3 | var 0..2: X_INTRODUCED_0_:: output_var:: is_defined_var; 4 | var 0..1: X_INTRODUCED_2_ ::var_is_introduced :: is_defined_var; 5 | var 0..1: X_INTRODUCED_3_ ::var_is_introduced :: is_defined_var; 6 | constraint int_lin_eq([1,1,-1],[X_INTRODUCED_3_,X_INTRODUCED_2_,X_INTRODUCED_0_],0):: defines_var(X_INTRODUCED_0_):: ctx_pos; 7 | constraint bool2int(y,X_INTRODUCED_2_):: defines_var(X_INTRODUCED_2_); 8 | constraint bool2int(x,X_INTRODUCED_3_):: defines_var(X_INTRODUCED_3_); 9 | solve :: warm_start_array([warm_start_bool([x],[true]),warm_start_bool([y],[false])]) maximize X_INTRODUCED_0_; 10 | 11 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/bool_warm_start.fzn: -------------------------------------------------------------------------------- 1 | var bool: x:: output_var; 2 | var bool: y:: output_var; 3 | var 0..2: X_INTRODUCED_0_:: output_var:: is_defined_var; 4 | var 0..1: X_INTRODUCED_2_ ::var_is_introduced :: is_defined_var; 5 | var 0..1: X_INTRODUCED_3_ ::var_is_introduced :: is_defined_var; 6 | array [1..2] of var bool: variables = [x,y]; 7 | constraint int_lin_eq([1,1,-1],[X_INTRODUCED_3_,X_INTRODUCED_2_,X_INTRODUCED_0_],0):: defines_var(X_INTRODUCED_0_):: ctx_pos; 8 | constraint bool2int(y,X_INTRODUCED_2_):: defines_var(X_INTRODUCED_2_); 9 | constraint bool2int(x,X_INTRODUCED_3_):: defines_var(X_INTRODUCED_3_); 10 | solve :: warm_start_bool(variables,[true,false]) maximize X_INTRODUCED_0_; 11 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/notifications/domain_event_notification/opaque_domain_event.rs: -------------------------------------------------------------------------------- 1 | use super::DomainEvent; 2 | #[cfg(doc)] 3 | use crate::engine::variables::IntegerVariable; 4 | 5 | /// A [`DomainEvent`] that happened in the solver. 6 | /// 7 | /// Obtain the event from the perspective of a variable through [`IntegerVariable::unpack_event`]. 8 | #[derive(Clone, Debug, Copy)] 9 | pub struct OpaqueDomainEvent(DomainEvent); 10 | 11 | impl From for OpaqueDomainEvent { 12 | fn from(event: DomainEvent) -> Self { 13 | OpaqueDomainEvent(event) 14 | } 15 | } 16 | 17 | impl OpaqueDomainEvent { 18 | pub(crate) fn unwrap(self) -> DomainEvent { 19 | self.0 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains propagator implementations that are used in Pumpkin. 2 | //! 3 | //! See the [`propagation`] for info on propagators. 4 | #[cfg(doc)] 5 | use crate::propagation; 6 | 7 | pub(crate) mod arithmetic; 8 | mod cumulative; 9 | mod disjunctive; 10 | pub(crate) mod element; 11 | pub(crate) mod nogoods; 12 | mod reified_propagator; 13 | pub(crate) use arithmetic::*; 14 | pub use cumulative::CumulativeExplanationType; 15 | pub use cumulative::CumulativeOptions; 16 | pub use cumulative::CumulativePropagationMethod; 17 | pub(crate) use cumulative::*; 18 | pub use disjunctive::disjunctive_task::ArgDisjunctiveTask; 19 | pub(crate) use disjunctive::*; 20 | pub(crate) use reified_propagator::*; 21 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf/normalized_g2x2.wcnf: -------------------------------------------------------------------------------- 1 | c Standarized MaxSat Instance 2 | c{ 3 | c "sha1sum": "715131b909f8c9f190705fbf541bd0b7e2e95126", 4 | c "nvars": 4, 5 | c "ncls": 8, 6 | c "nhards": 4, 7 | c "nhard_len_stats": 8 | c { "min": 3, "max": 3, "ave": 3.00, 9 | c "stddev": 0.00 }, 10 | c "nsofts": 4, 11 | c "nsoft_len_stats": 12 | c { "min": 1, "max": 1, "ave": 1.00, 13 | c "stddev": 0.00 }, 14 | c "nsoft_wts": 1, 15 | c "soft_wt_stats": 16 | c { "min": 1, "max": 1, "ave": 1.00, 17 | c "stddev": 0.00 } 18 | c} 19 | c------------------------------------------------------------ 20 | c SUBTRACT 0 21 | p wcnf 4 8 5 22 | 1 -1 0 23 | 1 -2 0 24 | 1 -3 0 25 | 1 -4 0 26 | 5 1 2 3 0 27 | 5 1 3 4 0 28 | 5 1 2 4 0 29 | 5 2 3 4 0 30 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/maxsat/optimisation/stopwatch.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | use std::time::Instant; 3 | 4 | /// A time keeping utility which keeps track of the elapsed time since creation. 5 | #[derive(Debug, Copy, Clone)] 6 | 7 | pub(crate) struct Stopwatch { 8 | time_start: Instant, 9 | } 10 | 11 | impl Stopwatch { 12 | /// Create a new [`Stopwatch`] which starts keeping track of time immediately. 13 | pub(crate) fn starting_now() -> Stopwatch { 14 | Stopwatch { 15 | time_start: Instant::now(), 16 | } 17 | } 18 | 19 | /// Get the duration since the [`Stopwatch`] was created. 20 | pub(crate) fn elapsed(&self) -> Duration { 21 | self.time_start.elapsed() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/constraints/element.rs: -------------------------------------------------------------------------------- 1 | use super::Constraint; 2 | use crate::proof::ConstraintTag; 3 | use crate::propagators::element::ElementArgs; 4 | use crate::variables::IntegerVariable; 5 | 6 | /// Creates the [element](https://sofdem.github.io/gccat/gccat/Celement.html) [`Constraint`] which states that `array[index] = rhs`. 7 | pub fn element( 8 | index: impl IntegerVariable + 'static, 9 | array: impl IntoIterator, 10 | rhs: impl IntegerVariable + 'static, 11 | constraint_tag: ConstraintTag, 12 | ) -> impl Constraint { 13 | ElementArgs { 14 | array: array.into_iter().collect(), 15 | index, 16 | rhs, 17 | constraint_tag, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/termination/combinator.rs: -------------------------------------------------------------------------------- 1 | use super::TerminationCondition; 2 | 3 | /// A [`TerminationCondition`] which triggers when one of two given [`TerminationCondition`]s 4 | /// triggers. 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Combinator { 7 | t1: T1, 8 | t2: T2, 9 | } 10 | 11 | impl Combinator { 12 | /// Combine two [`TerminationCondition`]s into one. 13 | pub fn new(t1: T1, t2: T2) -> Self { 14 | Combinator { t1, t2 } 15 | } 16 | } 17 | 18 | impl TerminationCondition 19 | for Combinator 20 | { 21 | fn should_stop(&mut self) -> bool { 22 | self.t1.should_stop() || self.t2.should_stop() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/containers/key_generator.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use super::StorageKey; 4 | 5 | /// Generates a sequence of [`StorageKey`]s. 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct KeyGenerator { 8 | key: PhantomData, 9 | counter: usize, 10 | } 11 | 12 | impl Default for KeyGenerator { 13 | fn default() -> Self { 14 | Self { 15 | key: Default::default(), 16 | counter: Default::default(), 17 | } 18 | } 19 | } 20 | 21 | impl KeyGenerator { 22 | /// Generate a new `Key`. 23 | pub fn next_key(&mut self) -> Key { 24 | let key = Key::create_from_index(self.counter); 25 | self.counter += 1; 26 | key 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagation/propagator_id.rs: -------------------------------------------------------------------------------- 1 | use crate::containers::StorageKey; 2 | 3 | /// An identifier to a propagator instance within the solver. 4 | /// Each propagator is assigned a unique identifier at runtime. 5 | #[repr(transparent)] 6 | #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] 7 | pub struct PropagatorId(pub(crate) u32); 8 | 9 | impl std::fmt::Display for PropagatorId { 10 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 11 | write!(f, "PropagatorId({})", self.0) 12 | } 13 | } 14 | 15 | impl StorageKey for PropagatorId { 16 | fn index(&self) -> usize { 17 | self.0 as usize 18 | } 19 | 20 | fn create_from_index(index: usize) -> Self { 21 | PropagatorId(index as u32) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/prime4.cnf: -------------------------------------------------------------------------------- 1 | c 1 = x@1 2 | c 2 = x@0 3 | c 3 = y@1 4 | c 4 = y@0 5 | p cnf 20 49 6 | -5 -1 0 7 | -5 2 0 8 | 1 -2 5 0 9 | -6 -3 0 10 | -6 4 0 11 | 3 -4 6 0 12 | -7 -5 0 13 | -7 -6 0 14 | 5 6 7 0 15 | -8 2 0 16 | -8 4 0 17 | -2 -4 8 0 18 | -9 2 0 19 | -9 3 0 20 | -2 -3 9 0 21 | -10 1 0 22 | -10 4 0 23 | -1 -4 10 0 24 | -11 9 0 25 | -11 10 0 26 | -9 -10 11 0 27 | -12 -9 0 28 | -12 -10 0 29 | 9 10 12 0 30 | -13 -11 0 31 | -13 -12 0 32 | 11 12 13 0 33 | -14 1 0 34 | -14 3 0 35 | -1 -3 14 0 36 | -15 14 0 37 | -15 11 0 38 | -14 -11 15 0 39 | -16 -14 0 40 | -16 -11 0 41 | 14 11 16 0 42 | -17 -15 0 43 | -17 -16 0 44 | 15 16 17 0 45 | -18 -13 0 46 | -18 17 0 47 | 13 -17 18 0 48 | -19 -8 0 49 | -19 18 0 50 | 8 -18 19 0 51 | -20 7 0 52 | -20 19 0 53 | -7 -19 20 0 54 | 20 0 55 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variable_names.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::containers::HashMap; 4 | use crate::engine::variables::DomainId; 5 | 6 | #[derive(Debug, Default, Clone)] 7 | pub(crate) struct VariableNames { 8 | integers: HashMap>, 9 | } 10 | 11 | impl VariableNames { 12 | /// Get the name associated with a domain id. 13 | pub(crate) fn get_int_name(&self, domain_id: DomainId) -> Option<&str> { 14 | self.integers.get(&domain_id).map(|s| s.as_ref()) 15 | } 16 | 17 | /// Add a name to the integer variable. This will override existing the name if it 18 | /// exists. 19 | pub(crate) fn add_integer(&mut self, integer: DomainId, name: Arc) { 20 | let _ = self.integers.insert(integer, name); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/conflict_analysis/resolvers/no_learning_resolver.rs: -------------------------------------------------------------------------------- 1 | use super::ConflictResolver; 2 | use crate::engine::conflict_analysis::ConflictAnalysisContext; 3 | 4 | /// Resolve conflicts by backtracking one decision level trying the opposite of the last decision. 5 | #[derive(Default, Debug, Clone, Copy)] 6 | pub(crate) struct NoLearningResolver; 7 | 8 | impl ConflictResolver for NoLearningResolver { 9 | fn resolve_conflict(&mut self, context: &mut ConflictAnalysisContext) { 10 | let last_decision = context 11 | .find_last_decision() 12 | .expect("the solver is not at decision level 0, so there exists a last decision"); 13 | 14 | context.backtrack(context.state.get_checkpoint() - 1); 15 | context.enqueue_propagated_predicate(!last_decision); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/containers/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains containers which are used by the solver. 2 | mod key_generator; 3 | mod key_value_heap; 4 | mod keyed_vec; 5 | mod sparse_set; 6 | 7 | use fnv::FnvBuildHasher; 8 | pub use key_generator::*; 9 | pub use key_value_heap::*; 10 | pub use keyed_vec::*; 11 | pub(crate) use sparse_set::*; 12 | 13 | /// [`std::collections::HashMap`] that defaults to a deterministic hasher. 14 | #[allow(clippy::disallowed_types, reason = "this is how we define our HashMap")] 15 | pub type HashMap = std::collections::HashMap; 16 | /// [`std::collections::HashSet`] that defaults to a deterministic hasher. 17 | #[allow(clippy::disallowed_types, reason = "this is how we define our HashSet")] 18 | pub type HashSet = std::collections::HashSet; 19 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/rcpsp_00.expected: -------------------------------------------------------------------------------- 1 | s = [0, 10, 0, 14, 1, 17, 14, 30, 17, 15, 23, 23, 30, 36, 6, 39, 42, 15, 34, 27, 48, 34, 39, 49, 30, 47, 41, 51, 49, 50]; 2 | objective = 58; 3 | ---------- 4 | s = [0, 10, 0, 14, 1, 17, 14, 30, 17, 15, 23, 23, 30, 36, 6, 39, 42, 15, 34, 27, 42, 34, 39, 43, 30, 47, 43, 51, 44, 50]; 5 | objective = 57; 6 | ---------- 7 | s = [0, 10, 0, 14, 1, 17, 14, 30, 17, 15, 23, 23, 30, 34, 6, 37, 40, 15, 34, 27, 41, 32, 37, 46, 40, 45, 42, 49, 42, 49]; 8 | objective = 55; 9 | ---------- 10 | s = [4, 0, 4, 4, 5, 7, 4, 17, 14, 5, 23, 21, 30, 30, 13, 33, 36, 10, 34, 23, 20, 28, 36, 28, 38, 44, 41, 48, 29, 48]; 11 | objective = 54; 12 | ---------- 13 | s = [5, 1, 0, 5, 1, 8, 5, 28, 15, 6, 21, 21, 28, 32, 6, 35, 38, 16, 32, 19, 39, 24, 35, 44, 38, 43, 40, 47, 40, 47]; 14 | objective = 53; 15 | ---------- 16 | ========== 17 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variables/transformable_variable.rs: -------------------------------------------------------------------------------- 1 | /// Trait for transforming a variable. 2 | /// 3 | /// At the moment this allows creating a scaled version of a 4 | /// variable using [`TransformableVariable::scaled`] or creating a variable with a constant offset 5 | /// based on the original variable using [`TransformableVariable::offset`]. 6 | pub trait TransformableVariable { 7 | /// Get a variable which domain is scaled compared to the domain of self. 8 | /// 9 | /// The scaled domain will have holes in it. E.g. if we have `dom(x) = {1, 2}`, then 10 | /// `dom(x.scaled(2)) = {2, 4}` and *not* `dom(x.scaled(2)) = {1, 2, 3, 4}`. 11 | fn scaled(&self, scale: i32) -> View; 12 | 13 | /// Get a variable which domain has a constant offset to the domain of self. 14 | fn offset(&self, offset: i32) -> View; 15 | } 16 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization/rcpsp_j60_1_6.expected: -------------------------------------------------------------------------------- 1 | s = [0, 0, 0, 3, 12, 13, 18, 15, 13, 24, 14, 3, 12, 7, 2, 6, 15, 15, 22, 22, 6, 3, 7, 16, 7, 27, 22, 20, 29, 23, 23, 2, 37, 24, 33, 31, 24, 12, 20, 28, 37, 38, 2, 45, 54, 29, 37, 29, 27, 45, 47, 61, 45, 61, 45, 64, 54, 63, 55, 65]; 2 | objective = 69; 3 | ---------- 4 | s = [0, 0, 0, 3, 12, 13, 18, 15, 13, 24, 14, 3, 12, 7, 2, 6, 15, 15, 22, 22, 6, 3, 7, 16, 7, 27, 22, 20, 29, 23, 23, 2, 37, 24, 33, 31, 24, 12, 20, 28, 37, 38, 2, 52, 45, 29, 37, 29, 27, 45, 47, 52, 45, 61, 45, 64, 54, 54, 55, 65]; 5 | objective = 67; 6 | ---------- 7 | s = [0, 0, 0, 3, 12, 13, 18, 15, 13, 24, 14, 3, 12, 7, 2, 6, 15, 15, 22, 22, 6, 3, 7, 16, 7, 27, 22, 23, 29, 22, 23, 2, 37, 28, 23, 31, 24, 12, 20, 31, 37, 37, 2, 51, 44, 29, 37, 32, 27, 45, 47, 51, 44, 60, 45, 63, 54, 54, 55, 64]; 8 | objective = 66; 9 | ---------- 10 | ========== 11 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/constraints/all_different.rs: -------------------------------------------------------------------------------- 1 | use super::Constraint; 2 | use super::binary_not_equals; 3 | use crate::proof::ConstraintTag; 4 | use crate::variables::IntegerVariable; 5 | 6 | /// Creates the [`Constraint`] that enforces that all the given `variables` are distinct. 7 | pub fn all_different( 8 | variables: impl Into>, 9 | constraint_tag: ConstraintTag, 10 | ) -> impl Constraint { 11 | let variables: Box<[Var]> = variables.into(); 12 | let mut constraints = Vec::new(); 13 | 14 | for i in 0..variables.len() { 15 | for j in i + 1..variables.len() { 16 | constraints.push(binary_not_equals( 17 | variables[i].clone(), 18 | variables[j].clone(), 19 | constraint_tag, 20 | )); 21 | } 22 | } 23 | 24 | constraints 25 | } 26 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/maxsat/optimisation/optimisation_result.rs: -------------------------------------------------------------------------------- 1 | use pumpkin_solver::results::Solution; 2 | 3 | #[cfg(doc)] 4 | use super::optimisation_solver::OptimisationSolver; 5 | 6 | /// The result of calling [`OptimisationSolver::solve()`]. 7 | #[derive(Debug)] 8 | pub(crate) enum MaxSatOptimisationResult { 9 | /// There exists no solution with a better objective value than this one. 10 | Optimal { solution: Solution }, 11 | /// The optimal solution was not found within the time budget. However, at least one solution 12 | /// was found. The provided solution is the solution with the best objective value that was 13 | /// encountered. 14 | Satisfiable { best_solution: Solution }, 15 | /// No solutions exist to the constraint satisfaction problem. 16 | Infeasible, 17 | /// No solution was found within the time budget. 18 | Unknown, 19 | } 20 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/optimisation/solution_callback.rs: -------------------------------------------------------------------------------- 1 | use crate::Solver; 2 | use crate::branching::Brancher; 3 | use crate::results::SolutionReference; 4 | 5 | pub trait SolutionCallback { 6 | fn on_solution_callback(&self, solver: &Solver, solution: SolutionReference, brancher: &B); 7 | } 8 | 9 | impl SolutionCallback for T { 10 | fn on_solution_callback(&self, solver: &Solver, solution: SolutionReference, brancher: &B) { 11 | (self)(solver, solution, brancher) 12 | } 13 | } 14 | 15 | impl, B: Brancher> SolutionCallback for Option { 16 | fn on_solution_callback(&self, solver: &Solver, solution: SolutionReference, brancher: &B) { 17 | if let Some(callback) = self { 18 | callback.on_solution_callback(solver, solution, brancher) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_infeasible/connected.template: -------------------------------------------------------------------------------- 1 | % https://github.com/ConSol-Lab/Pumpkin/issues/321 2 | int: n = 4; 3 | 4 | array [1..n,1..n] of var bool: node_active = [| 5 | false, true, true, false| 6 | true, false, false, true| 7 | true, true, true, true| 8 | true, false, false, false |]; 9 | 10 | % check if you can reach every active node from active node 11 | include "connected.mzn"; 12 | constraint connected( 13 | [x + (y-1)*n | x in 1..n-1, y in 1..n] ++ [x + (y-1)*n | x in 1..n, y in 1..n-1], 14 | [x + (y-1)*n | x in 2..n, y in 1..n] ++ [x + (y-1)*n | x in 1..n, y in 2..n], 15 | [node_active[x, y] | y in 1..n, x in 1..n], 16 | % an edge is in the subgraph if from and to are active 17 | [(node_active[x, y]) /\ (node_active[x + 1, y]) | x in 1..n-1, y in 1..n] 18 | ++ [(node_active[x, y]) /\ (node_active[x, y + 1]) | x in 1..n, y in 1..n-1], 19 | ); 20 | 21 | solve satisfy; 22 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/flatzinc/compiler/reserve_constraint_tags.rs: -------------------------------------------------------------------------------- 1 | //! This compiler pass reserves constraint tags for all the constraints in the model. This is 2 | //! necessary because adding a constraint can cause inferences to be introduced in the proof. 3 | //! However, we assume that the first n constraint tags are the flatzinc constraints. Therefore, 4 | //! the root-level inferences would throw off that mapping. 5 | 6 | use super::context::CompilationContext; 7 | use crate::flatzinc::ast::FlatZincAst; 8 | use crate::flatzinc::error::FlatZincError; 9 | 10 | pub(crate) fn run( 11 | ast: &FlatZincAst, 12 | context: &mut CompilationContext, 13 | ) -> Result<(), FlatZincError> { 14 | for decl in &ast.constraint_decls { 15 | let tag = context.solver.new_constraint_tag(); 16 | context.constraints.push((tag, decl.clone())); 17 | } 18 | 19 | Ok(()) 20 | } 21 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variables/domain_generator_iterator.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::variables::DomainId; 2 | 3 | #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] 4 | pub struct DomainGeneratorIterator { 5 | current_index: u32, 6 | end_index: u32, 7 | } 8 | 9 | impl DomainGeneratorIterator { 10 | pub fn new(start_index: u32, end_index: u32) -> DomainGeneratorIterator { 11 | DomainGeneratorIterator { 12 | current_index: start_index, 13 | end_index, 14 | } 15 | } 16 | } 17 | 18 | impl Iterator for DomainGeneratorIterator { 19 | type Item = DomainId; 20 | 21 | fn next(&mut self) -> Option { 22 | if self.current_index == self.end_index { 23 | return None; 24 | } 25 | 26 | let variable = DomainId::new(self.current_index); 27 | self.current_index += 1; 28 | 29 | Some(variable) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pumpkin-solver-py/tests/test_optimisation.py: -------------------------------------------------------------------------------- 1 | from pumpkin_solver import Model 2 | from pumpkin_solver.optimisation import Direction, OptimisationResult 3 | 4 | 5 | def test_linear_sat_unsat_minimisation(): 6 | model = Model() 7 | 8 | objective = model.new_integer_variable(1, 5, name="objective") 9 | 10 | result = model.optimise(objective, direction=Direction.Minimise) 11 | 12 | assert isinstance(result, OptimisationResult.Optimal) 13 | 14 | solution = result._0 15 | assert solution.int_value(objective) == 1 16 | 17 | 18 | def test_linear_sat_unsat_maximisation(): 19 | model = Model() 20 | 21 | objective = model.new_integer_variable(1, 5, name="objective") 22 | 23 | result = model.optimise(objective, direction=Direction.Maximise) 24 | 25 | assert isinstance(result, OptimisationResult.Optimal) 26 | 27 | solution = result._0 28 | assert solution.int_value(objective) == 5 29 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_lin_ne.expected: -------------------------------------------------------------------------------- 1 | x = 0; 2 | y = 2; 3 | ---------- 4 | x = 1; 5 | y = 2; 6 | ---------- 7 | x = 1; 8 | y = 3; 9 | ---------- 10 | x = 0; 11 | y = 3; 12 | ---------- 13 | x = 2; 14 | y = 3; 15 | ---------- 16 | x = 2; 17 | y = 1; 18 | ---------- 19 | x = 3; 20 | y = 1; 21 | ---------- 22 | x = 3; 23 | y = 2; 24 | ---------- 25 | x = 3; 26 | y = 3; 27 | ---------- 28 | x = 2; 29 | y = 2; 30 | ---------- 31 | x = 2; 32 | y = -2; 33 | ---------- 34 | x = 1; 35 | y = -2; 36 | ---------- 37 | x = 3; 38 | y = -2; 39 | ---------- 40 | x = 3; 41 | y = -1; 42 | ---------- 43 | x = 2; 44 | y = -1; 45 | ---------- 46 | x = 1; 47 | y = -1; 48 | ---------- 49 | x = 1; 50 | y = 0; 51 | ---------- 52 | x = 2; 53 | y = 0; 54 | ---------- 55 | x = 0; 56 | y = 0; 57 | ---------- 58 | x = 0; 59 | y = -1; 60 | ---------- 61 | x = 0; 62 | y = 1; 63 | ---------- 64 | x = 0; 65 | y = -2; 66 | ---------- 67 | ========== 68 | -------------------------------------------------------------------------------- /pumpkin-checker/src/inferences/nogood.rs: -------------------------------------------------------------------------------- 1 | use crate::inferences::Fact; 2 | use crate::inferences::InvalidInference; 3 | use crate::model::Constraint; 4 | use crate::state::VariableState; 5 | 6 | /// Verifies a `nogood` inference. 7 | /// 8 | /// This inference is used to rewrite a nogood `L /\ p -> false` to `L -> not p`. 9 | pub(crate) fn verify_nogood(fact: &Fact, constraint: &Constraint) -> Result<(), InvalidInference> { 10 | let Constraint::Nogood(nogood) = constraint else { 11 | return Err(InvalidInference::ConstraintLabelMismatch); 12 | }; 13 | 14 | let variable_state = VariableState::prepare_for_conflict_check(fact) 15 | .ok_or(InvalidInference::InconsistentPremises)?; 16 | 17 | let is_implied_by_nogood = nogood.iter().all(|atomic| variable_state.is_true(atomic)); 18 | 19 | if is_implied_by_nogood { 20 | Ok(()) 21 | } else { 22 | Err(InvalidInference::Unsound) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagation/local_id.rs: -------------------------------------------------------------------------------- 1 | use crate::containers::StorageKey; 2 | 3 | /// A local id uniquely identifies a variable within a specific propagator. A local id can be 4 | /// thought of as the index of the variable in the propagator. 5 | #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] 6 | pub struct LocalId(u32); 7 | 8 | impl LocalId { 9 | pub const fn from(value: u32) -> Self { 10 | LocalId(value) 11 | } 12 | 13 | pub fn unpack(self) -> u32 { 14 | self.0 15 | } 16 | } 17 | 18 | impl StorageKey for LocalId { 19 | fn index(&self) -> usize { 20 | self.0 as usize 21 | } 22 | 23 | fn create_from_index(index: usize) -> Self { 24 | LocalId::from(index as u32) 25 | } 26 | } 27 | 28 | impl std::fmt::Display for LocalId { 29 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 30 | write!(f, "{}", self.0) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/utils/structs/updated_task_info.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use super::Task; 4 | 5 | /// Stores the information of an updated task; for example in the context of 6 | /// [`TimeTablePerPointPropagator`] this is a task whose mandatory part has changed. 7 | #[derive(Debug, Clone)] 8 | pub(crate) struct UpdatedTaskInfo { 9 | /// The task which has been updated (where "updated" is according to some context-dependent 10 | /// definition) 11 | pub(crate) task: Rc>, 12 | /// The lower-bound of the [`Task`] before the update 13 | pub(crate) old_lower_bound: i32, 14 | /// The upper-bound of the [`Task`] before the update 15 | pub(crate) old_upper_bound: i32, 16 | /// The lower-bound of the [`Task`] after the update 17 | pub(crate) new_lower_bound: i32, 18 | /// The upper-bound of the [`Task`] after the update 19 | pub(crate) new_upper_bound: i32, 20 | } 21 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_mod.fzn: -------------------------------------------------------------------------------- 1 | % This is testing the redefinition that we have specified 2 | % This is the original input before compilation: 3 | % var -3..3: a :: output_var; 4 | % var {-3, -2, -1, 1, 2, 3}: b :: output_var; 5 | % var -3..3: c :: output_var; 6 | % 7 | % constraint int_mod(a, b, c); 8 | % 9 | % solve satisfy; 10 | 11 | array [1..3] of int: X_INTRODUCED_4_ = [1,-1,-1]; 12 | var -3..3: a:: is_defined_var:: output_var; 13 | var {-3,-2,-1,1,2,3}: b:: output_var; 14 | var -3..3: c:: output_var; 15 | var -3..3: X_INTRODUCED_1_ ::var_is_introduced :: is_defined_var; 16 | var -9..9: X_INTRODUCED_2_ ::var_is_introduced :: is_defined_var; 17 | constraint int_div(a,b,X_INTRODUCED_1_):: defines_var(X_INTRODUCED_1_); 18 | constraint int_lin_eq(X_INTRODUCED_4_,[a,X_INTRODUCED_2_,c],0):: defines_var(a); 19 | constraint int_times(X_INTRODUCED_1_,b,X_INTRODUCED_2_):: defines_var(X_INTRODUCED_2_); 20 | solve satisfy; 21 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/propagation_status_cp.rs: -------------------------------------------------------------------------------- 1 | use super::PropositionalConjunction; 2 | use crate::proof::InferenceCode; 3 | use crate::state::Conflict; 4 | 5 | /// The result of invoking a constraint programming propagator. The propagation can either succeed 6 | /// or identify a conflict. The necessary conditions for the conflict must be captured in the error 7 | /// variant, i.e. a propositional conjunction. 8 | pub(crate) type PropagationStatusCP = Result<(), Conflict>; 9 | 10 | /// A conflict stated by a propagator. A propagator that identifies a conflict that is _not_ an 11 | /// empty domain, describes that conflict with this type. 12 | #[derive(Clone, Debug, PartialEq, Eq)] 13 | pub struct PropagatorConflict { 14 | /// The conjunction that describes the infeasible partial assignment. 15 | pub conjunction: PropositionalConjunction, 16 | /// The inference code that identified the conflict. 17 | pub inference_code: InferenceCode, 18 | } 19 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/termination/time_budget.rs: -------------------------------------------------------------------------------- 1 | use super::TerminationCondition; 2 | use crate::basic_types::time::Duration; 3 | use crate::basic_types::time::Instant; 4 | 5 | /// A [`TerminationCondition`] which triggers when the specified time budget has been exceeded. 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct TimeBudget { 8 | /// The point in time from which to measure the budget. 9 | started_at: Instant, 10 | /// The amount of time before [`TimeBudget::should_stop()`] becomes true. 11 | budget: Duration, 12 | } 13 | 14 | impl TimeBudget { 15 | /// Give the solver a time budget, starting now. 16 | pub fn starting_now(budget: Duration) -> TimeBudget { 17 | let started_at = Instant::now(); 18 | 19 | TimeBudget { started_at, budget } 20 | } 21 | } 22 | 23 | impl TerminationCondition for TimeBudget { 24 | fn should_stop(&mut self) -> bool { 25 | self.started_at.elapsed() >= self.budget 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/sequence_generators/constant_sequence.rs: -------------------------------------------------------------------------------- 1 | use super::SequenceGenerator; 2 | 3 | // A sequence that generates the same value 4 | #[derive(Debug, Copy, Clone)] 5 | pub(crate) struct ConstantSequence { 6 | constant_value: i64, 7 | } 8 | 9 | impl ConstantSequence { 10 | pub(crate) fn new(constant_value: i64) -> ConstantSequence { 11 | ConstantSequence { constant_value } 12 | } 13 | } 14 | 15 | impl SequenceGenerator for ConstantSequence { 16 | fn next(&mut self) -> i64 { 17 | self.constant_value 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use super::ConstantSequence; 24 | use crate::basic_types::sequence_generators::SequenceGenerator; 25 | 26 | #[test] 27 | fn test_basic() { 28 | let constant_value = 100; 29 | let mut constant_sequence = ConstantSequence::new(constant_value); 30 | for _i in 0..1000 { 31 | assert!(constant_sequence.next() == constant_value); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variables/propositional_variable_generator_iterator.rs: -------------------------------------------------------------------------------- 1 | use crate::engine::variables::PropositionalVariable; 2 | 3 | #[derive(Debug, Copy, Clone)] 4 | pub struct PropositionalVariableGeneratorIterator { 5 | current_index: u32, 6 | end_index: u32, 7 | } 8 | 9 | impl PropositionalVariableGeneratorIterator { 10 | pub fn new(start_index: u32, end_index: u32) -> PropositionalVariableGeneratorIterator { 11 | PropositionalVariableGeneratorIterator { 12 | current_index: start_index, 13 | end_index, 14 | } 15 | } 16 | } 17 | 18 | impl Iterator for PropositionalVariableGeneratorIterator { 19 | type Item = PropositionalVariable; 20 | 21 | fn next(&mut self) -> Option { 22 | if self.current_index >= self.end_index { 23 | return None; 24 | } 25 | 26 | let variable = PropositionalVariable::new(self.current_index); 27 | self.current_index += 1; 28 | 29 | Some(variable) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/result.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use thiserror::Error; 4 | 5 | use crate::flatzinc::error::FlatZincError; 6 | use crate::parsers::dimacs::DimacsParseError; 7 | 8 | pub(crate) type PumpkinResult = Result; 9 | 10 | #[derive(Error, Debug)] 11 | 12 | pub(crate) enum PumpkinError { 13 | #[error("IO error, more details: {0}")] 14 | IOError(#[from] std::io::Error), 15 | #[error("The file {0} is not supported.")] 16 | InvalidInstanceFile(String), 17 | #[error("The dimacs file was invalid, more details: {0}")] 18 | InvalidDimacs(#[from] DimacsParseError), 19 | #[error("Failed to run flatzinc model, more details: {0}")] 20 | FlatZinc(#[from] FlatZincError), 21 | #[error("Proof generation for {0} is not supported.")] 22 | ProofGenerationNotSupported(String), 23 | } 24 | 25 | impl PumpkinError { 26 | pub(crate) fn invalid_instance(path: impl Display) -> Self { 27 | Self::InvalidInstanceFile(format!("{path}")) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pumpkin-solver-py/src/optimisation.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | use crate::result::Solution; 4 | 5 | #[pyclass] 6 | pub enum OptimisationResult { 7 | /// The problem was solved to optimality, and the solution is an optimal one. 8 | Optimal(Solution), 9 | /// At least one solution was identified, and the solution is the best one. 10 | Satisfiable(Solution), 11 | /// The problem was unsatisfiable. 12 | Unsatisfiable(), 13 | /// None of the other variants were concluded. 14 | Unknown(), 15 | } 16 | 17 | #[pyclass(eq, eq_int)] 18 | #[derive(Clone, Copy, PartialEq, Eq)] 19 | pub enum Optimiser { 20 | LinearSatUnsat, 21 | LinearUnsatSat, 22 | } 23 | 24 | #[pyclass(eq, eq_int)] 25 | #[derive(Clone, Copy, PartialEq, Eq)] 26 | pub enum Direction { 27 | Minimise, 28 | Maximise, 29 | } 30 | 31 | pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> { 32 | m.add_class::()?; 33 | m.add_class::()?; 34 | m.add_class::()?; 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /pumpkin-solver-py/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | .pytest_cache/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | .venv/ 14 | env/ 15 | bin/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | include/ 26 | man/ 27 | venv/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | pip-selfcheck.json 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | 48 | # Mr Developer 49 | .mr.developer.cfg 50 | .project 51 | .pydevproject 52 | 53 | # Rope 54 | .ropeproject 55 | 56 | # Django stuff: 57 | *.log 58 | *.pot 59 | 60 | .DS_Store 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyCharm 66 | .idea/ 67 | 68 | # VSCode 69 | .vscode/ 70 | 71 | # Pyenv 72 | .python-version 73 | -------------------------------------------------------------------------------- /fzn-rs/src/typed/flatzinc_constraint.rs: -------------------------------------------------------------------------------- 1 | use super::FromLiteral; 2 | use crate::InstanceError; 3 | use crate::Token; 4 | use crate::ast; 5 | 6 | /// Parse a constraint from the given [`ast::Constraint`]. 7 | pub trait FlatZincConstraint: Sized { 8 | fn from_ast(constraint: &ast::Node) -> Result; 9 | } 10 | 11 | /// Extract an argument from the [`ast::Argument`] node. 12 | pub trait FromArgument: Sized { 13 | fn from_argument(argument: &ast::Node) -> Result; 14 | } 15 | 16 | impl FromArgument for T { 17 | fn from_argument(argument: &ast::Node) -> Result { 18 | match &argument.node { 19 | ast::Argument::Literal(literal) => T::from_literal(literal), 20 | ast::Argument::Array(_) => Err(InstanceError::UnexpectedToken { 21 | expected: T::expected(), 22 | actual: Token::Array, 23 | span: argument.span, 24 | }), 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/constraint_operation_error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[cfg(doc)] 4 | use crate::Solver; 5 | 6 | /// Errors related to adding constraints to the [`Solver`]. 7 | #[derive(Error, Debug, Copy, Clone, PartialEq, Eq)] 8 | pub enum ConstraintOperationError { 9 | #[error("Adding the nogood failed because it is infeasible at the root")] 10 | InfeasibleNogood, 11 | /// Error which indicate that adding a clause led to infeasibility at the root. 12 | #[error("Adding the clause failed because it is infeasible at the root")] 13 | InfeasibleClause, 14 | /// Error which indicates that a constraint was attempted to be added while the [`Solver`] was 15 | /// in an infeasible state. 16 | #[error("Adding constraint failed because the solver is in an infeasible state")] 17 | InfeasibleState, 18 | /// Error which indicate that adding a propagator led to infeasibility at the root. 19 | #[error("Adding the constraint failed because it is infeasible at the root")] 20 | InfeasiblePropagator, 21 | } 22 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/predicates/mod.rs: -------------------------------------------------------------------------------- 1 | //! Structures which represent certain [predicates](https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)). 2 | //! 3 | //! The solver only utilizes the following types of predicates: 4 | //! - **Predicates over integers** - These [`IntegerPredicate`]s specify atomic constraints of the 5 | //! form `[x >= v]`, `[x <= v]`, `[x == v]`, and `[x != v]`. 6 | //! - **Predicates over literals** - These [`Predicate::Literal`]s specify [`Literal`]s which are 7 | //! linked to the aforementioned [`IntegerPredicate`]s through the [`VariableLiteralMappings`]. 8 | //! - **Always True/False** - The [`Predicate::True`]/[`Predicate::False`] specify logical 9 | //! predicates which are always true/false. 10 | //! 11 | //! In general, these [`Predicate`]s are used to represent propagations, explanations or decisions. 12 | pub(crate) mod predicate; 13 | pub(crate) mod predicate_constructor; 14 | #[cfg(doc)] 15 | use crate::engine::predicates::predicate::Predicate; 16 | #[cfg(doc)] 17 | use crate::engine::variables::IntegerVariable; 18 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/variables/propositional_variable.rs: -------------------------------------------------------------------------------- 1 | use crate::basic_types::StorageKey; 2 | #[cfg(doc)] 3 | use crate::variables::Literal; 4 | 5 | /// A boolean variable in the solver; unlike [`Literal`], this representation does not use a 6 | /// polarity. 7 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 8 | pub struct PropositionalVariable { 9 | index: u32, 10 | } 11 | 12 | impl PropositionalVariable { 13 | pub fn new(index: u32) -> PropositionalVariable { 14 | PropositionalVariable { index } 15 | } 16 | 17 | pub fn get_index(&self) -> u32 { 18 | self.index 19 | } 20 | } 21 | 22 | impl std::fmt::Display for PropositionalVariable { 23 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 24 | write!(f, "p{}", self.index) 25 | } 26 | } 27 | 28 | impl StorageKey for PropositionalVariable { 29 | fn index(&self) -> usize { 30 | self.index as usize 31 | } 32 | 33 | fn create_from_index(index: usize) -> Self { 34 | PropositionalVariable::new(index as u32) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/generate_expectations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generate all the `.expected` files for the `.fzn` files in this directory. 4 | # Assumes the current working directory is the directory of the script itself. 5 | 6 | for input in ./*.fzn; 7 | do 8 | test_name=${input%.fzn} 9 | test_name=${test_name#./} 10 | echo "Generating expectation for '$test_name'" 11 | 12 | expectation_file=$test_name.expected 13 | 14 | # If there is a $test_name.template.fzn file, use it to generate the 15 | # expectation. This means the flatzinc contains a global which has been 16 | # specialized to pumpkin itself, and thus Gecode will not recognize it. 17 | 18 | if [[ -f $test_name.template ]]; 19 | then 20 | fzn=$test_name.actual.fzn 21 | cp $test_name.template $fzn 22 | echo " Using template file" 23 | else 24 | fzn=$input 25 | fi 26 | 27 | minizinc --solver gecode -a $fzn > $expectation_file 28 | 29 | if [[ -f $test_name.template ]]; 30 | then 31 | rm $fzn 32 | fi 33 | done 34 | -------------------------------------------------------------------------------- /pumpkin-solver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pumpkin-solver" 3 | version = "0.2.2" 4 | description = "The Pumpkin combinatorial optimisation solver library." 5 | readme = "../README.md" 6 | authors.workspace = true 7 | license.workspace = true 8 | edition.workspace = true 9 | repository.workspace = true 10 | 11 | [dependencies] 12 | clap = { version = "4.5.17", features = ["derive"] } 13 | env_logger = "0.10.0" 14 | flatzinc = "0.3.21" 15 | log = "0.4.27" 16 | pumpkin-core = { version = "0.2.2", path = "../pumpkin-crates/core/", features = ["clap"] } 17 | signal-hook = "0.3.18" 18 | thiserror = "2.0.12" 19 | 20 | [dev-dependencies] 21 | clap = { version = "4.5.17", features = ["derive"] } 22 | env_logger = "0.10.0" 23 | regex = "1.11.0" 24 | stringcase = "0.3.0" 25 | wait-timeout = "0.2.0" 26 | pumpkin-macros = { version = "0.1.0", path = "../pumpkin-macros"} 27 | pumpkin-checker = { version = "0.1.0", path = "../pumpkin-checker"} 28 | 29 | [lints] 30 | workspace = true 31 | 32 | [features] 33 | debug-checks = ["pumpkin-core/debug-checks"] 34 | 35 | [build-dependencies] 36 | cc = "1.1.30" 37 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/flatzinc/error.rs: -------------------------------------------------------------------------------- 1 | use std::num::TryFromIntError; 2 | 3 | use thiserror::Error; 4 | 5 | #[derive(Debug, Error)] 6 | pub(crate) enum FlatZincError { 7 | #[error("failed to read instance file: {0}")] 8 | Io(#[from] std::io::Error), 9 | 10 | #[error("{0}")] 11 | SyntaxError(Box), 12 | 13 | #[error("{0} variables are not supported")] 14 | UnsupportedVariable(Box), 15 | 16 | #[error("integer too big")] 17 | IntegerTooBig(#[from] TryFromIntError), 18 | 19 | #[error("constraint {constraint_id} expects {expected} arguments, got {actual}")] 20 | IncorrectNumberOfArguments { 21 | constraint_id: Box, 22 | expected: usize, 23 | actual: usize, 24 | }, 25 | 26 | #[error("unexpected expression")] 27 | UnexpectedExpr, 28 | 29 | #[error("the identifier '{identifier}' does not resolve to an '{expected_type}'")] 30 | InvalidIdentifier { 31 | identifier: Box, 32 | expected_type: Box, 33 | }, 34 | 35 | #[error("missing solve item")] 36 | MissingSolveItem, 37 | } 38 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/variable_selection/mod.rs: -------------------------------------------------------------------------------- 1 | //! Provides the [`VariableSelector`] trait which is required 2 | //! for variable selectors to implement; the main method in this trait relies on 3 | //! [`VariableSelector::select_variable`]. 4 | //! 5 | //! Furthermore, it defines several implementations of the [`VariableSelector`] trait. Any 6 | //! [`VariableSelector`] should only select variables which have a domain of size 2 or larger. 7 | 8 | mod anti_first_fail; 9 | mod dynamic_variable_selector; 10 | mod first_fail; 11 | mod input_order; 12 | mod largest; 13 | mod max_regret; 14 | mod most_constrained; 15 | mod occurrence; 16 | mod proportional_domain_size; 17 | mod random; 18 | mod smallest; 19 | mod variable_selector; 20 | 21 | pub use anti_first_fail::*; 22 | pub use dynamic_variable_selector::*; 23 | pub use first_fail::*; 24 | pub use input_order::*; 25 | pub use largest::*; 26 | pub use max_regret::*; 27 | pub use most_constrained::*; 28 | pub use occurrence::*; 29 | pub use proportional_domain_size::*; 30 | pub use random::RandomSelector; 31 | pub use smallest::*; 32 | pub use variable_selector::VariableSelector; 33 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/mod.rs: -------------------------------------------------------------------------------- 1 | mod constraint_operation_error; 2 | mod csp_solver_execution_flag; 3 | mod function; 4 | pub(crate) mod moving_averages; 5 | mod predicate_id_generators; 6 | mod propagation_status_cp; 7 | mod propositional_conjunction; 8 | mod random; 9 | pub(crate) mod sequence_generators; 10 | mod solution; 11 | mod stored_conflict_info; 12 | pub(crate) mod time; 13 | mod trail; 14 | 15 | pub use constraint_operation_error::ConstraintOperationError; 16 | pub(crate) use csp_solver_execution_flag::CSPSolverExecutionFlag; 17 | pub use function::Function; 18 | pub(crate) use predicate_id_generators::DeletablePredicateIdGenerator; 19 | pub use predicate_id_generators::PredicateId; 20 | pub(crate) use predicate_id_generators::PredicateIdGenerator; 21 | pub use propagation_status_cp::*; 22 | pub use propositional_conjunction::PropositionalConjunction; 23 | pub use random::*; 24 | pub use solution::ProblemSolution; 25 | pub use solution::Solution; 26 | pub use solution::SolutionReference; 27 | pub(crate) use stored_conflict_info::*; 28 | pub use time::Duration; 29 | pub use time::Instant; 30 | pub(crate) use trail::Trail; 31 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ConSoL Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod conflict_analysis; 2 | pub(crate) mod constraint_satisfaction_solver; 3 | mod constraint_tag; 4 | pub(crate) mod cp; 5 | mod debug_helper; 6 | mod literal_block_distance; 7 | pub(crate) mod notifications; 8 | pub(crate) mod predicates; 9 | mod restart_strategy; 10 | mod solver_statistics; 11 | pub(crate) mod state; 12 | pub(crate) mod termination; 13 | pub(crate) mod variable_names; 14 | pub(crate) mod variables; 15 | 16 | pub(crate) use conflict_analysis::ResolutionResolver; 17 | pub use constraint_satisfaction_solver::ConflictResolver; 18 | pub(crate) use constraint_satisfaction_solver::ConstraintSatisfactionSolver; 19 | pub use constraint_satisfaction_solver::SatisfactionSolverOptions; 20 | pub use cp::EmptyDomain; 21 | pub(crate) use cp::*; 22 | pub(crate) use debug_helper::DebugDyn; 23 | pub(crate) use debug_helper::DebugHelper; 24 | pub(crate) use literal_block_distance::Lbd; 25 | pub use restart_strategy::RestartOptions; 26 | pub(crate) use restart_strategy::RestartStrategy; 27 | pub(crate) use solver_statistics::SolverStatistics; 28 | pub use state::*; 29 | pub(crate) use variable_names::VariableNames; 30 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(doc)] 2 | use crate::results::unsatisfiable::UnsatisfiableUnderAssumptions; 3 | pub(crate) mod basic_types; 4 | pub mod containers; 5 | pub(crate) mod engine; 6 | pub(crate) mod math; 7 | pub(crate) mod pumpkin_asserts; 8 | 9 | #[cfg(doc)] 10 | use crate::branching::Brancher; 11 | #[cfg(doc)] 12 | use crate::termination::TerminationCondition; 13 | 14 | pub mod branching; 15 | pub mod constraints; 16 | pub mod optimisation; 17 | pub mod proof; 18 | pub mod propagation; 19 | pub mod propagators; 20 | pub mod statistics; 21 | 22 | pub use convert_case; 23 | pub use rand; 24 | 25 | // We declare a private module with public use, so that all exports from API are exports directly 26 | // from the crate. 27 | // 28 | // Example: 29 | // `use pumpkin_solver::Solver;` 30 | // vs. 31 | // `use pumpkin_solver::api::Solver;` 32 | mod api; 33 | 34 | pub use api::*; 35 | 36 | pub use crate::api::solver::DefaultBrancher; 37 | pub use crate::api::solver::Solver; 38 | pub use crate::basic_types::ConstraintOperationError; 39 | pub use crate::basic_types::Duration; 40 | pub use crate::basic_types::Instant; 41 | pub use crate::basic_types::Random; 42 | -------------------------------------------------------------------------------- /minizinc/lib/fzn_disjunctive_strict.mzn: -------------------------------------------------------------------------------- 1 | % Taken from https://github.com/chuffed/chuffed/blob/develop/chuffed/flatzinc/mznlib/fzn_disjunctive_strict.mzn 2 | %------------------------------------------------------------------------------% 3 | % Requires that a set of tasks given by start times s and durations d 4 | % do not overlap in time. Tasks with duration 0 CANNOT be scheduled at any time, 5 | % but only when no other task is running. 6 | % 7 | % Assumptions: 8 | % - forall i, d[i] >= 0 9 | %------------------------------------------------------------------------------% 10 | 11 | predicate fzn_disjunctive_strict(array[int] of var int: s, 12 | array[int] of var int: d) = 13 | forall(i in index_set(d))(d[i] >= 0) 14 | /\ if is_fixed(d) then 15 | pumpkin_disjunctive_strict(s, fix(d)) 16 | else 17 | forall(i, j in index_set(d) where i < j) ( 18 | s[i] + d[i] <= s[j] \/ s[j] + d[j] <= s[i] 19 | ) 20 | endif 21 | ; 22 | 23 | % Global disjunctive propagator 24 | % 25 | predicate pumpkin_disjunctive_strict(array[int] of var int: s, array[int] of int: d); 26 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/ph5.cnf: -------------------------------------------------------------------------------- 1 | p cnf 30 81 2 | -1 -6 0 3 | -1 -11 0 4 | -1 -16 0 5 | -1 -21 0 6 | -1 -26 0 7 | -6 -11 0 8 | -6 -16 0 9 | -6 -21 0 10 | -6 -26 0 11 | -11 -16 0 12 | -11 -21 0 13 | -11 -26 0 14 | -16 -21 0 15 | -16 -26 0 16 | -21 -26 0 17 | -2 -7 0 18 | -2 -12 0 19 | -2 -17 0 20 | -2 -22 0 21 | -2 -27 0 22 | -7 -12 0 23 | -7 -17 0 24 | -7 -22 0 25 | -7 -27 0 26 | -12 -17 0 27 | -12 -22 0 28 | -12 -27 0 29 | -17 -22 0 30 | -17 -27 0 31 | -22 -27 0 32 | -3 -8 0 33 | -3 -13 0 34 | -3 -18 0 35 | -3 -23 0 36 | -3 -28 0 37 | -8 -13 0 38 | -8 -18 0 39 | -8 -23 0 40 | -8 -28 0 41 | -13 -18 0 42 | -13 -23 0 43 | -13 -28 0 44 | -18 -23 0 45 | -18 -28 0 46 | -23 -28 0 47 | -4 -9 0 48 | -4 -14 0 49 | -4 -19 0 50 | -4 -24 0 51 | -4 -29 0 52 | -9 -14 0 53 | -9 -19 0 54 | -9 -24 0 55 | -9 -29 0 56 | -14 -19 0 57 | -14 -24 0 58 | -14 -29 0 59 | -19 -24 0 60 | -19 -29 0 61 | -24 -29 0 62 | -5 -10 0 63 | -5 -15 0 64 | -5 -20 0 65 | -5 -25 0 66 | -5 -30 0 67 | -10 -15 0 68 | -10 -20 0 69 | -10 -25 0 70 | -10 -30 0 71 | -15 -20 0 72 | -15 -25 0 73 | -15 -30 0 74 | -20 -25 0 75 | -20 -30 0 76 | -25 -30 0 77 | 5 4 3 2 1 0 78 | 10 9 8 7 6 0 79 | 15 14 13 12 11 0 80 | 20 19 18 17 16 0 81 | 25 24 23 22 21 0 82 | 30 29 28 27 26 0 83 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_infeasible/prop_stress.fzn: -------------------------------------------------------------------------------- 1 | % Taken from the prop_stress model with inputs k = 1, n = 2, m = 2 2 | 3 | array [1..2] of int: X_INTRODUCED_8_ = [1,-1]; 4 | var 0..2: X_INTRODUCED_1_; 5 | var 0..2: X_INTRODUCED_2_; 6 | var 0..2: X_INTRODUCED_3_; 7 | var 0..2: X_INTRODUCED_5_; 8 | var 0..2: X_INTRODUCED_6_; 9 | var 0..2: X_INTRODUCED_7_; 10 | array [1..3] of var int: X_INTRODUCED_0_:: output_array([1..3]) = [X_INTRODUCED_1_,X_INTRODUCED_2_,X_INTRODUCED_3_]; 11 | array [1..3] of var int: X_INTRODUCED_4_:: output_array([1..3]) = [X_INTRODUCED_5_,X_INTRODUCED_6_,X_INTRODUCED_7_]; 12 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_2_,X_INTRODUCED_3_],0); 13 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_1_,X_INTRODUCED_2_],2); 14 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_1_,X_INTRODUCED_3_],1); 15 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_3_,X_INTRODUCED_5_],0); 16 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_5_,X_INTRODUCED_6_],0); 17 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_5_,X_INTRODUCED_7_],0); 18 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_6_,X_INTRODUCED_7_],0); 19 | constraint int_lin_le(X_INTRODUCED_8_,[X_INTRODUCED_7_,X_INTRODUCED_1_],-2); 20 | solve satisfy; 21 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/flatzinc/compiler/handle_set_in.rs: -------------------------------------------------------------------------------- 1 | //! Scan through all constraint definition and determine whether a `set_in` constraint is present; 2 | //! if this is the case then update the domain of the variable directly. 3 | use super::context::CompilationContext; 4 | use crate::flatzinc::error::FlatZincError; 5 | 6 | pub(crate) fn run(context: &mut CompilationContext) -> Result<(), FlatZincError> { 7 | for (_, constraint_item) in &context.constraints { 8 | let flatzinc::ConstraintItem { 9 | id, 10 | exprs, 11 | annos: _, 12 | } = constraint_item; 13 | if id != "set_in" { 14 | continue; 15 | } 16 | 17 | let set = context.resolve_set_constant(&exprs[1])?; 18 | 19 | let id = context.identifiers.get_interned(match &exprs[0] { 20 | flatzinc::Expr::VarParIdentifier(id) => id, 21 | _ => return Err(FlatZincError::UnexpectedExpr), 22 | }); 23 | 24 | let mut domain = context.equivalences.get_mut_domain(&id); 25 | 26 | // We take the intersection between the two domains 27 | let new_domain = domain.merge(&set.into()); 28 | *domain = new_domain; 29 | } 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/branchers/alternating/strategies/other_only.rs: -------------------------------------------------------------------------------- 1 | use crate::branching::Brancher; 2 | use crate::branching::BrancherEvent; 3 | use crate::branching::SelectionContext; 4 | #[cfg(doc)] 5 | use crate::branching::branchers::alternating::AlternatingBrancher; 6 | use crate::branching::branchers::alternating::AlternatingStrategy; 7 | use crate::branching::branchers::alternating::BrancherToUse; 8 | 9 | /// Specifies that the [`AlternatingBrancher`] should always use the other strategy. 10 | #[derive(Default, Debug, Clone, Copy)] 11 | pub struct OtherOnly; 12 | 13 | impl AlternatingStrategy for OtherOnly { 14 | fn next_decision(&mut self, _context: &mut SelectionContext) -> BrancherToUse { 15 | BrancherToUse::Other 16 | } 17 | 18 | fn is_using_default_brancher(&self) -> bool { 19 | false 20 | } 21 | 22 | fn subscribe_to_events(&self) -> Vec { 23 | vec![] 24 | } 25 | 26 | fn is_restart_pointless( 27 | &mut self, 28 | _default_brancher: &mut impl Brancher, 29 | other_brancher: &mut impl Brancher, 30 | ) -> bool { 31 | other_brancher.is_restart_pointless() 32 | } 33 | 34 | fn will_always_use_default(&self) -> bool { 35 | false 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/statistics/statistic_logger.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use itertools::Itertools; 4 | 5 | use super::statistic_logging::log_statistic; 6 | #[cfg(doc)] 7 | use crate::propagation::Propagator; 8 | 9 | /// Responsible for logging the statistics with the provided prefix; currently used when logging 10 | /// the statistics of propagators. 11 | #[derive(Debug, Default, Clone)] 12 | pub struct StatisticLogger { 13 | /// The prefix which will be attached to the statistic name 14 | name_prefix: String, 15 | } 16 | 17 | impl StatisticLogger { 18 | pub fn new>(name_prefix: Input) -> Self { 19 | Self { 20 | name_prefix: name_prefix.into_iter().join("_"), 21 | } 22 | } 23 | 24 | /// Attaches the provided `addition_to_prefix` to the stored internal prefix and returns a new 25 | /// [`StatisticLogger`] with these two prefixes. 26 | pub fn attach_to_prefix(&self, addition_to_prefix: impl Display) -> Self { 27 | Self { 28 | name_prefix: format!("{}_{}", self.name_prefix, addition_to_prefix), 29 | } 30 | } 31 | 32 | pub fn log_statistic(&self, value: impl Display) { 33 | log_statistic(&self.name_prefix, value); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pumpkin-crates/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pumpkin-core" 3 | version = "0.2.2" 4 | repository.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | authors.workspace = true 8 | description = "The core of the Pumpkin constraint programming solver." 9 | 10 | [lints] 11 | workspace = true 12 | 13 | [dependencies] 14 | thiserror = "2.0.12" 15 | log = "0.4.17" 16 | bitfield = "0.14.0" 17 | enumset = "1.1.2" 18 | fnv = "1.0.7" # We require features which are on the `main` branch of the repository but are not on crates.io 19 | rand = { version = "0.8.5", features = [ "small_rng", "alloc" ] } 20 | once_cell = "1.19.0" 21 | downcast-rs = "1.2.1" 22 | drcp-format = { version = "0.3.0", path = "../../drcp-format" } 23 | convert_case = "0.6.0" 24 | itertools = "0.13.0" 25 | bitfield-struct = "0.9.2" 26 | num = "0.4.3" 27 | enum-map = "2.7.3" 28 | clap = { version = "4.5.40", optional = true } 29 | indexmap = "2.10.0" 30 | dyn-clone = "1.0.20" 31 | flate2 = { version = "1.1.2" } 32 | 33 | [target.'cfg(target_arch = "wasm32")'.dependencies] 34 | web-time = "1.1" 35 | getrandom = { version = "0.2", features = ["js"] } 36 | 37 | [target.'cfg(target_arch = "wasm32")'.dev-dependencies] 38 | wasm-bindgen-test = "0.3" 39 | 40 | [features] 41 | debug-checks = [] 42 | clap = ["dep:clap"] 43 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/tie_breaking/tie_breaker.rs: -------------------------------------------------------------------------------- 1 | #[cfg(doc)] 2 | use crate::branching::variable_selection::VariableSelector; 3 | 4 | /// The interface for a tie-breaker which considers additional elements with values; depending on 5 | /// the [`Direction`] it should only consider variables with the "best" value for selection. 6 | pub trait TieBreaker { 7 | /// Consider the next additional element with corresponding value 8 | fn consider(&mut self, variable: Var, value: Value); 9 | 10 | /// Get the final variable which was selected. After this method is called it resets the stored 11 | /// values such that it can be used again. This resetting is done to prevent the tie-breaker 12 | /// from returning a variable which has a value which is out-of-date. 13 | fn select(&mut self) -> Option; 14 | 15 | /// Returns whether the tie-breaker is attempting to find the minimum ([`Direction::Minimum`]) 16 | /// or maximum ([`Direction::Maximum`]) element. 17 | fn get_direction(&self) -> Direction; 18 | } 19 | 20 | /// Whether the value comparison should find the maximum [`Direction::Maximum`] variable or the 21 | /// [`Direction::Minimum`] variable. 22 | #[derive(Copy, Clone, Debug, PartialEq)] 23 | pub enum Direction { 24 | Maximum, 25 | Minimum, 26 | } 27 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/math/num_ext.rs: -------------------------------------------------------------------------------- 1 | //! Extensions for numbers that are not present in the stable standard library. 2 | 3 | pub(crate) trait NumExt { 4 | /// Division with rounding up. 5 | fn div_ceil(self, other: Self) -> Self; 6 | 7 | /// Division with rounding down. 8 | /// 9 | /// Note this is different from truncating, which is rounding toward zero. 10 | fn div_floor(self, other: Self) -> Self; 11 | } 12 | 13 | impl NumExt for i32 { 14 | fn div_ceil(self, other: Self) -> Self { 15 | // TODO: The source is taken from the standard library nightly implementation of this 16 | // function and div_floor. Once they are stabilized, these definitions can be removed. 17 | // Tracking issue: https://github.com/rust-lang/rust/issues/88581 18 | let d = self / other; 19 | let r = self % other; 20 | if (r > 0 && other > 0) || (r < 0 && other < 0) { 21 | d + 1 22 | } else { 23 | d 24 | } 25 | } 26 | 27 | fn div_floor(self, other: Self) -> Self { 28 | // TODO: See todo in `div_ceil`. 29 | let d = self / other; 30 | let r = self % other; 31 | if (r > 0 && other < 0) || (r < 0 && other > 0) { 32 | d - 1 33 | } else { 34 | d 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/reset_reviewed_status.yml: -------------------------------------------------------------------------------- 1 | # See: https://github.com/orgs/community/discussions/17875 2 | name: Dismiss old reviews when re-requested 3 | 4 | on: 5 | pull_request: 6 | types: [review_requested] 7 | 8 | jobs: 9 | review_requested: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | pull-requests: write 13 | steps: 14 | - name: Dismiss old reviews 15 | uses: actions/github-script@v7 16 | with: 17 | script: | 18 | const reviews = await github.paginate(github.rest.pulls.listReviews, { 19 | pull_number: context.payload.number, 20 | owner: context.repo.owner, 21 | repo: context.repo.repo, 22 | }); 23 | 24 | for (const review of reviews) { 25 | if (review.state === 'CHANGES_REQUESTED' && review.user.id === context.payload.requested_reviewer?.id) { 26 | console.log('Dismissing re-requested review.'); 27 | await github.rest.pulls.dismissReview({ 28 | pull_number: context.payload.number, 29 | owner: context.repo.owner, 30 | repo: context.repo.repo, 31 | review_id: review.id, 32 | message: 'Review re-requested', 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pumpkin-solver-py/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod constraints; 2 | mod model; 3 | mod optimisation; 4 | mod result; 5 | mod variables; 6 | 7 | use pyo3::prelude::*; 8 | 9 | macro_rules! submodule { 10 | ($module:ident, $python:ident, $m:ident) => {{ 11 | let submodule = PyModule::new($m.py(), stringify!($module))?; 12 | 13 | // See https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021 14 | pyo3::py_run!( 15 | $python, 16 | submodule, 17 | &format!( 18 | "import sys; sys.modules['pumpkin_solver.{}'] = submodule", 19 | stringify!($module) 20 | ) 21 | ); 22 | 23 | $module::register(&submodule)?; 24 | }}; 25 | } 26 | 27 | #[pymodule] 28 | fn pumpkin_solver(python: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { 29 | m.add_class::()?; 30 | m.add_class::()?; 31 | m.add_class::()?; 32 | m.add_class::()?; 33 | m.add_class::()?; 34 | m.add_class::()?; 35 | m.add_class::()?; 36 | m.add_class::()?; 37 | 38 | submodule!(constraints, python, m); 39 | submodule!(optimisation, python, m); 40 | 41 | Ok(()) 42 | } 43 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/literal_block_distance.rs: -------------------------------------------------------------------------------- 1 | use crate::containers::SparseSet; 2 | use crate::engine::Assignments; 3 | use crate::predicates::Predicate; 4 | 5 | /// Used to compute the LBD of nogoods. 6 | /// The type carries state that prevents the re-allocation of helper data structures. 7 | #[derive(Clone, Debug)] 8 | pub(crate) struct Lbd { 9 | lbd_helper: SparseSet, 10 | } 11 | 12 | impl Default for Lbd { 13 | fn default() -> Self { 14 | fn sparse_set_mapping(elem: &u32) -> usize { 15 | *elem as usize 16 | } 17 | 18 | Lbd { 19 | lbd_helper: SparseSet::new(vec![], sparse_set_mapping), 20 | } 21 | } 22 | } 23 | 24 | impl Lbd { 25 | /// Compute the LBD of the given nogood under the given assignment. 26 | pub(crate) fn compute_lbd( 27 | &mut self, 28 | predicates: &[Predicate], 29 | assignments: &Assignments, 30 | ) -> u32 { 31 | self.lbd_helper.set_to_empty(); 32 | self.lbd_helper 33 | .accommodate(&(assignments.get_checkpoint() as u32)); 34 | 35 | for predicate in predicates { 36 | let checkpoint = assignments.get_checkpoint_for_predicate(predicate).unwrap(); 37 | 38 | self.lbd_helper.insert(checkpoint as u32); 39 | } 40 | 41 | self.lbd_helper.len() as u32 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pumpkin-solver-py/src/result.rs: -------------------------------------------------------------------------------- 1 | use pumpkin_solver::results::ProblemSolution; 2 | use pyo3::prelude::*; 3 | 4 | use crate::variables::BoolExpression; 5 | use crate::variables::IntExpression; 6 | use crate::variables::Predicate; 7 | use crate::variables::VariableMap; 8 | 9 | #[pyclass] 10 | #[allow(clippy::large_enum_variant)] 11 | pub enum SatisfactionResult { 12 | Satisfiable(Solution), 13 | Unsatisfiable(), 14 | Unknown(), 15 | } 16 | 17 | #[pyclass] 18 | #[allow(clippy::large_enum_variant)] 19 | pub enum SatisfactionUnderAssumptionsResult { 20 | Satisfiable(Solution), 21 | UnsatisfiableUnderAssumptions(Vec), 22 | Unsatisfiable(), 23 | Unknown(), 24 | } 25 | 26 | #[pyclass] 27 | #[derive(Clone)] 28 | pub struct Solution { 29 | pub solver_solution: pumpkin_solver::results::Solution, 30 | pub variable_map: VariableMap, 31 | } 32 | 33 | #[pymethods] 34 | impl Solution { 35 | fn int_value(&self, variable: IntExpression) -> i32 { 36 | self.solver_solution 37 | .get_integer_value(variable.to_affine_view(&self.variable_map)) 38 | } 39 | 40 | fn bool_value(&self, variable: BoolExpression) -> bool { 41 | self.solver_solution 42 | .get_literal_value(variable.to_literal(&self.variable_map)) 43 | } 44 | } 45 | 46 | #[pyclass] 47 | #[derive(Clone)] 48 | pub struct CoreExtractor {} 49 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_infeasible_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | mod helpers; 4 | 5 | use helpers::TestType; 6 | use helpers::run_mzn_test; 7 | 8 | use crate::helpers::check_mzn_proof; 9 | 10 | macro_rules! mzn_infeasible_test { 11 | ($name:ident, with_proof: $with_proof:literal) => { 12 | #[test] 13 | fn $name() { 14 | run_mzn_infeasible_test(stringify!($name), "mzn_infeasible", $with_proof); 15 | } 16 | }; 17 | 18 | ($name:ident) => { 19 | mzn_infeasible_test!($name, with_proof: false); 20 | }; 21 | } 22 | mzn_infeasible_test!(prop_stress); 23 | mzn_infeasible_test!(connected); 24 | 25 | mzn_infeasible_test!(rcpsp_00_unsat, with_proof: true); 26 | mzn_infeasible_test!(rcpsp_01_unsat, with_proof: true); 27 | mzn_infeasible_test!(rcpsp_st27_14, with_proof: true); 28 | mzn_infeasible_test!(rcpsp_bl2006, with_proof: true); 29 | mzn_infeasible_test!(rcpsp_j60_1_6, with_proof: true); 30 | 31 | mzn_infeasible_test!(ghoulomb_3_5_11, with_proof: true); 32 | 33 | pub fn run_mzn_infeasible_test(instance_name: &str, folder_name: &str, with_proof: bool) { 34 | let _ = run_mzn_test::( 35 | instance_name, 36 | folder_name, 37 | with_proof, 38 | TestType::Unsatisfiable, 39 | ); 40 | 41 | if with_proof { 42 | check_mzn_proof(instance_name, folder_name); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /minizinc/Dockerfile: -------------------------------------------------------------------------------- 1 | # A Dockerfile used to submit Pumpkin to the MiniZinc challenge 2024. 2 | 3 | # As suggested in the challenge instruction, the docker file contains two 4 | # stages. The first stage builds the solver from source, and the second 5 | # sets up the MiniZinc configuration to make Pumpkin the default solver. 6 | 7 | 8 | FROM rust:latest AS builder 9 | 10 | # Copy the project source to the Docker image. 11 | COPY . /pumpkin-src 12 | 13 | WORKDIR /pumpkin-src 14 | 15 | # Compile the solver with optimizations turned on. 16 | RUN cargo build -p pumpkin-solver --release 17 | 18 | # Create the MiniZinc image 19 | FROM minizinc/mznc2025:latest 20 | 21 | # Copy the solver executable 22 | COPY --from=builder /pumpkin-src/target/release/pumpkin-solver /pumpkin/pumpkin-solver 23 | 24 | # Copy the MiniZinc library 25 | COPY --from=builder /pumpkin-src/minizinc/ /pumpkin/ 26 | 27 | # Change the path to the solver executable to be the correct one. 28 | RUN sed -i 's/..\/target\/release\/pumpkin-solver/pumpkin-solver/' /pumpkin/pumpkin.msc 29 | 30 | # Add Pumpkin to the MiniZinc search path and set it as the default solver. 31 | # 32 | # See https://www.minizinc.org/doc-2.8.5/en/command_line.html#user-configuration-files 33 | RUN echo '{"mzn_solver_path": ["/pumpkin"],' > $HOME/.minizinc/Preferences.json 34 | RUN echo '"tagDefaults": [["", "pumpkin"]]}' >> $HOME/.minizinc/Preferences.json 35 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/os_signal_termination.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::atomic::AtomicBool; 3 | use std::sync::atomic::Ordering; 4 | 5 | use pumpkin_solver::termination::TerminationCondition; 6 | 7 | /// A [`TerminationCondition`] which triggers due to a SIGINT signal. 8 | #[derive(Clone, Debug)] 9 | pub(crate) struct OsSignal { 10 | signal_received: Arc, 11 | } 12 | 13 | impl OsSignal { 14 | /// Create a termination and install the event listeners. 15 | pub(crate) fn install() -> OsSignal { 16 | // The signals to listen to for termination. 17 | const TERMINATION_SIGNALS: &[std::ffi::c_int] = 18 | &[signal_hook::consts::SIGINT, signal_hook::consts::SIGTERM]; 19 | 20 | let signal_termination = OsSignal { 21 | signal_received: Arc::new(AtomicBool::new(false)), 22 | }; 23 | 24 | for &signal in TERMINATION_SIGNALS { 25 | let _ = signal_hook::flag::register( 26 | signal, 27 | Arc::clone(&signal_termination.signal_received), 28 | ) 29 | .expect("failed to register signal listener"); 30 | } 31 | 32 | signal_termination 33 | } 34 | } 35 | 36 | impl TerminationCondition for OsSignal { 37 | fn should_stop(&mut self) -> bool { 38 | self.signal_received.load(Ordering::Relaxed) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/termination/mod.rs: -------------------------------------------------------------------------------- 1 | //! A [`TerminationCondition`] is a condition which is polled by the solver during the search 2 | //! process. It indicates when the solver should stop, even if no definitive conclusions have been 3 | //! made. The most common example would be [`time_budget::TimeBudget`], which gives the solver a 4 | //! certain time budget to complete its search. 5 | 6 | use std::ops::DerefMut; 7 | 8 | pub(crate) mod combinator; 9 | pub(crate) mod indefinite; 10 | pub(crate) mod time_budget; 11 | 12 | /// The central trait that defines a termination condition. A termination condition determines when 13 | /// the solver should give up searching for solutions. 14 | /// 15 | /// # Notes 16 | /// - Any `Box` is a valid implementation of `TerminationCondition`. 17 | pub trait TerminationCondition { 18 | /// Returns `true` when the solver should stop, `false` otherwise. 19 | fn should_stop(&mut self) -> bool; 20 | } 21 | 22 | impl TerminationCondition for Option { 23 | fn should_stop(&mut self) -> bool { 24 | match self { 25 | Some(t) => t.should_stop(), 26 | None => false, 27 | } 28 | } 29 | } 30 | 31 | impl TerminationCondition for Box { 32 | fn should_stop(&mut self) -> bool { 33 | self.deref_mut().should_stop() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pumpkin-solver-py/tests/test_assumptions.py: -------------------------------------------------------------------------------- 1 | from pumpkin_solver import ( 2 | Comparator, 3 | Model, 4 | Predicate, 5 | SatisfactionUnderAssumptionsResult, 6 | ) 7 | from pumpkin_solver.constraints import LessThanOrEquals 8 | 9 | 10 | def test_assumptions_are_respected(): 11 | model = Model() 12 | 13 | x = model.new_integer_variable(1, 5, name="x") 14 | 15 | assumption = Predicate(x, Comparator.LessThanOrEqual, 3) 16 | 17 | result = model.satisfy_under_assumptions([assumption]) 18 | assert isinstance(result, SatisfactionUnderAssumptionsResult.Satisfiable) 19 | 20 | solution = result._0 21 | x_value = solution.int_value(x) 22 | assert x_value <= 3 23 | 24 | 25 | def test_core_extraction(): 26 | model = Model() 27 | 28 | x = model.new_integer_variable(1, 5, name="x") 29 | y = model.new_integer_variable(1, 5, name="x") 30 | 31 | x_ge_3 = Predicate(x, Comparator.GreaterThanOrEqual, 3) 32 | y_ge_3 = Predicate(y, Comparator.GreaterThanOrEqual, 3) 33 | 34 | le_tag = model.new_constraint_tag() 35 | model.add_constraint(LessThanOrEquals([x, y], 5, le_tag)) 36 | 37 | result = model.satisfy_under_assumptions([x_ge_3, y_ge_3]) 38 | assert isinstance( 39 | result, SatisfactionUnderAssumptionsResult.UnsatisfiableUnderAssumptions 40 | ) 41 | 42 | core = set(result._0) 43 | assert set([x_ge_3, y_ge_3]) == core 44 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | mod helpers; 4 | 5 | use helpers::TestType; 6 | use helpers::run_mzn_test; 7 | 8 | macro_rules! mzn_search_ordered { 9 | ($name:ident) => { 10 | #[test] 11 | fn $name() { 12 | let _ = run_mzn_test::( 13 | stringify!($name), 14 | "mzn_search", 15 | false, 16 | TestType::SolutionEnumeration, 17 | ); 18 | } 19 | }; 20 | } 21 | 22 | macro_rules! mzn_search_unordered { 23 | ($name:ident) => { 24 | #[test] 25 | fn $name() { 26 | let _ = run_mzn_test::( 27 | stringify!($name), 28 | "mzn_search", 29 | false, 30 | TestType::SolutionEnumeration, 31 | ); 32 | } 33 | }; 34 | } 35 | 36 | mzn_search_ordered!(bool_search_provided_directly); 37 | mzn_search_ordered!(search_over_ints_no_propagators); 38 | mzn_search_ordered!(search_over_bools_no_propagators); 39 | mzn_search_ordered!(seq_search_1); 40 | mzn_search_unordered!(search_with_constants_in_search); 41 | mzn_search_unordered!(search_annotation_does_not_fix_all_variables); 42 | 43 | mzn_search_ordered!(bool_warm_start); 44 | mzn_search_ordered!(int_warm_start); 45 | 46 | mzn_search_ordered!(bool_warm_start_array); 47 | mzn_search_ordered!(int_warm_start_array); 48 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/cnf/full6.cnf: -------------------------------------------------------------------------------- 1 | p cnf 6 64 2 | 6 -5 -1 -2 -3 -4 0 3 | 6 -5 -1 -2 -3 4 0 4 | 6 -5 -1 -2 3 -4 0 5 | 6 -5 -1 -2 3 4 0 6 | 6 -5 -1 2 -3 -4 0 7 | 6 -5 -1 2 -3 4 0 8 | 6 -5 -1 2 3 -4 0 9 | 6 -5 -1 2 3 4 0 10 | 6 -5 1 -2 -3 -4 0 11 | 6 -5 1 -2 -3 4 0 12 | 6 -5 1 -2 3 -4 0 13 | 6 -5 1 -2 3 4 0 14 | 6 -5 1 2 -3 -4 0 15 | 6 -5 1 2 -3 4 0 16 | 6 -5 1 2 3 -4 0 17 | 6 -5 1 2 3 4 0 18 | 6 5 -1 -2 -3 -4 0 19 | 6 5 -1 -2 -3 4 0 20 | 6 5 -1 -2 3 -4 0 21 | 6 5 -1 -2 3 4 0 22 | 6 5 -1 2 -3 -4 0 23 | 6 5 -1 2 -3 4 0 24 | 6 5 -1 2 3 -4 0 25 | 6 5 -1 2 3 4 0 26 | 6 5 1 -2 -3 -4 0 27 | 6 5 1 -2 -3 4 0 28 | 6 5 1 -2 3 -4 0 29 | 6 5 1 -2 3 4 0 30 | 6 5 1 2 -3 -4 0 31 | 6 5 1 2 -3 4 0 32 | 6 5 1 2 3 -4 0 33 | 6 5 1 2 3 4 0 34 | -6 -5 -1 -2 -3 -4 0 35 | -6 -5 -1 -2 -3 4 0 36 | -6 -5 -1 -2 3 -4 0 37 | -6 -5 -1 -2 3 4 0 38 | -6 -5 -1 2 -3 -4 0 39 | -6 -5 -1 2 -3 4 0 40 | -6 -5 -1 2 3 -4 0 41 | -6 -5 -1 2 3 4 0 42 | -6 -5 1 -2 -3 -4 0 43 | -6 -5 1 -2 -3 4 0 44 | -6 -5 1 -2 3 -4 0 45 | -6 -5 1 -2 3 4 0 46 | -6 -5 1 2 -3 -4 0 47 | -6 -5 1 2 -3 4 0 48 | -6 -5 1 2 3 -4 0 49 | -6 -5 1 2 3 4 0 50 | -6 5 -1 -2 -3 -4 0 51 | -6 5 -1 -2 -3 4 0 52 | -6 5 -1 -2 3 -4 0 53 | -6 5 -1 -2 3 4 0 54 | -6 5 -1 2 -3 -4 0 55 | -6 5 -1 2 -3 4 0 56 | -6 5 -1 2 3 -4 0 57 | -6 5 -1 2 3 4 0 58 | -6 5 1 -2 -3 -4 0 59 | -6 5 1 -2 -3 4 0 60 | -6 5 1 -2 3 -4 0 61 | -6 5 1 -2 3 4 0 62 | -6 5 1 2 -3 -4 0 63 | -6 5 1 2 -3 4 0 64 | -6 5 1 2 3 -4 0 65 | -6 5 1 2 3 4 0 66 | -------------------------------------------------------------------------------- /fzn-rs-derive/tests/utils.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | dead_code, 3 | reason = "it is used in other test files, but somehow compiler can't see it" 4 | )] 5 | #![cfg(test)] 6 | 7 | use std::collections::BTreeMap; 8 | use std::rc::Rc; 9 | 10 | use fzn_rs::ast::{self}; 11 | 12 | pub(crate) fn satisfy_solve() -> ast::SolveItem { 13 | ast::SolveItem { 14 | method: test_node(ast::Method::Satisfy), 15 | annotations: vec![], 16 | } 17 | } 18 | 19 | pub(crate) fn test_node(data: T) -> ast::Node { 20 | node(data, usize::MAX, usize::MAX) 21 | } 22 | 23 | pub(crate) fn node(data: T, span_start: usize, span_end: usize) -> ast::Node { 24 | ast::Node { 25 | node: data, 26 | span: ast::Span { 27 | start: span_start, 28 | end: span_end, 29 | }, 30 | } 31 | } 32 | 33 | pub(crate) fn unbounded_variables<'a>( 34 | names: impl IntoIterator, 35 | ) -> BTreeMap, ast::Node>> { 36 | names 37 | .into_iter() 38 | .map(|name| { 39 | ( 40 | Rc::from(name), 41 | test_node(ast::Variable { 42 | domain: test_node(ast::Domain::UnboundedInt), 43 | value: None, 44 | annotations: vec![], 45 | }), 46 | ) 47 | }) 48 | .collect() 49 | } 50 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/mod.rs: -------------------------------------------------------------------------------- 1 | //! Provides the [`ValueSelector`] trait which is required 2 | //! for value selectors to implement; the main method in this trait relies on 3 | //! [`ValueSelector::select_value`]. 4 | //! 5 | //! Furthermore, it defines several implementations of the [`ValueSelector`] trait. Any 6 | //! [`ValueSelector`] should only select values which are in the domain of the provided variable. 7 | 8 | mod dynamic_value_selector; 9 | mod in_domain_interval; 10 | mod in_domain_max; 11 | mod in_domain_median; 12 | mod in_domain_middle; 13 | mod in_domain_min; 14 | mod in_domain_random; 15 | mod in_domain_split; 16 | mod in_domain_split_random; 17 | mod out_domain_max; 18 | mod out_domain_median; 19 | mod out_domain_min; 20 | mod out_domain_random; 21 | mod random_splitter; 22 | mod reverse_in_domain_split; 23 | mod value_selector; 24 | 25 | pub use dynamic_value_selector::*; 26 | pub use in_domain_interval::*; 27 | pub use in_domain_max::*; 28 | pub use in_domain_median::*; 29 | pub use in_domain_middle::*; 30 | pub use in_domain_min::*; 31 | pub use in_domain_random::*; 32 | pub use in_domain_split::*; 33 | pub use in_domain_split_random::*; 34 | pub use out_domain_max::*; 35 | pub use out_domain_median::*; 36 | pub use out_domain_min::*; 37 | pub use out_domain_random::*; 38 | pub use random_splitter::*; 39 | pub use reverse_in_domain_split::*; 40 | pub use value_selector::ValueSelector; 41 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/sequence_generators/sequence_generator_type.rs: -------------------------------------------------------------------------------- 1 | /// Specifies the type of sequence which is used to generate conflict limits before a restart 2 | /// occurs. 3 | #[derive(Default, Clone, Copy, Debug)] 4 | #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] 5 | pub enum SequenceGeneratorType { 6 | /// Indicates that the restart strategy should restart every `x` conflicts. 7 | #[default] 8 | Constant, 9 | /// Indicates that the restarts strategy should use geometric restarts. 10 | /// 11 | /// Given two constants `base` and `multiplicative_factor`, the i-th element `f(i)` in a 12 | /// geometric sequence is caluclated as follows: 13 | /// - `f(i) = f(i - 1) * multiplicative_factor` 14 | /// - `f(0) = base` 15 | /// 16 | /// When `multiplicative_factor` is not an integer, then the above formula is **not** the same 17 | /// as the formula `f(i) = a * m^i` since intermediate values are founded down. 18 | Geometric, 19 | /// Indicates that the restart strategy should use Luby restarts \[1\]. 20 | /// 21 | /// The Luby sequence is a recursive sequence of the form: 22 | /// 1, 1, 2, 1, 1, 2, 4, 1, 1, 2, 1, 1, 2, 4, 8, 1, 1, 2.... 23 | /// 24 | /// # Bibliography 25 | /// \[1\] M. Luby, A. Sinclair, and D. Zuckerman, ‘Optimal speedup of Las Vegas algorithms’, 26 | /// Information Processing Letters, vol. 47, no. 4, pp. 173–180, 1993. 27 | Luby, 28 | } 29 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/stored_conflict_info.rs: -------------------------------------------------------------------------------- 1 | use super::propagation_status_cp::PropagatorConflict; 2 | use crate::ConstraintOperationError; 3 | #[cfg(doc)] 4 | use crate::engine::ConstraintSatisfactionSolver; 5 | use crate::engine::EmptyDomainConflict; 6 | use crate::engine::state::Conflict; 7 | use crate::predicates::Predicate; 8 | #[cfg(doc)] 9 | use crate::propagation::Propagator; 10 | 11 | /// a conflict info which can be stored in the solver. 12 | /// two (related) conflicts can happen: 13 | /// 1) a propagator explicitly detects a conflict. 14 | /// 2) a propagator post a domain change that results in a variable having an empty domain. 15 | #[derive(Debug, PartialEq, Eq, Clone)] 16 | pub(crate) enum StoredConflictInfo { 17 | Propagator(PropagatorConflict), 18 | EmptyDomain(EmptyDomainConflict), 19 | /// The conflict is due to inconsistent assumptions. 20 | /// 21 | /// The provided predicate and its negation are both assumptions. 22 | InconsistentAssumptions(Predicate), 23 | RootLevelConflict(ConstraintOperationError), 24 | } 25 | 26 | impl From for StoredConflictInfo { 27 | fn from(value: Conflict) -> Self { 28 | match value { 29 | Conflict::Propagator(propagator_conflict) => { 30 | StoredConflictInfo::Propagator(propagator_conflict) 31 | } 32 | Conflict::EmptyDomain(empty_domain_conflict) => { 33 | StoredConflictInfo::EmptyDomain(empty_domain_conflict) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf/normalized_g9x3.wcnf: -------------------------------------------------------------------------------- 1 | c Standarized MaxSat Instance 2 | c{ 3 | c "sha1sum": "da26691f64f027102f9af4beceb46e09a132ca25", 4 | c "nvars": 27, 5 | c "ncls": 54, 6 | c "nhards": 27, 7 | c "nhard_len_stats": 8 | c { "min": 3, "max": 5, "ave": 4.11, 9 | c "stddev": 0.63 }, 10 | c "nsofts": 27, 11 | c "nsoft_len_stats": 12 | c { "min": 1, "max": 1, "ave": 1.00, 13 | c "stddev": 0.00 }, 14 | c "nsoft_wts": 1, 15 | c "soft_wt_stats": 16 | c { "min": 1, "max": 1, "ave": 1.00, 17 | c "stddev": 0.00 } 18 | c} 19 | c------------------------------------------------------------ 20 | c SUBTRACT 0 21 | p wcnf 27 54 28 22 | 1 -1 0 23 | 1 -2 0 24 | 1 -3 0 25 | 1 -4 0 26 | 1 -5 0 27 | 1 -6 0 28 | 1 -7 0 29 | 1 -8 0 30 | 1 -9 0 31 | 1 -10 0 32 | 1 -11 0 33 | 1 -12 0 34 | 1 -13 0 35 | 1 -14 0 36 | 1 -15 0 37 | 1 -16 0 38 | 1 -17 0 39 | 1 -18 0 40 | 1 -19 0 41 | 1 -20 0 42 | 1 -21 0 43 | 1 -22 0 44 | 1 -23 0 45 | 1 -24 0 46 | 1 -25 0 47 | 1 -26 0 48 | 1 -27 0 49 | 28 1 2 10 0 50 | 28 1 10 11 19 0 51 | 28 10 19 20 0 52 | 28 1 2 3 11 0 53 | 28 2 10 11 12 20 0 54 | 28 11 19 20 21 0 55 | 28 2 3 4 12 0 56 | 28 3 11 12 13 21 0 57 | 28 12 20 21 22 0 58 | 28 3 4 5 13 0 59 | 28 4 12 13 14 22 0 60 | 28 13 21 22 23 0 61 | 28 4 5 6 14 0 62 | 28 5 13 14 15 23 0 63 | 28 14 22 23 24 0 64 | 28 5 6 7 15 0 65 | 28 6 14 15 16 24 0 66 | 28 15 23 24 25 0 67 | 28 6 7 8 16 0 68 | 28 7 15 16 17 25 0 69 | 28 16 24 25 26 0 70 | 28 7 8 9 17 0 71 | 28 8 16 17 18 26 0 72 | 28 17 25 26 27 0 73 | 28 8 9 18 0 74 | 28 9 17 18 27 0 75 | 28 18 26 27 0 76 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_optimization_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | mod helpers; 4 | 5 | use helpers::TestType; 6 | use helpers::check_mzn_proof; 7 | use helpers::run_mzn_test; 8 | 9 | macro_rules! mzn_optimization_test { 10 | ($name:ident, with_proof: $with_proof:literal) => { 11 | #[test] 12 | fn $name() { 13 | let output = run_mzn_test::( 14 | stringify!($name), 15 | "mzn_optimization", 16 | $with_proof, 17 | TestType::Optimality, 18 | ); 19 | assert!(output.ends_with("==========\n")); 20 | 21 | if $with_proof { 22 | check_mzn_proof(stringify!($name), "mzn_optimization"); 23 | } 24 | } 25 | }; 26 | 27 | ($name:ident) => { 28 | mzn_optimization_test!($name, with_proof: false); 29 | }; 30 | } 31 | 32 | mzn_optimization_test!(constant_objective); 33 | mzn_optimization_test!(unfixed_objective); 34 | mzn_optimization_test!(minimise_1); 35 | mzn_optimization_test!(maximise_1); 36 | mzn_optimization_test!(unconstrained_objective_minimise); 37 | mzn_optimization_test!(unconstrained_objective_maximise); 38 | 39 | mzn_optimization_test!(rcpsp_00, with_proof: true); 40 | mzn_optimization_test!(rcpsp_01, with_proof: true); 41 | mzn_optimization_test!(rcpsp_st27_14, with_proof: true); 42 | mzn_optimization_test!(rcpsp_bl2006, with_proof: true); 43 | mzn_optimization_test!(rcpsp_j60_1_6, with_proof: true); 44 | 45 | mzn_optimization_test!(ghoulomb_3_5_11, with_proof: true); 46 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/optimisation/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains structures related to optimissation. 2 | 3 | use solution_callback::SolutionCallback; 4 | 5 | use crate::Solver; 6 | use crate::branching::Brancher; 7 | use crate::results::OptimisationResult; 8 | use crate::termination::TerminationCondition; 9 | 10 | pub mod linear_sat_unsat; 11 | pub mod linear_unsat_sat; 12 | pub mod solution_callback; 13 | 14 | pub trait OptimisationProcedure> { 15 | fn optimise( 16 | &mut self, 17 | brancher: &mut B, 18 | termination: &mut impl TerminationCondition, 19 | solver: &mut Solver, 20 | ) -> OptimisationResult; 21 | } 22 | 23 | /// The type of search which is performed by the solver. 24 | #[derive(Debug, Clone, Copy, Default)] 25 | #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] 26 | pub enum OptimisationStrategy { 27 | /// Linear SAT-UNSAT - Starts with a satisfiable solution and tightens the bound on the 28 | /// objective variable until an UNSAT result is reached. Can be seen as upper-bounding search. 29 | #[default] 30 | LinearSatUnsat, 31 | /// Linear UNSAT-SAT - Starts with an unsatisfiable solution and tightens the bound on the 32 | /// objective variable until a SAT result is reached. Can be seen as lower-bounding search. 33 | LinearUnsatSat, 34 | } 35 | 36 | /// The direction of the optimisation, either maximising or minimising. 37 | #[derive(Debug, Clone, Copy, PartialEq)] 38 | pub enum OptimisationDirection { 39 | Maximise, 40 | Minimise, 41 | } 42 | -------------------------------------------------------------------------------- /pumpkin-solver-py/README.md: -------------------------------------------------------------------------------- 1 | # Pumpkin Python Interface 2 | 3 | The python interface for the Pumpkin solver. 4 | 5 | ## Contributing 6 | 7 | When contributing to the python interface, two tools should be installed in 8 | the current python environment: 9 | 1. `maturin`, which builds and installs the python module 10 | 2. `pytest`, to run the tests. 11 | 12 | To build the `pumpkin_solver_py` module and make it available to the current python 13 | environment, run: 14 | ``` 15 | maturin develop 16 | ``` 17 | This command will compile the Rust binary. This means that whenever the Rust 18 | code changes, maturin has to re-compile before those changes are visible to 19 | the python module. This is not the case for the python code. Changes to that 20 | are immediately visible in the environment, without needing to run `maturin` 21 | again. 22 | 23 | Then, the examples (for example `nqueens`) can be run with 24 | ``` 25 | python examples/nqueens.py 5 26 | ``` 27 | 28 | ### PyO3 rebuilds 29 | 30 | When developing in an IDE that runs `cargo check` on save, the PyO3 build 31 | cache can get invalidated unnecessarily. See https://github.com/PyO3/pyo3/issues/1708 32 | for more details. One way to fix this is by making `rust-analyzer` use a 33 | different directory. In VSCode, you could fix this by adding the following 34 | to your `.vscode/settings.json` (in the main project directory): 35 | 36 | ```json 37 | { 38 | "rust-analyzer.server.extraEnv": { 39 | "CARGO_TARGET_DIR": "target/analyzer" 40 | }, 41 | "rust-analyzer.check.extraArgs": [ 42 | "--target-dir=target/analyzer" 43 | ] 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /pumpkin-solver-py/src/constraints/arguments.rs: -------------------------------------------------------------------------------- 1 | use pumpkin_solver::variables::AffineView; 2 | use pumpkin_solver::variables::DomainId; 3 | use pumpkin_solver::variables::Literal; 4 | 5 | use crate::variables::BoolExpression; 6 | use crate::variables::IntExpression; 7 | use crate::variables::VariableMap; 8 | 9 | /// Trait which helps to convert Python API types to the solver types when creating constraints. 10 | pub trait PythonConstraintArg { 11 | type Output; 12 | 13 | fn to_solver_constraint_argument(self, variable_map: &VariableMap) -> Self::Output; 14 | } 15 | 16 | impl PythonConstraintArg for IntExpression { 17 | type Output = AffineView; 18 | 19 | fn to_solver_constraint_argument(self, variable_map: &VariableMap) -> Self::Output { 20 | self.to_affine_view(variable_map) 21 | } 22 | } 23 | 24 | impl PythonConstraintArg for BoolExpression { 25 | type Output = Literal; 26 | 27 | fn to_solver_constraint_argument(self, variable_map: &VariableMap) -> Self::Output { 28 | self.to_literal(variable_map) 29 | } 30 | } 31 | 32 | impl PythonConstraintArg for i32 { 33 | type Output = i32; 34 | 35 | fn to_solver_constraint_argument(self, _: &VariableMap) -> Self::Output { 36 | self 37 | } 38 | } 39 | 40 | impl PythonConstraintArg for Vec { 41 | type Output = Vec; 42 | 43 | fn to_solver_constraint_argument(self, variable_map: &VariableMap) -> Self::Output { 44 | self.into_iter() 45 | .map(|arg| arg.to_solver_constraint_argument(variable_map)) 46 | .collect() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_search/search_annotation_does_not_fix_all_variables.expected: -------------------------------------------------------------------------------- 1 | x1 = 1; 2 | x2 = 1; 3 | x3 = 1; 4 | ---------- 5 | x1 = 2; 6 | x2 = 1; 7 | x3 = 1; 8 | ---------- 9 | x1 = 3; 10 | x2 = 1; 11 | x3 = 1; 12 | ---------- 13 | x1 = 1; 14 | x2 = 2; 15 | x3 = 1; 16 | ---------- 17 | x1 = 2; 18 | x2 = 2; 19 | x3 = 1; 20 | ---------- 21 | x1 = 3; 22 | x2 = 2; 23 | x3 = 1; 24 | ---------- 25 | x1 = 1; 26 | x2 = 3; 27 | x3 = 1; 28 | ---------- 29 | x1 = 2; 30 | x2 = 3; 31 | x3 = 1; 32 | ---------- 33 | x1 = 3; 34 | x2 = 3; 35 | x3 = 1; 36 | ---------- 37 | x1 = 1; 38 | x2 = 1; 39 | x3 = 2; 40 | ---------- 41 | x1 = 2; 42 | x2 = 1; 43 | x3 = 2; 44 | ---------- 45 | x1 = 3; 46 | x2 = 1; 47 | x3 = 2; 48 | ---------- 49 | x1 = 1; 50 | x2 = 2; 51 | x3 = 2; 52 | ---------- 53 | x1 = 2; 54 | x2 = 2; 55 | x3 = 2; 56 | ---------- 57 | x1 = 3; 58 | x2 = 2; 59 | x3 = 2; 60 | ---------- 61 | x1 = 1; 62 | x2 = 3; 63 | x3 = 2; 64 | ---------- 65 | x1 = 2; 66 | x2 = 3; 67 | x3 = 2; 68 | ---------- 69 | x1 = 3; 70 | x2 = 3; 71 | x3 = 2; 72 | ---------- 73 | x1 = 1; 74 | x2 = 1; 75 | x3 = 3; 76 | ---------- 77 | x1 = 2; 78 | x2 = 1; 79 | x3 = 3; 80 | ---------- 81 | x1 = 3; 82 | x2 = 1; 83 | x3 = 3; 84 | ---------- 85 | x1 = 1; 86 | x2 = 2; 87 | x3 = 3; 88 | ---------- 89 | x1 = 2; 90 | x2 = 2; 91 | x3 = 3; 92 | ---------- 93 | x1 = 3; 94 | x2 = 2; 95 | x3 = 3; 96 | ---------- 97 | x1 = 1; 98 | x2 = 3; 99 | x3 = 3; 100 | ---------- 101 | x1 = 2; 102 | x2 = 3; 103 | x3 = 3; 104 | ---------- 105 | x1 = 3; 106 | x2 = 3; 107 | x3 = 3; 108 | ---------- 109 | ========== -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf/checkers/stream_utils.h: -------------------------------------------------------------------------------- 1 | /***********[stream_utils.h] 2 | Copyright (c) 2020 Fahiem Bacchus 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | ***********/ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | struct Istream_guard { 32 | std::istream &is; 33 | std::ios_base::iostate old_e = is.exceptions(); 34 | Istream_guard(std::istream &ss, std::ios_base::iostate e) : is{ss} { 35 | is.exceptions(is.exceptions() | e); 36 | } 37 | ~Istream_guard() { is.exceptions(old_e); } 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/flatzinc/compiler/mod.rs: -------------------------------------------------------------------------------- 1 | mod collect_domains; 2 | mod context; 3 | mod create_objective; 4 | mod create_search_strategy; 5 | mod define_constants; 6 | mod define_variable_arrays; 7 | mod handle_set_in; 8 | mod merge_equivalences; 9 | mod post_constraints; 10 | mod prepare_variables; 11 | mod remove_unused_variables; 12 | mod reserve_constraint_tags; 13 | 14 | use context::CompilationContext; 15 | use pumpkin_solver::Solver; 16 | 17 | use super::FlatZincError; 18 | use super::FlatZincOptions; 19 | use super::ast::FlatZincAst; 20 | use super::instance::FlatZincInstance; 21 | 22 | pub(crate) fn compile( 23 | mut ast: FlatZincAst, 24 | solver: &mut Solver, 25 | options: FlatZincOptions, 26 | ) -> Result { 27 | let mut context = CompilationContext::new(solver); 28 | 29 | define_constants::run(&ast, &mut context)?; 30 | reserve_constraint_tags::run(&ast, &mut context)?; 31 | remove_unused_variables::run(&mut ast, &mut context)?; 32 | prepare_variables::run(&ast, &mut context)?; 33 | merge_equivalences::run(&mut ast, &mut context, &options)?; 34 | handle_set_in::run(&mut context)?; 35 | collect_domains::run(&ast, &mut context)?; 36 | define_variable_arrays::run(&ast, &mut context)?; 37 | post_constraints::run(&ast, &mut context, &options)?; 38 | let objective_function = create_objective::run(&ast, &mut context)?; 39 | let search = create_search_strategy::run(&ast, &mut context, objective_function)?; 40 | 41 | Ok(FlatZincInstance { 42 | outputs: context.outputs, 43 | objective_function, 44 | search: Some(search), 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/cumulative/utils/structs/resource_profile.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::rc::Rc; 3 | 4 | use super::Task; 5 | use crate::variables::IntegerVariable; 6 | 7 | /// Structures used for storing the data related to resource profiles; 8 | /// A [`ResourceProfile`] represents a rectangle where the height is the cumulative mandatory 9 | /// resource usage of the [`profile tasks`][ResourceProfile::profile_tasks] 10 | #[derive(Clone)] 11 | pub(crate) struct ResourceProfile { 12 | /// The start time of the [`ResourceProfile`] (inclusive) 13 | pub(crate) start: i32, 14 | /// The end time of the [`ResourceProfile`] (inclusive) 15 | pub(crate) end: i32, 16 | /// The IDs of the tasks which are part of the profile 17 | pub(crate) profile_tasks: Vec>>, 18 | /// The amount of cumulative resource usage of all [`profile 19 | /// tasks`][ResourceProfile::profile_tasks] (i.e. the height of the rectangle) 20 | pub(crate) height: i32, 21 | } 22 | 23 | impl Debug for ResourceProfile { 24 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 25 | f.debug_struct("ResourceProfile") 26 | .field("start", &self.start) 27 | .field("end", &self.end) 28 | .field("height", &self.height) 29 | .finish() 30 | } 31 | } 32 | 33 | impl ResourceProfile { 34 | pub(crate) fn default(time: i32) -> ResourceProfile { 35 | ResourceProfile { 36 | start: time, 37 | end: time, 38 | profile_tasks: Vec::new(), 39 | height: 0, 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/basic_types/function.rs: -------------------------------------------------------------------------------- 1 | use super::solution::ProblemSolution; 2 | use crate::basic_types::SolutionReference; 3 | use crate::containers::HashMap; 4 | use crate::variables::Literal; 5 | 6 | /// A struct which represents a linear function over weighted [`Literal`]s, and a 7 | /// constant term. 8 | #[derive(Clone, Default, Debug)] 9 | pub struct Function { 10 | literals: HashMap, 11 | constant_term: u64, 12 | } 13 | 14 | impl Function { 15 | pub fn get_sum_of_literal_weights(&self) -> u64 { 16 | self.literals.values().sum() 17 | } 18 | 19 | pub fn add_weighted_literal(&mut self, literal: Literal, weight: u64) { 20 | *self.literals.entry(!literal).or_insert(0) += weight; 21 | } 22 | 23 | pub fn add_constant_term(&mut self, value: u64) { 24 | self.constant_term += value; 25 | } 26 | 27 | pub fn get_literal_terms(&self) -> impl Iterator { 28 | self.literals.iter() 29 | } 30 | 31 | pub fn get_constant_term(&self) -> u64 { 32 | self.constant_term 33 | } 34 | 35 | pub fn evaluate_solution(&self, solution: SolutionReference) -> u64 { 36 | let mut value: u64 = self.constant_term; 37 | for (literal, weight) in self.get_literal_terms() { 38 | value += weight * (solution.get_literal_value(*literal)) as u64; 39 | } 40 | value 41 | } 42 | 43 | pub fn evaluate_assignment(&self, solution: SolutionReference) -> u64 { 44 | let mut value: u64 = self.constant_term; 45 | for (literal, weight) in self.get_literal_terms() { 46 | value += weight * solution.get_literal_value(*literal) as u32 as u64; 47 | } 48 | value 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pumpkin-checker/src/inferences/time_table.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use super::Fact; 4 | use crate::inferences::InvalidInference; 5 | use crate::model::Constraint; 6 | use crate::state::VariableState; 7 | 8 | /// Verifies a `time_table` inference for the cumulative constraint. 9 | /// 10 | /// The premises and negation of the consequent should lead to an overflow of the resource 11 | /// capacity. 12 | pub(crate) fn verify_time_table( 13 | fact: &Fact, 14 | constraint: &Constraint, 15 | ) -> Result<(), InvalidInference> { 16 | let Constraint::Cumulative(cumulative) = constraint else { 17 | return Err(InvalidInference::ConstraintLabelMismatch); 18 | }; 19 | 20 | let variable_state = VariableState::prepare_for_conflict_check(fact) 21 | .ok_or(InvalidInference::InconsistentPremises)?; 22 | 23 | // The profile is a key-value store. The keys correspond to time-points, and the values to the 24 | // relative change in resource consumption. A BTreeMap is used to maintain a sorted order of 25 | // the time points. 26 | let mut profile = BTreeMap::new(); 27 | 28 | for task in cumulative.tasks.iter() { 29 | let lst = variable_state.upper_bound(&task.start_time); 30 | let ect = variable_state.lower_bound(&task.start_time) + task.duration; 31 | 32 | if ect <= lst { 33 | *profile.entry(ect).or_insert(0) += task.resource_usage; 34 | *profile.entry(lst).or_insert(0) -= task.resource_usage; 35 | } 36 | } 37 | 38 | let mut usage = 0; 39 | for delta in profile.values() { 40 | usage += delta; 41 | 42 | if usage > cumulative.capacity { 43 | return Ok(()); 44 | } 45 | } 46 | 47 | Err(InvalidInference::Unsound) 48 | } 49 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/all_different.expected: -------------------------------------------------------------------------------- 1 | x1 = 4; 2 | x2 = 3; 3 | x3 = 2; 4 | x4 = 1; 5 | ---------- 6 | x1 = 3; 7 | x2 = 4; 8 | x3 = 2; 9 | x4 = 1; 10 | ---------- 11 | x1 = 4; 12 | x2 = 2; 13 | x3 = 3; 14 | x4 = 1; 15 | ---------- 16 | x1 = 2; 17 | x2 = 4; 18 | x3 = 3; 19 | x4 = 1; 20 | ---------- 21 | x1 = 3; 22 | x2 = 2; 23 | x3 = 4; 24 | x4 = 1; 25 | ---------- 26 | x1 = 2; 27 | x2 = 3; 28 | x3 = 4; 29 | x4 = 1; 30 | ---------- 31 | x1 = 4; 32 | x2 = 3; 33 | x3 = 1; 34 | x4 = 2; 35 | ---------- 36 | x1 = 3; 37 | x2 = 4; 38 | x3 = 1; 39 | x4 = 2; 40 | ---------- 41 | x1 = 4; 42 | x2 = 1; 43 | x3 = 3; 44 | x4 = 2; 45 | ---------- 46 | x1 = 1; 47 | x2 = 4; 48 | x3 = 3; 49 | x4 = 2; 50 | ---------- 51 | x1 = 3; 52 | x2 = 1; 53 | x3 = 4; 54 | x4 = 2; 55 | ---------- 56 | x1 = 1; 57 | x2 = 3; 58 | x3 = 4; 59 | x4 = 2; 60 | ---------- 61 | x1 = 4; 62 | x2 = 2; 63 | x3 = 1; 64 | x4 = 3; 65 | ---------- 66 | x1 = 2; 67 | x2 = 4; 68 | x3 = 1; 69 | x4 = 3; 70 | ---------- 71 | x1 = 4; 72 | x2 = 1; 73 | x3 = 2; 74 | x4 = 3; 75 | ---------- 76 | x1 = 1; 77 | x2 = 4; 78 | x3 = 2; 79 | x4 = 3; 80 | ---------- 81 | x1 = 2; 82 | x2 = 1; 83 | x3 = 4; 84 | x4 = 3; 85 | ---------- 86 | x1 = 1; 87 | x2 = 2; 88 | x3 = 4; 89 | x4 = 3; 90 | ---------- 91 | x1 = 3; 92 | x2 = 2; 93 | x3 = 1; 94 | x4 = 4; 95 | ---------- 96 | x1 = 2; 97 | x2 = 3; 98 | x3 = 1; 99 | x4 = 4; 100 | ---------- 101 | x1 = 3; 102 | x2 = 1; 103 | x3 = 2; 104 | x4 = 4; 105 | ---------- 106 | x1 = 1; 107 | x2 = 3; 108 | x3 = 2; 109 | x4 = 4; 110 | ---------- 111 | x1 = 2; 112 | x2 = 1; 113 | x3 = 3; 114 | x4 = 4; 115 | ---------- 116 | x1 = 1; 117 | x2 = 2; 118 | x3 = 3; 119 | x4 = 4; 120 | ---------- 121 | ========== 122 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/out_domain_max.rs: -------------------------------------------------------------------------------- 1 | use crate::branching::SelectionContext; 2 | use crate::branching::brancher::BrancherEvent; 3 | use crate::branching::value_selection::ValueSelector; 4 | use crate::engine::predicates::predicate::Predicate; 5 | use crate::engine::variables::DomainId; 6 | use crate::predicate; 7 | 8 | /// A [`ValueSelector`] which excludes the largest value from the domain. 9 | #[derive(Debug, Copy, Clone)] 10 | pub struct OutDomainMax; 11 | 12 | impl ValueSelector for OutDomainMax { 13 | fn select_value( 14 | &mut self, 15 | context: &mut SelectionContext, 16 | decision_variable: DomainId, 17 | ) -> Predicate { 18 | predicate!(decision_variable <= context.upper_bound(decision_variable) - 1) 19 | } 20 | 21 | fn subscribe_to_events(&self) -> Vec { 22 | vec![] 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use crate::basic_types::tests::TestRandom; 29 | use crate::branching::SelectionContext; 30 | use crate::branching::value_selection::OutDomainMax; 31 | use crate::branching::value_selection::ValueSelector; 32 | use crate::predicate; 33 | 34 | #[test] 35 | fn test_returns_correct_literal() { 36 | let (assignments, _) = SelectionContext::create_for_testing(vec![(0, 10)]); 37 | let mut test_rng = TestRandom::default(); 38 | let mut context = SelectionContext::new(&assignments, &mut test_rng); 39 | let domain_ids = context.get_domains().collect::>(); 40 | 41 | let mut selector = OutDomainMax; 42 | 43 | let selected_predicate = selector.select_value(&mut context, domain_ids[0]); 44 | assert_eq!(selected_predicate, predicate!(domain_ids[0] <= 9)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/out_domain_min.rs: -------------------------------------------------------------------------------- 1 | use crate::branching::SelectionContext; 2 | use crate::branching::brancher::BrancherEvent; 3 | use crate::branching::value_selection::ValueSelector; 4 | use crate::engine::predicates::predicate::Predicate; 5 | use crate::engine::variables::DomainId; 6 | use crate::predicate; 7 | 8 | /// A [`ValueSelector`] which excludes the smallest value from the domain. 9 | #[derive(Debug, Copy, Clone)] 10 | pub struct OutDomainMin; 11 | 12 | impl ValueSelector for OutDomainMin { 13 | fn select_value( 14 | &mut self, 15 | context: &mut SelectionContext, 16 | decision_variable: DomainId, 17 | ) -> Predicate { 18 | predicate!(decision_variable >= context.lower_bound(decision_variable) + 1) 19 | } 20 | 21 | fn subscribe_to_events(&self) -> Vec { 22 | vec![] 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use crate::basic_types::tests::TestRandom; 29 | use crate::branching::SelectionContext; 30 | use crate::branching::value_selection::OutDomainMin; 31 | use crate::branching::value_selection::ValueSelector; 32 | use crate::predicate; 33 | 34 | #[test] 35 | fn test_returns_correct_literal() { 36 | let (assignments, _) = SelectionContext::create_for_testing(vec![(0, 10)]); 37 | let mut test_rng = TestRandom::default(); 38 | let mut context = SelectionContext::new(&assignments, &mut test_rng); 39 | let domain_ids = context.get_domains().collect::>(); 40 | 41 | let mut selector = OutDomainMin; 42 | 43 | let selected_predicate = selector.select_value(&mut context, domain_ids[0]); 44 | assert_eq!(selected_predicate, predicate!(domain_ids[0] >= 1)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/in_domain_min.rs: -------------------------------------------------------------------------------- 1 | use super::ValueSelector; 2 | use crate::branching::SelectionContext; 3 | use crate::branching::brancher::BrancherEvent; 4 | use crate::engine::predicates::predicate::Predicate; 5 | use crate::engine::variables::IntegerVariable; 6 | use crate::predicate; 7 | 8 | /// [`ValueSelector`] which chooses to assign the provided variable to its lowest-bound. 9 | #[derive(Debug, Copy, Clone)] 10 | pub struct InDomainMin; 11 | 12 | impl ValueSelector for InDomainMin { 13 | fn select_value( 14 | &mut self, 15 | context: &mut SelectionContext, 16 | decision_variable: Var, 17 | ) -> Predicate { 18 | predicate!(decision_variable <= context.lower_bound(decision_variable)) 19 | } 20 | 21 | fn subscribe_to_events(&self) -> Vec { 22 | vec![] 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use crate::basic_types::tests::TestRandom; 29 | use crate::branching::SelectionContext; 30 | use crate::branching::value_selection::InDomainMin; 31 | use crate::branching::value_selection::ValueSelector; 32 | use crate::predicate; 33 | 34 | #[test] 35 | fn test_returns_correct_literal() { 36 | let (assignments, _) = SelectionContext::create_for_testing(vec![(0, 10)]); 37 | let mut test_rng = TestRandom::default(); 38 | let mut context = SelectionContext::new(&assignments, &mut test_rng); 39 | let domain_ids = context.get_domains().collect::>(); 40 | 41 | let mut selector = InDomainMin; 42 | 43 | let selected_predicate = selector.select_value(&mut context, domain_ids[0]); 44 | assert_eq!(selected_predicate, predicate!(domain_ids[0] <= 0)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/in_domain_max.rs: -------------------------------------------------------------------------------- 1 | use crate::branching::SelectionContext; 2 | use crate::branching::brancher::BrancherEvent; 3 | use crate::branching::value_selection::ValueSelector; 4 | use crate::engine::predicates::predicate::Predicate; 5 | use crate::engine::variables::IntegerVariable; 6 | use crate::predicate; 7 | 8 | /// [`ValueSelector`] which chooses to assign the provided variable to its upper-bound. 9 | #[derive(Debug, Copy, Clone)] 10 | pub struct InDomainMax; 11 | 12 | impl ValueSelector for InDomainMax { 13 | fn select_value( 14 | &mut self, 15 | context: &mut SelectionContext, 16 | decision_variable: Var, 17 | ) -> Predicate { 18 | predicate!(decision_variable >= context.upper_bound(decision_variable)) 19 | } 20 | 21 | fn subscribe_to_events(&self) -> Vec { 22 | vec![] 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use crate::basic_types::tests::TestRandom; 29 | use crate::branching::SelectionContext; 30 | use crate::branching::value_selection::InDomainMax; 31 | use crate::branching::value_selection::ValueSelector; 32 | use crate::predicate; 33 | 34 | #[test] 35 | fn test_returns_correct_literal() { 36 | let (assignments, _) = SelectionContext::create_for_testing(vec![(0, 10)]); 37 | let mut test_rng = TestRandom::default(); 38 | let mut context = SelectionContext::new(&assignments, &mut test_rng); 39 | let domain_ids = context.get_domains().collect::>(); 40 | 41 | let mut selector = InDomainMax; 42 | 43 | let selected_predicate = selector.select_value(&mut context, domain_ids[0]); 44 | assert_eq!(selected_predicate, predicate!(domain_ids[0] >= 10)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/int_times.expected: -------------------------------------------------------------------------------- 1 | a = 1; 2 | b = -3; 3 | c = -3; 4 | ---------- 5 | a = 3; 6 | b = -1; 7 | c = -3; 8 | ---------- 9 | a = -3; 10 | b = 1; 11 | c = -3; 12 | ---------- 13 | a = -1; 14 | b = 3; 15 | c = -3; 16 | ---------- 17 | a = 1; 18 | b = -2; 19 | c = -2; 20 | ---------- 21 | a = 2; 22 | b = -1; 23 | c = -2; 24 | ---------- 25 | a = -2; 26 | b = 1; 27 | c = -2; 28 | ---------- 29 | a = -1; 30 | b = 2; 31 | c = -2; 32 | ---------- 33 | a = 1; 34 | b = -1; 35 | c = -1; 36 | ---------- 37 | a = -1; 38 | b = 1; 39 | c = -1; 40 | ---------- 41 | a = 0; 42 | b = -3; 43 | c = 0; 44 | ---------- 45 | a = 0; 46 | b = -2; 47 | c = 0; 48 | ---------- 49 | a = 0; 50 | b = -1; 51 | c = 0; 52 | ---------- 53 | a = -3; 54 | b = 0; 55 | c = 0; 56 | ---------- 57 | a = -2; 58 | b = 0; 59 | c = 0; 60 | ---------- 61 | a = -1; 62 | b = 0; 63 | c = 0; 64 | ---------- 65 | a = 0; 66 | b = 0; 67 | c = 0; 68 | ---------- 69 | a = 1; 70 | b = 0; 71 | c = 0; 72 | ---------- 73 | a = 2; 74 | b = 0; 75 | c = 0; 76 | ---------- 77 | a = 3; 78 | b = 0; 79 | c = 0; 80 | ---------- 81 | a = 0; 82 | b = 1; 83 | c = 0; 84 | ---------- 85 | a = 0; 86 | b = 2; 87 | c = 0; 88 | ---------- 89 | a = 0; 90 | b = 3; 91 | c = 0; 92 | ---------- 93 | a = -1; 94 | b = -1; 95 | c = 1; 96 | ---------- 97 | a = 1; 98 | b = 1; 99 | c = 1; 100 | ---------- 101 | a = -1; 102 | b = -2; 103 | c = 2; 104 | ---------- 105 | a = -2; 106 | b = -1; 107 | c = 2; 108 | ---------- 109 | a = 2; 110 | b = 1; 111 | c = 2; 112 | ---------- 113 | a = 1; 114 | b = 2; 115 | c = 2; 116 | ---------- 117 | a = -1; 118 | b = -3; 119 | c = 3; 120 | ---------- 121 | a = -3; 122 | b = -1; 123 | c = 3; 124 | ---------- 125 | a = 3; 126 | b = 1; 127 | c = 3; 128 | ---------- 129 | a = 1; 130 | b = 3; 131 | c = 3; 132 | ---------- 133 | ========== 134 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/value_selection/dynamic_value_selector.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use super::ValueSelector; 4 | use crate::basic_types::SolutionReference; 5 | use crate::branching::SelectionContext; 6 | use crate::branching::brancher::BrancherEvent; 7 | #[cfg(doc)] 8 | use crate::branching::branchers::dynamic_brancher::DynamicBrancher; 9 | use crate::engine::predicates::predicate::Predicate; 10 | use crate::engine::variables::DomainId; 11 | 12 | /// Similar to [`DynamicBrancher`], this is a pass-along structure which should be used when a 13 | /// [`Sized`] object is required. 14 | pub struct DynamicValueSelector { 15 | selector: Box>, 16 | } 17 | 18 | impl Debug for DynamicValueSelector { 19 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 20 | f.debug_struct("DynamicValueSelector").finish() 21 | } 22 | } 23 | 24 | impl DynamicValueSelector { 25 | pub fn new(selector: Box>) -> Self { 26 | Self { selector } 27 | } 28 | } 29 | 30 | impl ValueSelector for DynamicValueSelector { 31 | fn select_value( 32 | &mut self, 33 | context: &mut SelectionContext, 34 | decision_variable: Var, 35 | ) -> Predicate { 36 | self.selector.select_value(context, decision_variable) 37 | } 38 | 39 | fn on_solution(&mut self, solution: SolutionReference) { 40 | self.selector.on_solution(solution) 41 | } 42 | 43 | fn on_unassign_integer(&mut self, variable: DomainId, value: i32) { 44 | self.selector.on_unassign_integer(variable, value) 45 | } 46 | 47 | fn is_restart_pointless(&mut self) -> bool { 48 | self.selector.is_restart_pointless() 49 | } 50 | 51 | fn subscribe_to_events(&self) -> Vec { 52 | self.selector.subscribe_to_events() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pumpkin-solver/src/bin/pumpkin-solver/flatzinc/compiler/create_objective.rs: -------------------------------------------------------------------------------- 1 | //! Add objective function to solver 2 | 3 | use flatzinc::BoolExpr; 4 | use flatzinc::Goal; 5 | 6 | use super::context::CompilationContext; 7 | use crate::flatzinc::FlatZincError; 8 | use crate::flatzinc::ast::FlatZincAst; 9 | use crate::flatzinc::instance::FlatzincObjective; 10 | 11 | pub(crate) fn run( 12 | ast: &FlatZincAst, 13 | context: &mut CompilationContext, 14 | ) -> Result, FlatZincError> { 15 | match &ast.solve_item.goal { 16 | Goal::Satisfy => Ok(None), 17 | Goal::OptimizeBool(optimization_type, bool_expr) => { 18 | // The objective function will be parsed as a bool because that is the first identifier 19 | // it will find For now we assume that the objective function is a single 20 | // integer 21 | 22 | let domain = match bool_expr { 23 | BoolExpr::Bool(_) => unreachable!( 24 | "We do not expect a constant to be present in the objective function!" 25 | ), 26 | BoolExpr::VarParIdentifier(x) => { 27 | if context.is_identifier_parameter(x) { 28 | context.resolve_integer_constant_from_identifier(x)? 29 | } else { 30 | context.resolve_integer_variable_from_identifier(x)? 31 | } 32 | } 33 | }; 34 | 35 | Ok(Some(match optimization_type { 36 | flatzinc::OptimizationType::Minimize => FlatzincObjective::Minimize(domain), 37 | flatzinc::OptimizationType::Maximize => FlatzincObjective::Maximize(domain), 38 | })) 39 | } 40 | _ => todo!( 41 | "For now we assume that the optimisation function is a single integer to optimise" 42 | ), 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pumpkin-solver-py/examples/nqueens.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | from pathlib import Path 3 | 4 | from pumpkin_solver_py import constraints, SatisfactionResult, Model 5 | 6 | 7 | def main(n: int, proof: Path | None): 8 | assert n > 0, "Please provide a positive non-zero 'n'" 9 | 10 | model = Model() 11 | 12 | variables = [model.new_integer_variable(0, n - 1, name=f"q{i}") for i in range(n)] 13 | 14 | model.add_constraint(constraints.AllDifferent(variables), tag=1) 15 | 16 | diag1 = [var.offset(i) for (i, var) in enumerate(variables)] 17 | diag2 = [var.offset(-i) for (i, var) in enumerate(variables)] 18 | 19 | model.add_constraint(constraints.AllDifferent(diag1), tag=2) 20 | model.add_constraint(constraints.AllDifferent(diag2), tag=3) 21 | 22 | status = model.satisfy(proof=proof) 23 | match status: 24 | case SatisfactionResult.Satisfiable(solution): 25 | row_separator = "+---" * n + "+" 26 | 27 | for row in range(n): 28 | print(f"{row_separator}") 29 | queen_col = solution.int_value(variables[row]) 30 | 31 | for col in range(n): 32 | string = "| * " if queen_col == col else "| " 33 | print(f"{string}", end="") 34 | 35 | print("|") 36 | 37 | print(f"{row_separator}") 38 | 39 | case SatisfactionResult.Unsatisfiable(): 40 | print(f"{n}-queens is unsatisfiable.") 41 | 42 | case SatisfactionResult.Unknown(): 43 | print("Timeout.") 44 | 45 | 46 | if __name__ == "__main__": 47 | arg_parser = ArgumentParser() 48 | 49 | arg_parser.add_argument("--proof", type=Path, help="The proof file.", default=None) 50 | arg_parser.add_argument("n", type=int, help="The size of the chessboard.") 51 | 52 | args = arg_parser.parse_args() 53 | 54 | main(args.n, args.proof) 55 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/engine/notifications/domain_event_notification/domain_events.rs: -------------------------------------------------------------------------------- 1 | use enumset::EnumSet; 2 | use enumset::enum_set; 3 | 4 | use super::DomainEvent; 5 | 6 | /// A set of [`DomainEvent`]s. 7 | #[derive(Debug, Copy, Clone)] 8 | pub struct DomainEvents { 9 | events: Option>, 10 | } 11 | 12 | impl DomainEvents { 13 | /// DomainEvents with both lower and upper bound tightening (but not other value removal). 14 | pub const BOUNDS: DomainEvents = 15 | DomainEvents::new(enum_set!(DomainEvent::LowerBound | DomainEvent::UpperBound)); 16 | // this is all options right now, but won't be once we add variables of other types 17 | /// DomainEvents with lower and upper bound tightening, assigning to a single value, and 18 | /// single value removal. 19 | pub const ANY_INT: DomainEvents = DomainEvents::new(enum_set!( 20 | DomainEvent::Assign 21 | | DomainEvent::LowerBound 22 | | DomainEvent::UpperBound 23 | | DomainEvent::Removal 24 | )); 25 | /// DomainEvents with only lower bound tightening. 26 | pub const LOWER_BOUND: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::LowerBound)); 27 | /// DomainEvents with only upper bound tightening. 28 | pub const UPPER_BOUND: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::UpperBound)); 29 | /// DomainEvents with only assigning to a single value. 30 | pub const ASSIGN: DomainEvents = DomainEvents::new(enum_set!(DomainEvent::Assign)); 31 | } 32 | 33 | impl DomainEvents { 34 | pub(crate) const fn new(int_events: EnumSet) -> DomainEvents { 35 | DomainEvents { 36 | events: Some(int_events), 37 | } 38 | } 39 | 40 | pub(crate) fn events(&self) -> EnumSet { 41 | self.events 42 | .expect("Tried to retrieve int_events when it was not initialized") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /drcp-format/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.3.0](https://github.com/ConSol-Lab/Pumpkin/compare/drcp-format-v0.2.1...drcp-format-v0.3.0) (2025-07-10) 9 | 10 | 11 | ### Features 12 | 13 | * Update to the new format, which inlines atomic constraint definitions into the proof steps ([#204](https://github.com/ConSol-Lab/Pumpkin/issues/204)) ([5cdc747](https://github.com/ConSol-Lab/Pumpkin/commit/5cdc747d8f241859dfea806297595f7feb12fa7e)) 14 | * Do mapping from codes to atomic constraints inside the crate ([#204](https://github.com/ConSol-Lab/Pumpkin/issues/204)) ([5cdc747](https://github.com/ConSol-Lab/Pumpkin/commit/5cdc747d8f241859dfea806297595f7feb12fa7e)) 15 | 16 | ## [0.2.1](https://github.com/consol-lab/pumpkin/compare/drcp-format-v0.2.0...drcp-format-v0.2.1) (2025-04-11) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * an empty nogood with hints can now be parsed. ([e4cb2cc](https://github.com/consol-lab/pumpkin/commit/e4cb2ccef1aa821e7dae6e162b53fba4682aeca2)) 22 | 23 | ## [0.2.0](https://github.com/ConSol-Lab/Pumpkin/compare/drcp-format-v0.1.0...drcp-format-v0.2.0) (2024-11-05) 24 | 25 | 26 | ### ⚠ BREAKING CHANGES 27 | 28 | * introduce inference-nogoods in drcp-format ([#98](https://github.com/ConSol-Lab/Pumpkin/issues/98)) 29 | 30 | ### Features 31 | 32 | * introduce inference-nogoods in drcp-format ([#98](https://github.com/ConSol-Lab/Pumpkin/issues/98)) ([e5ae6c2](https://github.com/ConSol-Lab/Pumpkin/commit/e5ae6c25ac6d9e5407d3b1ed963c20ef25e88d18)) 33 | 34 | ## [0.1.0] - 2024-10-16 35 | 36 | ### Added 37 | 38 | - Parsing/reading of DRCP files. 39 | - Writing of DRCP files. 40 | - Reading of literal definition files. 41 | - Writing of literal definition files. 42 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/branching/variable_selection/dynamic_variable_selector.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use super::VariableSelector; 4 | use crate::branching::SelectionContext; 5 | use crate::branching::brancher::BrancherEvent; 6 | #[cfg(doc)] 7 | use crate::branching::branchers::dynamic_brancher::DynamicBrancher; 8 | use crate::engine::predicates::predicate::Predicate; 9 | use crate::engine::variables::DomainId; 10 | 11 | /// Similar to [`DynamicBrancher`], this is a pass-along structure which should be used when a 12 | /// [`Sized`] object is required. 13 | pub struct DynamicVariableSelector { 14 | selector: Box>, 15 | } 16 | 17 | impl Debug for DynamicVariableSelector { 18 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 19 | f.debug_struct("DynamicVariableSelector").finish() 20 | } 21 | } 22 | 23 | impl DynamicVariableSelector { 24 | pub fn new(selector: Box>) -> Self { 25 | Self { selector } 26 | } 27 | } 28 | 29 | impl VariableSelector for DynamicVariableSelector { 30 | fn select_variable(&mut self, context: &mut SelectionContext) -> Option { 31 | self.selector.select_variable(context) 32 | } 33 | 34 | fn on_appearance_in_conflict_predicate(&mut self, predicate: Predicate) { 35 | self.selector.on_appearance_in_conflict_predicate(predicate) 36 | } 37 | 38 | fn on_conflict(&mut self) { 39 | self.selector.on_conflict() 40 | } 41 | 42 | fn on_unassign_integer(&mut self, variable: DomainId, value: i32) { 43 | self.selector.on_unassign_integer(variable, value) 44 | } 45 | 46 | fn is_restart_pointless(&mut self) -> bool { 47 | self.selector.is_restart_pointless() 48 | } 49 | 50 | fn subscribe_to_events(&self) -> Vec { 51 | self.selector.subscribe_to_events() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fzn-rs-derive/src/common.rs: -------------------------------------------------------------------------------- 1 | use convert_case::Case; 2 | use convert_case::Casing; 3 | 4 | /// Get the name of the constraint or annotation from the variant. This either is converting the 5 | /// variant name to snake case, or retrieving the value from the `#[name(...)]` attribute. 6 | pub(crate) fn get_explicit_name(variant: &syn::Variant) -> syn::Result { 7 | variant 8 | .attrs 9 | .iter() 10 | // Find the attribute with a `name` as the path. 11 | .find(|attr| attr.path().get_ident().is_some_and(|ident| ident == "name")) 12 | // Parse the arguments of the attribute to a string literal. 13 | .map(|attr| { 14 | attr.parse_args::() 15 | .map(|string_lit| string_lit.value()) 16 | }) 17 | // If no `name` attribute exists, return the snake-case version of the variant name. 18 | .unwrap_or_else(|| Ok(variant.ident.to_string().to_case(Case::Snake))) 19 | } 20 | 21 | /// Returns the type of the arguments for the variant if the variant has exactly the following 22 | /// shape: 23 | /// 24 | /// ```ignore 25 | /// #[args] 26 | /// Variant(Type) 27 | /// ``` 28 | pub(crate) fn get_args_type(variant: &syn::Variant) -> Option<&syn::Type> { 29 | let has_args_attr = variant 30 | .attrs 31 | .iter() 32 | .any(|attr| attr.path().get_ident().is_some_and(|ident| ident == "args")); 33 | 34 | if !has_args_attr { 35 | return None; 36 | } 37 | 38 | if variant.fields.len() != 1 { 39 | // If there is not exactly one argument for this variant, then it cannot be a struct 40 | // constraint. 41 | return None; 42 | } 43 | 44 | let field = variant 45 | .fields 46 | .iter() 47 | .next() 48 | .expect("there is exactly one field"); 49 | 50 | if field.ident.is_none() { 51 | Some(&field.ty) 52 | } else { 53 | None 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pumpkin-crates/core/src/propagators/nogoods/nogood_info.rs: -------------------------------------------------------------------------------- 1 | /// A struct which represents a nogood (i.e. a list of [`Predicate`]s which cannot all be true at 2 | /// the same time). 3 | /// 4 | /// It additionally contains certain fields related to how the clause was created/activity. 5 | #[derive(Clone, Debug, Default)] 6 | pub(crate) struct NogoodInfo { 7 | /// Indicates whether the nogood is a learned nogood or not. 8 | pub(crate) is_learned: bool, 9 | /// The LBD score of the nogood; this is an indication of how "good" the nogood is. 10 | pub(crate) lbd: u32, 11 | /// Whether the nogood has been marked as deleted; this means that it can be replaced by 12 | /// another nogood in the future. 13 | pub(crate) is_deleted: bool, 14 | /// Whether to not allow the nogood to have their activity bumped. 15 | /// 16 | /// A single nogood can be bumped at most twice when learning a new nogood. It can appear at 17 | /// most once during conflict analysis, and at most once during recursive minimisation. 18 | /// Setting this to true prevents a nogood from being bumped twice if it is used in both 19 | /// conflict analysis and recursive minisation. 20 | /// 21 | /// TODO: not clear whether this is a problem or whether it makes sense. 22 | pub(crate) block_bumps: bool, 23 | /// The activity score of the nogood. 24 | pub(crate) activity: f32, 25 | } 26 | 27 | impl NogoodInfo { 28 | pub(crate) fn new_learned_nogood_info(lbd: u32) -> Self { 29 | NogoodInfo { 30 | is_learned: true, 31 | lbd, 32 | is_deleted: false, 33 | block_bumps: false, 34 | activity: 0.0, 35 | } 36 | } 37 | 38 | pub(crate) fn new_permanent_nogood_info() -> Self { 39 | NogoodInfo { 40 | is_learned: false, 41 | lbd: 0, 42 | is_deleted: false, 43 | block_bumps: false, 44 | activity: 0.0, 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/mzn_constraints/unbounded_integer.expected: -------------------------------------------------------------------------------- 1 | x = -2; 2 | y = -2; 3 | z = -2; 4 | ---------- 5 | x = -2; 6 | y = -1; 7 | z = -2; 8 | ---------- 9 | x = -2; 10 | y = 0; 11 | z = -2; 12 | ---------- 13 | x = -2; 14 | y = 1; 15 | z = -2; 16 | ---------- 17 | x = -2; 18 | y = 2; 19 | z = -2; 20 | ---------- 21 | x = -1; 22 | y = -1; 23 | z = -2; 24 | ---------- 25 | x = -1; 26 | y = 0; 27 | z = -2; 28 | ---------- 29 | x = -1; 30 | y = 1; 31 | z = -2; 32 | ---------- 33 | x = -1; 34 | y = 2; 35 | z = -2; 36 | ---------- 37 | x = -1; 38 | y = -1; 39 | z = -1; 40 | ---------- 41 | x = -1; 42 | y = 0; 43 | z = -1; 44 | ---------- 45 | x = -1; 46 | y = 1; 47 | z = -1; 48 | ---------- 49 | x = -1; 50 | y = 2; 51 | z = -1; 52 | ---------- 53 | x = 0; 54 | y = 0; 55 | z = -2; 56 | ---------- 57 | x = 0; 58 | y = 1; 59 | z = -2; 60 | ---------- 61 | x = 0; 62 | y = 2; 63 | z = -2; 64 | ---------- 65 | x = 0; 66 | y = 0; 67 | z = -1; 68 | ---------- 69 | x = 0; 70 | y = 1; 71 | z = -1; 72 | ---------- 73 | x = 0; 74 | y = 2; 75 | z = -1; 76 | ---------- 77 | x = 0; 78 | y = 0; 79 | z = 0; 80 | ---------- 81 | x = 0; 82 | y = 1; 83 | z = 0; 84 | ---------- 85 | x = 0; 86 | y = 2; 87 | z = 0; 88 | ---------- 89 | x = 1; 90 | y = 1; 91 | z = -2; 92 | ---------- 93 | x = 1; 94 | y = 2; 95 | z = -2; 96 | ---------- 97 | x = 1; 98 | y = 1; 99 | z = -1; 100 | ---------- 101 | x = 1; 102 | y = 2; 103 | z = -1; 104 | ---------- 105 | x = 1; 106 | y = 1; 107 | z = 0; 108 | ---------- 109 | x = 1; 110 | y = 2; 111 | z = 0; 112 | ---------- 113 | x = 1; 114 | y = 1; 115 | z = 1; 116 | ---------- 117 | x = 1; 118 | y = 2; 119 | z = 1; 120 | ---------- 121 | x = 2; 122 | y = 2; 123 | z = -2; 124 | ---------- 125 | x = 2; 126 | y = 2; 127 | z = -1; 128 | ---------- 129 | x = 2; 130 | y = 2; 131 | z = 0; 132 | ---------- 133 | x = 2; 134 | y = 2; 135 | z = 1; 136 | ---------- 137 | x = 2; 138 | y = 2; 139 | z = 2; 140 | ---------- 141 | ========== 142 | -------------------------------------------------------------------------------- /pumpkin-solver/tests/wcnf_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] // workaround for https://github.com/rust-lang/rust-clippy/issues/11024 2 | use std::process::Command; 3 | use std::process::Output; 4 | 5 | mod helpers; 6 | 7 | use helpers::Checker; 8 | use helpers::CheckerOutput; 9 | use helpers::Files; 10 | use helpers::run_solution_checker; 11 | use helpers::run_solver; 12 | 13 | macro_rules! test_wcnf_instance { 14 | ($name:ident, $optimal_objective:literal) => { 15 | #[test] 16 | fn $name() { 17 | run_wcnf_test(stringify!($name), $optimal_objective); 18 | } 19 | }; 20 | } 21 | 22 | test_wcnf_instance!(simple, 1); 23 | test_wcnf_instance!(karate, 4); 24 | test_wcnf_instance!(riskmap, 9); 25 | test_wcnf_instance!(johnson8_2_4, 24); 26 | test_wcnf_instance!(johnson8_4_4, 56); 27 | test_wcnf_instance!(normalized_g2x2, 2); 28 | test_wcnf_instance!(normalized_g9x3, 7); 29 | // test_wcnf_instance!(normalized_g9x9, 20); 30 | test_wcnf_instance!(ram_k3_n9, 1); 31 | 32 | struct MaxSATChecker { 33 | expected_objective: u64, 34 | } 35 | 36 | impl Checker for MaxSATChecker { 37 | fn executable_name(&self) -> &'static str { 38 | "maxsat-checker" 39 | } 40 | 41 | fn prepare_command(&self, cmd: &mut Command, files: &Files) { 42 | let _ = cmd.arg("-o").arg(format!("{}", self.expected_objective)); 43 | let _ = cmd.arg(&files.instance_file); 44 | let _ = cmd.arg(&files.log_file); 45 | } 46 | 47 | fn parse_checker_output(&self, output: &Output) -> CheckerOutput { 48 | if output.status.success() { 49 | CheckerOutput::Acceptable 50 | } else { 51 | CheckerOutput::Panic 52 | } 53 | } 54 | } 55 | 56 | fn run_wcnf_test(instance_name: &str, expected_objective: u64) { 57 | let instance_path = format!( 58 | "{}/tests/wcnf/{instance_name}.wcnf", 59 | env!("CARGO_MANIFEST_DIR") 60 | ); 61 | let files = run_solver(instance_path, false); 62 | 63 | run_solution_checker(files, MaxSATChecker { expected_objective }); 64 | } 65 | --------------------------------------------------------------------------------