Lines
100 %
Functions
use conjure_core::matrix_expr;
use conjure_oxide::ast::{
Atom::Reference, Declaration, Domain::BoolDomain, Domain::IntDomain, Expression::*, Name, Range,
};
use conjure_oxide::solver::adaptors::sat_common::CNFModel;
use conjure_oxide::solver::SolverError;
use conjure_oxide::utils::testing::assert_eq_any_order;
use conjure_oxide::{Metadata, Model as ConjureModel};
#[test]
fn test_single_var() {
// x -> [[1]]
let mut model: ConjureModel = ConjureModel::default();
let submodel = model.as_submodel_mut();
let x: Name = Name::UserName(String::from('x'));
submodel.add_symbol(Declaration::new_var(x.clone(), BoolDomain));
submodel.add_constraint(Atomic(Metadata::new(), Reference(x.clone())));
let res: Result<CNFModel, SolverError> = CNFModel::from_conjure(model);
assert!(res.is_ok());
let cnf = res.unwrap();
assert_eq!(cnf.get_index(&x), Some(1));
assert!(cnf.get_name(1).is_some());
assert_eq!(cnf.get_name(1).unwrap(), &x);
assert_eq!(cnf.clauses, vec![vec![1]]);
}
fn test_single_not() {
// Not(x) -> [[-1]]
submodel.add_constraint(Not(
Metadata::new(),
Box::from(Atomic(Metadata::new(), Reference(x.clone()))),
));
let cnf: CNFModel = CNFModel::from_conjure(model).unwrap();
assert_eq!(cnf.clauses, vec![vec![-1]]);
assert_eq!(
cnf.as_expression().unwrap(),
And(
Box::new(matrix_expr![Or(
Box::new(matrix_expr![Not(
Box::from(Atomic(Metadata::new(), Reference(x.clone())))
)])
)
fn test_single_or() {
// Or(x, y) -> [[1, 2]]
let y: Name = Name::UserName(String::from('y'));
submodel.add_symbol(Declaration::new_var(y.clone(), BoolDomain));
submodel.add_constraint(Or(
Box::new(matrix_expr![
Atomic(Metadata::new(), Reference(x.clone())),
Atomic(Metadata::new(), Reference(y.clone())),
]),
let xi = cnf.get_index(&x).unwrap();
let yi = cnf.get_index(&y).unwrap();
assert_eq_any_order(&cnf.clauses, &vec![vec![xi, yi]]);
fn test_or_not() {
// Or(x, Not(y)) -> [[1, -2]]
Not(
Box::from(Atomic(Metadata::new(), Reference(y.clone()))),
),
assert_eq_any_order(&cnf.clauses, &vec![vec![xi, -yi]]);
Box::from(Atomic(Metadata::new(), Reference(y.clone())))
])
fn test_multiple() {
// [x, y] - equivalent to And(x, y) -> [[1], [2]]
submodel.add_constraint(Atomic(Metadata::new(), Reference(y.clone())));
assert_eq_any_order(&cnf.clauses, &vec![vec![xi], vec![yi]]);
Or(
Box::new(matrix_expr![Atomic(Metadata::new(), Reference(x.clone()))])
Box::new(matrix_expr![Atomic(Metadata::new(), Reference(y.clone()))])
fn test_and() {
// And(x, y) -> [[1], [2]]
submodel.add_constraint(And(
Box::new(matrix_expr![Atomic(Metadata::new(), Reference(x.clone())),])
Box::new(matrix_expr![Atomic(Metadata::new(), Reference(y.clone())),])
fn test_nested_ors() {
// Or(x, Or(y, z)) -> [[1, 2, 3]]
let z: Name = Name::UserName(String::from('z'));
submodel.add_symbol(Declaration::new_var(z.clone(), BoolDomain));
Atomic(Metadata::new(), Reference(z.clone())),
let zi = cnf.get_index(&z).unwrap();
assert_eq_any_order(&cnf.clauses, &vec![vec![xi, yi, zi]]);
fn test_int() {
// y is an IntDomain - only booleans should be allowed
submodel.add_symbol(Declaration::new_var(
y.clone(),
IntDomain(vec![Range::Bounded(1, 2)]),
let cnf: Result<CNFModel, SolverError> = CNFModel::from_conjure(model);
assert!(cnf.is_err());
fn test_eq() {
// Eq(x, y) - this operation is not allowed
submodel.add_constraint(Eq(