logicng 0.1.0-alpha.3

A Library for Creating, Manipulating, and Solving Boolean Formulas
Documentation
use crate::cardinality_constraints::cc_config::{AlkEncoder, AmkEncoder, CcConfig};
use crate::formulas::CType::{GE, LE};
use crate::formulas::{FormulaFactory, Variable};
use crate::solver::minisat::sat::Tristate::{False, True};
use crate::solver::minisat::{MiniSat, MiniSatConfig};

const fn configs() -> [CcConfig; 3] {
    [
        CcConfig::new().amk_encoder(AmkEncoder::Totalizer).alk_encoder(AlkEncoder::Totalizer),
        CcConfig::new().amk_encoder(AmkEncoder::CardinalityNetwork).alk_encoder(AlkEncoder::CardinalityNetwork),
        CcConfig::new().amk_encoder(AmkEncoder::ModularTotalizer).alk_encoder(AlkEncoder::ModularTotalizer),
    ]
}

fn solvers() -> [MiniSat; 2] {
    [MiniSat::new_with_config(MiniSatConfig::default()), MiniSat::new_with_config(MiniSatConfig::default().incremental(false))]
}

#[test]
fn test_simple_incremental_amk() {
    for config in configs() {
        for solver in &mut solvers() {
            let f = &mut FormulaFactory::new();
            f.config.cc_config = configs()[2].clone();
            let vars: Box<[Variable]> = (0..10).map(|i| f.var(&format!("v{i}"))).collect();
            solver.add(f.cc(GE, 4, vars.clone()), f);
            solver.add(f.cc(LE, 7, vars.clone()), f);
            f.config.cc_config = config.clone();

            let mut inc_data = solver.add_incremental_cc(&f.cc(LE, 9, vars).as_cc(f).unwrap(), f).unwrap();
            assert_eq!(solver.sat(), True);
            inc_data.new_upper_bound_for_solver(solver, f, 8);
            assert_eq!(solver.sat(), True);
            inc_data.new_upper_bound_for_solver(solver, f, 7);
            assert_eq!(solver.sat(), True);
            inc_data.new_upper_bound_for_solver(solver, f, 6);
            assert_eq!(solver.sat(), True);
            inc_data.new_upper_bound_for_solver(solver, f, 5);
            assert_eq!(solver.sat(), True);
            inc_data.new_upper_bound_for_solver(solver, f, 4);
            assert_eq!(solver.sat(), True);

            if solver.underlying_solver.config.incremental {
                let state = solver.save_state();
                inc_data.new_upper_bound_for_solver(solver, f, 3);
                assert_eq!(solver.sat(), False);
                solver.load_state(&state);
                assert_eq!(solver.sat(), True);
                inc_data.new_upper_bound_for_solver(solver, f, 2);
                assert_eq!(solver.sat(), False);
            }
        }
    }
}

#[test]
fn test_simple_incremental_alk() {
    for config in configs() {
        for solver in &mut solvers() {
            let f = &mut FormulaFactory::new();
            f.config.cc_config = configs()[2].clone();
            let vars: Box<[Variable]> = (0..10).map(|i| f.var(&format!("v{i}"))).collect();
            solver.add(f.cc(GE, 4, vars.clone()), f);
            solver.add(f.cc(LE, 7, vars.clone()), f);
            f.config.cc_config = config.clone();

            let mut inc_data = solver.add_incremental_cc(&f.cc(GE, 2, vars).as_cc(f).unwrap(), f).unwrap();
            assert_eq!(solver.sat(), True);
            inc_data.new_lower_bound_for_solver(solver, f, 3);
            assert_eq!(solver.sat(), True);
            inc_data.new_lower_bound_for_solver(solver, f, 4);
            assert_eq!(solver.sat(), True);
            inc_data.new_lower_bound_for_solver(solver, f, 5);
            assert_eq!(solver.sat(), True);
            inc_data.new_lower_bound_for_solver(solver, f, 6);
            assert_eq!(solver.sat(), True);
            inc_data.new_lower_bound_for_solver(solver, f, 7);
            assert_eq!(solver.sat(), True);

            if solver.underlying_solver.config.incremental {
                let state = solver.save_state();
                inc_data.new_lower_bound_for_solver(solver, f, 8);
                assert_eq!(solver.sat(), False);
                solver.load_state(&state);
                assert_eq!(solver.sat(), True);
                inc_data.new_lower_bound_for_solver(solver, f, 9);
                assert_eq!(solver.sat(), False);
            }
        }
    }
}

#[test]
#[cfg_attr(not(feature = "long_running_tests"), ignore)]
fn test_large_upper_bound_amk() {
    for config in [&configs()[0], &configs()[2]] {
        for mut solver in solvers() {
            let f = &mut FormulaFactory::new();
            f.config.cc_config = configs()[2].clone();
            let num_lits = 100;
            let vars: Box<[Variable]> = (0..num_lits).map(|i| f.var(&format!("v{i}"))).collect();
            let mut current_bound = num_lits - 1;
            solver.add(f.cc(GE, 42, vars.clone()), f);
            f.config.cc_config = config.clone();
            let mut inc_data = solver.add_incremental_cc(&f.cc(LE, current_bound, vars).as_cc(f).unwrap(), f).unwrap();
            while solver.sat() == True {
                current_bound -= 1;
                inc_data.new_upper_bound_for_solver(&mut solver, f, current_bound);
            }
            assert_eq!(current_bound, 41);
        }
    }
}

#[test]
#[cfg_attr(not(feature = "long_running_tests"), ignore)]
fn test_large_lower_bound_alk() {
    for config in [&configs()[0], &configs()[2]] {
        for mut solver in solvers() {
            let f = &mut FormulaFactory::new();
            f.config.cc_config = configs()[2].clone();
            let num_lits = 100;
            let vars: Box<[Variable]> = (0..num_lits).map(|i| f.var(&format!("v{i}"))).collect();
            let mut current_bound = 2;
            solver.add(f.cc(LE, 87, vars.clone()), f);
            f.config.cc_config = config.clone();
            let mut inc_data = solver.add_incremental_cc(&f.cc(GE, current_bound, vars).as_cc(f).unwrap(), f).unwrap();
            while solver.sat() == True {
                current_bound += 1;
                inc_data.new_lower_bound_for_solver(&mut solver, f, current_bound);
            }
            assert_eq!(current_bound, 88);
        }
    }
}

#[test]
#[ignore = "Too large for MiniSat, requires Glucose"]
fn test_very_large_modular_totalizer_amk() {
    let f = &mut FormulaFactory::new();
    f.config.cc_config = configs()[2].clone();
    let num_lits = 300;
    let vars: Box<[Variable]> = (0..num_lits).map(|i| f.var(&format!("v{i}"))).collect();
    let mut current_bound = num_lits - 1;
    let mut solver = MiniSat::new();
    solver.add(f.cc(GE, 234, vars.clone()), f);
    let mut inc_data = solver.add_incremental_cc(&f.cc(LE, current_bound, vars).as_cc(f).unwrap(), f).unwrap();
    while solver.sat() == True {
        current_bound -= 1;
        inc_data.new_upper_bound_for_solver(&mut solver, f, current_bound);
    }
    assert_eq!(current_bound, 233);
}