fix admissibility, unify with verification
This commit is contained in:
parent
7b24b2b96a
commit
328cd79636
|
@ -4,31 +4,111 @@ use crate::{
|
||||||
aba::{inference_helper, Aba, Inference},
|
aba::{inference_helper, Aba, Inference},
|
||||||
clauses::{Atom, Clause, ClauseList},
|
clauses::{Atom, Clause, ClauseList},
|
||||||
literal::{InferenceAtom, InferenceAtomHelper, IntoLiteral},
|
literal::{InferenceAtom, InferenceAtomHelper, IntoLiteral},
|
||||||
mapper::Mapper,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{LoopControl, MultishotProblem};
|
use super::{LoopControl, MultishotProblem, Problem, SolverState};
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Admissibility<A: Atom> {
|
pub struct Admissibility<A: Atom> {
|
||||||
found: Vec<HashSet<A>>,
|
found: Vec<HashSet<A>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VerifyAdmissibility<A: Atom> {
|
||||||
|
pub assumptions: Vec<A>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SetInference<A: Atom>(A);
|
pub struct SetInference<A: Atom>(A);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SetInferenceHelper<A: Atom>(usize, A);
|
pub struct SetInferenceHelper<A: Atom>(usize, A);
|
||||||
|
|
||||||
|
fn initial_clauses<A: Atom>(aba: &Aba<A>) -> ClauseList {
|
||||||
|
let mut clauses = vec![];
|
||||||
|
// Create inference for the problem set
|
||||||
|
inference_helper::<SetInference<_>, _>(aba).collect_into(&mut clauses);
|
||||||
|
// Attack the inference of the aba, if an attack exists
|
||||||
|
for (assumption, inverse) in &aba.inverses {
|
||||||
|
[
|
||||||
|
// For any assumption `a` and it's inverse `b`:
|
||||||
|
// Inference(a) <=> not SetInference(b)
|
||||||
|
Clause::from(vec![
|
||||||
|
Inference::new(assumption.clone()).pos(),
|
||||||
|
SetInference::new(inverse.clone()).pos(),
|
||||||
|
]),
|
||||||
|
Clause::from(vec![
|
||||||
|
Inference::new(assumption.clone()).neg(),
|
||||||
|
SetInference::new(inverse.clone()).neg(),
|
||||||
|
]),
|
||||||
|
// Prevent attacks from the opponent to the selected set
|
||||||
|
// For any assumption `a` and it's inverse `b`:
|
||||||
|
// Inference(b) and SetInference(a) => bottom
|
||||||
|
Clause::from(vec![
|
||||||
|
Inference::new(inverse.clone()).neg(),
|
||||||
|
SetInference::new(assumption.clone()).neg(),
|
||||||
|
]),
|
||||||
|
// Prevent self-attacks
|
||||||
|
// For any assumption `a` and it's inverse `b`:
|
||||||
|
// SetInference(a) and SetInference(b) => bottom
|
||||||
|
Clause::from(vec![
|
||||||
|
SetInference::new(assumption.clone()).neg(),
|
||||||
|
SetInference::new(inverse.clone()).neg(),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect_into(&mut clauses);
|
||||||
|
}
|
||||||
|
|
||||||
|
clauses
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_found_set<A: Atom>(state: SolverState<'_, A>) -> HashSet<A> {
|
||||||
|
state
|
||||||
|
.aba
|
||||||
|
.inverses
|
||||||
|
.keys()
|
||||||
|
.filter_map(|assumption| {
|
||||||
|
let literal = SetInference::new(assumption.clone()).pos();
|
||||||
|
let raw = state.map.get_raw(&literal)?;
|
||||||
|
match state.solver.value(raw) {
|
||||||
|
Some(true) => Some(assumption.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Atom> Problem<A> for Admissibility<A> {
|
||||||
|
type Output = HashSet<A>;
|
||||||
|
|
||||||
|
fn additional_clauses(&self, aba: &Aba<A>) -> ClauseList {
|
||||||
|
let mut clauses = initial_clauses(aba);
|
||||||
|
// Prevent the empty set
|
||||||
|
let no_empty_set: Clause = aba
|
||||||
|
.inverses
|
||||||
|
.keys()
|
||||||
|
.map(|assumption| SetInference::new(assumption.clone()).pos())
|
||||||
|
.collect();
|
||||||
|
clauses.push(no_empty_set);
|
||||||
|
clauses
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_output(self, state: SolverState<'_, A>) -> Self::Output {
|
||||||
|
if state.sat_result {
|
||||||
|
construct_found_set(state)
|
||||||
|
} else {
|
||||||
|
HashSet::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
||||||
type Output = Vec<HashSet<A>>;
|
type Output = Vec<HashSet<A>>;
|
||||||
|
|
||||||
fn additional_clauses(&self, aba: &Aba<A>, iteration: usize) -> ClauseList {
|
fn additional_clauses(&self, aba: &Aba<A>, iteration: usize) -> ClauseList {
|
||||||
match iteration {
|
match iteration {
|
||||||
0 => {
|
0 => {
|
||||||
let mut clauses = vec![];
|
let mut clauses = initial_clauses(aba);
|
||||||
// Create inference for the problem set
|
|
||||||
inference_helper::<SetInference<_>, _>(aba).collect_into(&mut clauses);
|
|
||||||
// Prevent the empty set
|
// Prevent the empty set
|
||||||
let no_empty_set: Clause = aba
|
let no_empty_set: Clause = aba
|
||||||
.inverses
|
.inverses
|
||||||
|
@ -36,50 +116,6 @@ impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
||||||
.map(|assumption| SetInference::new(assumption.clone()).pos())
|
.map(|assumption| SetInference::new(assumption.clone()).pos())
|
||||||
.collect();
|
.collect();
|
||||||
clauses.push(no_empty_set);
|
clauses.push(no_empty_set);
|
||||||
// Attack the inference of the aba, if an attack exists
|
|
||||||
for (assumption, inverse) in &aba.inverses {
|
|
||||||
[
|
|
||||||
// For any assumption `a` and it's inverse `b`:
|
|
||||||
// Inference(a) <=> not SetInference(b) and not SetInference(a)
|
|
||||||
Clause::from(vec![
|
|
||||||
Inference::new(assumption.clone()).neg(),
|
|
||||||
SetInference::new(inverse.clone()).neg(),
|
|
||||||
]),
|
|
||||||
Clause::from(vec![
|
|
||||||
Inference::new(assumption.clone()).neg(),
|
|
||||||
SetInference::new(assumption.clone()).neg(),
|
|
||||||
]),
|
|
||||||
Clause::from(vec![
|
|
||||||
SetInference::new(inverse.clone()).pos(),
|
|
||||||
SetInference::new(assumption.clone()).pos(),
|
|
||||||
Inference::new(assumption.clone()).pos(),
|
|
||||||
]),
|
|
||||||
// Prevent attacks from the opponent to the selected set
|
|
||||||
// For any assumption `a` and it's inverse `b`:
|
|
||||||
// Inference(b) and SetInference(a) => bottom
|
|
||||||
Clause::from(vec![
|
|
||||||
Inference::new(inverse.clone()).neg(),
|
|
||||||
SetInference::new(assumption.clone()).neg(),
|
|
||||||
]),
|
|
||||||
// Prevent self-attacks
|
|
||||||
// For any assumption `a` and it's inverse `b`:
|
|
||||||
// SetInference(a) and SetInference(b) => bottom
|
|
||||||
Clause::from(vec![
|
|
||||||
SetInference::new(assumption.clone()).neg(),
|
|
||||||
SetInference::new(inverse.clone()).neg(),
|
|
||||||
]),
|
|
||||||
// Prevent attacks from the set to the opponent
|
|
||||||
// For any assumption `a` and it's inverse `b`:
|
|
||||||
// Inference(a) and SetInference(b) => bottom
|
|
||||||
Clause::from(vec![
|
|
||||||
Inference::new(assumption.clone()).neg(),
|
|
||||||
SetInference::new(inverse.clone()).neg(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect_into(&mut clauses);
|
|
||||||
}
|
|
||||||
|
|
||||||
clauses
|
clauses
|
||||||
}
|
}
|
||||||
idx => {
|
idx => {
|
||||||
|
@ -103,24 +139,19 @@ impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn feedback(
|
fn feedback(&mut self, state: SolverState<'_, A>) -> LoopControl {
|
||||||
&mut self,
|
if !state.sat_result {
|
||||||
aba: &Aba<A>,
|
|
||||||
sat_result: bool,
|
|
||||||
solver: &cadical::Solver,
|
|
||||||
map: &Mapper,
|
|
||||||
) -> LoopControl {
|
|
||||||
if !sat_result {
|
|
||||||
return LoopControl::Stop;
|
return LoopControl::Stop;
|
||||||
}
|
}
|
||||||
// TODO: Somehow query the mapper about things instead of this
|
// TODO: Somehow query the mapper about things instead of this
|
||||||
let found = aba
|
let found = state
|
||||||
|
.aba
|
||||||
.inverses
|
.inverses
|
||||||
.keys()
|
.keys()
|
||||||
.filter_map(|assumption| {
|
.filter_map(|assumption| {
|
||||||
let literal = SetInference::new(assumption.clone()).pos();
|
let literal = SetInference::new(assumption.clone()).pos();
|
||||||
let raw = map.get_raw(&literal)?;
|
let raw = state.map.get_raw(&literal)?;
|
||||||
match solver.value(raw) {
|
match state.solver.value(raw) {
|
||||||
Some(true) => Some(assumption.clone()),
|
Some(true) => Some(assumption.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -132,9 +163,7 @@ impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
||||||
|
|
||||||
fn construct_output(
|
fn construct_output(
|
||||||
mut self,
|
mut self,
|
||||||
_aba: &Aba<A>,
|
_state: SolverState<'_, A>,
|
||||||
_sat_result: bool,
|
|
||||||
_solver: &cadical::Solver,
|
|
||||||
_total_iterations: usize,
|
_total_iterations: usize,
|
||||||
) -> Self::Output {
|
) -> Self::Output {
|
||||||
// Re-Add the empty set
|
// Re-Add the empty set
|
||||||
|
@ -143,6 +172,33 @@ impl<A: Atom> MultishotProblem<A> for Admissibility<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A: Atom> Problem<A> for VerifyAdmissibility<A> {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn additional_clauses(&self, aba: &Aba<A>) -> crate::clauses::ClauseList {
|
||||||
|
let mut clauses = initial_clauses(aba);
|
||||||
|
// Force inference on all members of the set
|
||||||
|
for assumption in aba.assumptions() {
|
||||||
|
let inf = SetInference::new(assumption.clone());
|
||||||
|
if self.assumptions.contains(assumption) {
|
||||||
|
clauses.push(Clause::from(vec![inf.pos()]))
|
||||||
|
} else {
|
||||||
|
clauses.push(Clause::from(vec![inf.neg()]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clauses
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_output(self, state: SolverState<'_, A>) -> Self::Output {
|
||||||
|
state.sat_result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(&self, aba: &Aba<A>) -> bool {
|
||||||
|
// Make sure that every assumption is part of the ABA
|
||||||
|
self.assumptions.iter().all(|a| aba.contains_assumption(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Atom> InferenceAtom<A> for SetInference<A> {
|
impl<A: Atom> InferenceAtom<A> for SetInference<A> {
|
||||||
type Helper = SetInferenceHelper<A>;
|
type Helper = SetInferenceHelper<A>;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
use cadical::Solver;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
aba::{Aba, Inference, Inverse},
|
aba::{Aba, Inference, Inverse},
|
||||||
clauses::{Clause, ClauseList},
|
clauses::{Clause, ClauseList},
|
||||||
literal::{InferenceAtom, IntoLiteral},
|
literal::{InferenceAtom, IntoLiteral},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Problem;
|
use super::{Problem, SolverState};
|
||||||
|
|
||||||
pub struct ConflictFreeness {
|
pub struct ConflictFreeness {
|
||||||
pub assumptions: Vec<char>,
|
pub assumptions: Vec<char>,
|
||||||
|
@ -44,8 +42,8 @@ impl Problem<char> for ConflictFreeness {
|
||||||
clauses
|
clauses
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_output(self, sat_result: bool, _: &Aba<char>, _: &Solver) -> Self::Output {
|
fn construct_output(self, state: SolverState<'_, char>) -> Self::Output {
|
||||||
sat_result
|
state.sat_result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(&self, aba: &Aba<char>) -> bool {
|
fn check(&self, aba: &Aba<char>) -> bool {
|
||||||
|
|
|
@ -10,7 +10,6 @@ use super::Aba;
|
||||||
|
|
||||||
pub mod admissibility;
|
pub mod admissibility;
|
||||||
pub mod conflict_free;
|
pub mod conflict_free;
|
||||||
pub mod verify_admissibility;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum LoopControl {
|
pub enum LoopControl {
|
||||||
|
@ -18,10 +17,17 @@ pub enum LoopControl {
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SolverState<'a, A: Atom + 'a> {
|
||||||
|
aba: &'a Aba<A>,
|
||||||
|
sat_result: bool,
|
||||||
|
solver: &'a Solver,
|
||||||
|
map: &'a Mapper,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Problem<A: Atom> {
|
pub trait Problem<A: Atom> {
|
||||||
type Output;
|
type Output;
|
||||||
fn additional_clauses(&self, aba: &Aba<A>) -> ClauseList;
|
fn additional_clauses(&self, aba: &Aba<A>) -> ClauseList;
|
||||||
fn construct_output(self, sat_result: bool, aba: &Aba<A>, solver: &Solver) -> Self::Output;
|
fn construct_output(self, state: SolverState<'_, A>) -> Self::Output;
|
||||||
|
|
||||||
fn check(&self, _aba: &Aba<A>) -> bool {
|
fn check(&self, _aba: &Aba<A>) -> bool {
|
||||||
true
|
true
|
||||||
|
@ -31,20 +37,8 @@ pub trait Problem<A: Atom> {
|
||||||
pub trait MultishotProblem<A: Atom> {
|
pub trait MultishotProblem<A: Atom> {
|
||||||
type Output;
|
type Output;
|
||||||
fn additional_clauses(&self, aba: &Aba<A>, iteration: usize) -> ClauseList;
|
fn additional_clauses(&self, aba: &Aba<A>, iteration: usize) -> ClauseList;
|
||||||
fn feedback(
|
fn feedback(&mut self, state: SolverState<'_, A>) -> LoopControl;
|
||||||
&mut self,
|
fn construct_output(self, state: SolverState<'_, A>, total_iterations: usize) -> Self::Output;
|
||||||
aba: &Aba<A>,
|
|
||||||
sat_result: bool,
|
|
||||||
solver: &Solver,
|
|
||||||
map: &Mapper,
|
|
||||||
) -> LoopControl;
|
|
||||||
fn construct_output(
|
|
||||||
self,
|
|
||||||
aba: &Aba<A>,
|
|
||||||
sat_result: bool,
|
|
||||||
solver: &Solver,
|
|
||||||
total_iterations: usize,
|
|
||||||
) -> Self::Output;
|
|
||||||
|
|
||||||
fn check(&self, _aba: &Aba<A>) -> bool {
|
fn check(&self, _aba: &Aba<A>) -> bool {
|
||||||
true
|
true
|
||||||
|
@ -62,7 +56,12 @@ pub fn solve<A: Atom, P: Problem<A>>(problem: P, aba: &Aba<A>) -> Result<P::Outp
|
||||||
map.as_raw_iter(&additional_clauses)
|
map.as_raw_iter(&additional_clauses)
|
||||||
.for_each(|raw| sat.add_clause(raw));
|
.for_each(|raw| sat.add_clause(raw));
|
||||||
if let Some(sat_result) = sat.solve() {
|
if let Some(sat_result) = sat.solve() {
|
||||||
Ok(problem.construct_output(sat_result, aba, &sat))
|
Ok(problem.construct_output(SolverState {
|
||||||
|
aba,
|
||||||
|
sat_result,
|
||||||
|
solver: &sat,
|
||||||
|
map: &map,
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::SatCallInterrupted)
|
Err(Error::SatCallInterrupted)
|
||||||
}
|
}
|
||||||
|
@ -94,11 +93,24 @@ pub fn multishot_solve<A: Atom, P: MultishotProblem<A>>(
|
||||||
let rec = map.reconstruct(&sat).collect::<Vec<_>>();
|
let rec = map.reconstruct(&sat).collect::<Vec<_>>();
|
||||||
eprintln!("{rec:#?}");
|
eprintln!("{rec:#?}");
|
||||||
}
|
}
|
||||||
let control = problem.feedback(aba, sat_result, &sat, &map);
|
let control = problem.feedback(SolverState {
|
||||||
|
aba,
|
||||||
|
sat_result,
|
||||||
|
solver: &sat,
|
||||||
|
map: &map,
|
||||||
|
});
|
||||||
if control == LoopControl::Stop {
|
if control == LoopControl::Stop {
|
||||||
break sat_result;
|
break sat_result;
|
||||||
}
|
}
|
||||||
iteration += 1;
|
iteration += 1;
|
||||||
};
|
};
|
||||||
Ok(problem.construct_output(aba, final_result, &sat, iteration))
|
Ok(problem.construct_output(
|
||||||
|
SolverState {
|
||||||
|
aba,
|
||||||
|
sat_result: final_result,
|
||||||
|
solver: &sat,
|
||||||
|
map: &map,
|
||||||
|
},
|
||||||
|
iteration,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
use crate::{
|
|
||||||
aba::{inference_helper, Aba, Inference, Inverse},
|
|
||||||
clauses::{Atom, Clause},
|
|
||||||
literal::{InferenceAtom, IntoLiteral},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{admissibility::SetInference, Problem};
|
|
||||||
|
|
||||||
pub struct VerifyAdmissibility<A: Atom> {
|
|
||||||
pub assumptions: Vec<A>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Atom> Problem<A> for VerifyAdmissibility<A> {
|
|
||||||
type Output = bool;
|
|
||||||
|
|
||||||
fn additional_clauses(&self, aba: &Aba<A>) -> crate::clauses::ClauseList {
|
|
||||||
let mut clauses = vec![];
|
|
||||||
// Create inference for the problem set
|
|
||||||
inference_helper::<SetInference<_>, _>(aba).collect_into(&mut clauses);
|
|
||||||
// Force inference on all members of the set
|
|
||||||
aba.inverses
|
|
||||||
.keys()
|
|
||||||
.cloned()
|
|
||||||
.map(|assumption| {
|
|
||||||
if self.assumptions.contains(&assumption) {
|
|
||||||
Clause::from(vec![SetInference::new(assumption).pos()])
|
|
||||||
} else {
|
|
||||||
Clause::from(vec![SetInference::new(assumption).neg()])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect_into(&mut clauses);
|
|
||||||
// Attack the inference of the aba, if an attack exists
|
|
||||||
for elem in aba.universe() {
|
|
||||||
for assumption in self.assumptions.iter() {
|
|
||||||
clauses.push(Clause::from(vec![
|
|
||||||
SetInference::new(assumption.clone()).neg(),
|
|
||||||
Inverse {
|
|
||||||
from: assumption.clone(),
|
|
||||||
to: elem.clone(),
|
|
||||||
}
|
|
||||||
.neg(),
|
|
||||||
Inference::new(elem.clone()).neg(),
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
for assumption in aba.assumptions() {
|
|
||||||
clauses.push(Clause::from(vec![
|
|
||||||
SetInference::new(assumption.clone()).neg(),
|
|
||||||
Inverse {
|
|
||||||
from: assumption.clone(),
|
|
||||||
to: elem.clone(),
|
|
||||||
}
|
|
||||||
.neg(),
|
|
||||||
SetInference::new(elem.clone()).neg(),
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clauses
|
|
||||||
}
|
|
||||||
|
|
||||||
fn construct_output(
|
|
||||||
self,
|
|
||||||
sat_result: bool,
|
|
||||||
_: &crate::aba::Aba<A>,
|
|
||||||
_: &cadical::Solver,
|
|
||||||
) -> Self::Output {
|
|
||||||
sat_result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check(&self, aba: &Aba<A>) -> bool {
|
|
||||||
// Make sure that every assumption is part of the ABA
|
|
||||||
self.assumptions.iter().all(|a| aba.contains_assumption(a))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,6 +21,7 @@ pub struct Args {
|
||||||
pub file: PathBuf,
|
pub file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum Problems {
|
pub enum Problems {
|
||||||
#[clap(visible_alias = "ve-ad")]
|
#[clap(visible_alias = "ve-ad")]
|
||||||
|
@ -30,4 +31,7 @@ pub enum Problems {
|
||||||
},
|
},
|
||||||
#[clap(visible_alias = "ee-ad")]
|
#[clap(visible_alias = "ee-ad")]
|
||||||
EnumerateAdmissibility,
|
EnumerateAdmissibility,
|
||||||
|
/// Will only return the empty extension if no other is found
|
||||||
|
#[clap(visible_alias = "se-ad")]
|
||||||
|
SampleAdmissibility,
|
||||||
}
|
}
|
||||||
|
|
34
src/main.rs
34
src/main.rs
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use std::{collections::HashSet, fmt::Write, fs::read_to_string};
|
use std::{collections::HashSet, fmt::Write, fs::read_to_string};
|
||||||
|
|
||||||
use aba::problems::{admissibility::Admissibility, verify_admissibility::VerifyAdmissibility};
|
use aba::problems::admissibility::{Admissibility, VerifyAdmissibility};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
|
@ -35,10 +35,10 @@ mod tests;
|
||||||
fn __main() -> Result {
|
fn __main() -> Result {
|
||||||
let args = args::Args::parse();
|
let args = args::Args::parse();
|
||||||
|
|
||||||
|
let content = read_to_string(&args.file).map_err(Error::OpeningAbaFile)?;
|
||||||
|
let aba = parser::aba_file(&content)?;
|
||||||
match args.problem {
|
match args.problem {
|
||||||
args::Problems::VerifyAdmissibility { set } => {
|
args::Problems::VerifyAdmissibility { set } => {
|
||||||
let content = read_to_string(&args.file).map_err(Error::OpeningAbaFile)?;
|
|
||||||
let aba = parser::aba_file(&content)?;
|
|
||||||
let result = aba::problems::solve(
|
let result = aba::problems::solve(
|
||||||
VerifyAdmissibility {
|
VerifyAdmissibility {
|
||||||
assumptions: set.into_iter().collect(),
|
assumptions: set.into_iter().collect(),
|
||||||
|
@ -48,11 +48,13 @@ fn __main() -> Result {
|
||||||
print_bool_result(result);
|
print_bool_result(result);
|
||||||
}
|
}
|
||||||
args::Problems::EnumerateAdmissibility => {
|
args::Problems::EnumerateAdmissibility => {
|
||||||
let content = read_to_string(&args.file).map_err(Error::OpeningAbaFile)?;
|
|
||||||
let aba = parser::aba_file(&content)?;
|
|
||||||
let result = aba::problems::multishot_solve(Admissibility::default(), &aba)?;
|
let result = aba::problems::multishot_solve(Admissibility::default(), &aba)?;
|
||||||
print_witnesses_result(result)?;
|
print_witnesses_result(result)?;
|
||||||
}
|
}
|
||||||
|
args::Problems::SampleAdmissibility => {
|
||||||
|
let result = aba::problems::solve(Admissibility::default(), &aba)?;
|
||||||
|
print_witness_result(result)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -69,14 +71,16 @@ fn print_bool_result(result: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_witnesses_result(result: Vec<HashSet<u32>>) -> Result {
|
fn print_witnesses_result(result: Vec<HashSet<u32>>) -> Result {
|
||||||
result.into_iter().try_for_each(|set| {
|
result.into_iter().try_for_each(print_witness_result)
|
||||||
let set = set
|
}
|
||||||
.into_iter()
|
|
||||||
.try_fold(String::new(), |mut list, num| -> Result<_, Error> {
|
fn print_witness_result(result: HashSet<u32>) -> Result {
|
||||||
write!(list, " {num}")?;
|
let set = result
|
||||||
Result::Ok(list)
|
.into_iter()
|
||||||
})?;
|
.try_fold(String::new(), |mut list, num| -> Result<_, Error> {
|
||||||
println!("w{set}");
|
write!(list, " {num}")?;
|
||||||
Ok(())
|
Result::Ok(list)
|
||||||
})
|
})?;
|
||||||
|
println!("w{set}");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,25 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::aba::{
|
use crate::aba::{
|
||||||
problems::{
|
problems::{
|
||||||
admissibility::Admissibility, conflict_free::ConflictFreeness,
|
admissibility::{Admissibility, VerifyAdmissibility},
|
||||||
verify_admissibility::VerifyAdmissibility,
|
conflict_free::ConflictFreeness,
|
||||||
},
|
},
|
||||||
Aba,
|
Aba,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
fn simple_aba_example_1() -> Aba<char> {
|
||||||
fn simple_conflict_free_verification() {
|
Aba::new()
|
||||||
let aba = Aba::new()
|
|
||||||
.with_assumption('a', 'r')
|
.with_assumption('a', 'r')
|
||||||
.with_assumption('b', 's')
|
.with_assumption('b', 's')
|
||||||
.with_assumption('c', 't')
|
.with_assumption('c', 't')
|
||||||
.with_rule('p', ['q', 'a'])
|
.with_rule('p', ['q', 'a'])
|
||||||
.with_rule('q', [])
|
.with_rule('q', [])
|
||||||
.with_rule('r', ['b', 'c']);
|
.with_rule('r', ['b', 'c'])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_conflict_free_verification() {
|
||||||
|
let aba = simple_aba_example_1();
|
||||||
let set_checks = vec![
|
let set_checks = vec![
|
||||||
(vec![], true),
|
(vec![], true),
|
||||||
(vec!['a'], true),
|
(vec!['a'], true),
|
||||||
|
@ -40,12 +44,7 @@ fn simple_conflict_free_verification() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_admissible_verification() {
|
fn simple_admissible_verification() {
|
||||||
let aba = Aba::new()
|
let aba = simple_aba_example_1();
|
||||||
.with_assumption('a', 'c')
|
|
||||||
.with_assumption('b', 'd')
|
|
||||||
.with_rule('c', vec!['a'])
|
|
||||||
.with_rule('c', vec!['b'])
|
|
||||||
.with_rule('d', vec!['a']);
|
|
||||||
let set_checks = vec![
|
let set_checks = vec![
|
||||||
(vec![], true),
|
(vec![], true),
|
||||||
(vec!['a', 'b'], false),
|
(vec!['a', 'b'], false),
|
||||||
|
@ -66,25 +65,34 @@ fn simple_admissible_verification() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_admissible_thing() {
|
fn simple_admissible_example() {
|
||||||
let aba = Aba::new()
|
let aba = simple_aba_example_1();
|
||||||
.with_assumption('a', 'r')
|
let expected: Vec<HashSet<char>> = vec![set!(), set!('b'), set!('b', 'c'), set!('c')];
|
||||||
.with_assumption('b', 's')
|
|
||||||
.with_assumption('c', 't')
|
|
||||||
.with_rule('p', vec!['q', 'a'])
|
|
||||||
.with_rule('q', vec![])
|
|
||||||
.with_rule('r', vec!['b', 'c']);
|
|
||||||
let expected: Vec<HashSet<char>> = vec![
|
|
||||||
set!(),
|
|
||||||
set!('a', 'b'),
|
|
||||||
set!('a', 'c'),
|
|
||||||
set!('b'),
|
|
||||||
set!('b', 'c'),
|
|
||||||
set!('c'),
|
|
||||||
];
|
|
||||||
let result = crate::aba::problems::multishot_solve(Admissibility::default(), &aba).unwrap();
|
let result = crate::aba::problems::multishot_solve(Admissibility::default(), &aba).unwrap();
|
||||||
for elem in &expected {
|
for elem in &expected {
|
||||||
assert!(result.contains(elem));
|
assert!(
|
||||||
|
result.contains(elem),
|
||||||
|
"{elem:?} was expected but not found in result"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for elem in &result {
|
||||||
|
assert!(
|
||||||
|
expected.contains(elem),
|
||||||
|
"{elem:?} was found in the result, but is not expected!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_admissible_example_with_defense() {
|
||||||
|
let aba = simple_aba_example_1().with_rule('t', vec!['a', 'b']);
|
||||||
|
let expected: Vec<HashSet<char>> = vec![set!(), set!('a', 'b'), set!('b'), set!('b', 'c')];
|
||||||
|
let result = crate::aba::problems::multishot_solve(Admissibility::default(), &aba).unwrap();
|
||||||
|
for elem in &expected {
|
||||||
|
assert!(
|
||||||
|
result.contains(elem),
|
||||||
|
"{elem:?} was expected but not found in result"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for elem in &result {
|
for elem in &result {
|
||||||
assert!(
|
assert!(
|
||||||
|
|
Loading…
Reference in a new issue