diff --git a/lib/src/adf.rs b/lib/src/adf.rs index aae8967..d7dcb04 100644 --- a/lib/src/adf.rs +++ b/lib/src/adf.rs @@ -8,7 +8,6 @@ This module describes the abstract dialectical framework. pub mod heuristics; use std::cell::RefCell; -use crate::datatypes::BddNode; use crate::{ datatypes::{ adf::{ @@ -52,23 +51,18 @@ impl Default for Adf { } } -impl Adf { - /// Instntiates an ADF based on the publically available data - pub fn from_ord_nodes_and_ac( - ordering: VarContainer, - bdd_nodes: Vec, - ac: Vec, - ) -> Self { - let bdd = Bdd::from_nodes(bdd_nodes); - - Adf { - ordering, - bdd, - ac, +impl From<(VarContainer, Bdd, Vec)> for Adf { + fn from(source: (VarContainer, Bdd, Vec)) -> Self { + Self { + ordering: source.0, + bdd: source.1, + ac: source.2, rng: Self::default_rng(), } } +} +impl Adf { /// Instantiates a new ADF, based on the [parser-data][crate::parser::AdfParser]. pub fn from_parser(parser: &AdfParser) -> Self { log::info!("[Start] instantiating BDD"); diff --git a/lib/src/datatypes/adf.rs b/lib/src/datatypes/adf.rs index 0940704..52bcc83 100644 --- a/lib/src/datatypes/adf.rs +++ b/lib/src/datatypes/adf.rs @@ -26,7 +26,7 @@ impl Default for VarContainer { } impl VarContainer { - /// Create [VarContainer] from its components + /// Create [`VarContainer`] from its components pub fn from_parser( names: Arc>>, mapping: Arc>>, @@ -52,12 +52,12 @@ impl VarContainer { .and_then(|name| name.get(var.value()).cloned()) } - /// Return ordered names from [VarContainer] + /// Return ordered names from [`VarContainer`] pub fn names(&self) -> Arc>> { Arc::clone(&self.names) } - /// Return map from names to indices in [VarContainer] + /// Return map from names to indices in [`VarContainer`] pub fn mappings(&self) -> Arc>> { Arc::clone(&self.mapping) } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 3709699..b1d4a93 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -198,6 +198,146 @@ while let Ok(result) = r.recv() { solving.join().unwrap(); ``` + +### Serialize and Deserialize custom datastructures representing an [`adf::Adf`] + +The Web Application uses custom datastructures that are stored in a mongodb which inspired this example. + +```rust +use std::sync::{Arc, RwLock}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use adf_bdd::datatypes::adf::VarContainer; +use adf_bdd::datatypes::{BddNode, Term, Var}; +use adf_bdd::obdd::Bdd; +use adf_bdd::parser::AdfParser; +use adf_bdd::adf::Adf; + +// Custom Datastructures for (De-)Serialization + +# #[derive(PartialEq, Debug)] +#[derive(Deserialize, Serialize)] +struct MyCustomVarContainer { + names: Vec, + mapping: HashMap, +} + +impl From for MyCustomVarContainer { + fn from(source: VarContainer) -> Self { + Self { + names: source.names().read().unwrap().clone(), + mapping: source + .mappings() + .read() + .unwrap() + .iter() + .map(|(k, v)| (k.clone(), v.to_string())) + .collect(), + } + } +} + +impl From for VarContainer { + fn from(source: MyCustomVarContainer) -> Self { + Self::from_parser( + Arc::new(RwLock::new(source.names)), + Arc::new(RwLock::new( + source + .mapping + .into_iter() + .map(|(k, v)| (k, v.parse().unwrap())) + .collect(), + )), + ) + } +} + +# #[derive(PartialEq, Debug)] +#[derive(Deserialize, Serialize)] +struct MyCustomBddNode { + var: String, + lo: String, + hi: String, +} + +impl From for MyCustomBddNode { + fn from(source: BddNode) -> Self { + Self { + var: source.var().0.to_string(), + lo: source.lo().0.to_string(), + hi: source.hi().0.to_string(), + } + } +} + +impl From for BddNode { + fn from(source: MyCustomBddNode) -> Self { + Self::new( + Var(source.var.parse().unwrap()), + Term(source.lo.parse().unwrap()), + Term(source.hi.parse().unwrap()), + ) + } +} + +# #[derive(PartialEq, Debug)] +#[derive(Deserialize, Serialize)] +struct MyCustomAdf { + ordering: MyCustomVarContainer, + bdd: Vec, + ac: Vec, +} + +impl From for MyCustomAdf { + fn from(source: Adf) -> Self { + Self { + ordering: source.ordering.into(), + bdd: source.bdd.nodes.into_iter().map(Into::into).collect(), + ac: source.ac.into_iter().map(|t| t.0.to_string()).collect(), + } + } +} + +impl From for Adf { + fn from(source: MyCustomAdf) -> Self { + let bdd = Bdd::from(source.bdd.into_iter().map(Into::into).collect::>()); + + Adf::from(( + source.ordering.into(), + bdd, + source + .ac + .into_iter() + .map(|t| Term(t.parse().unwrap())) + .collect(), + )) + } +} + +// use the above example as input +let input = "s(a).s(b).s(c).s(d).ac(a,c(v)).ac(b,or(a,b)).ac(c,neg(b)).ac(d,d)."; +let parser = AdfParser::default(); +parser.parse()(&input).unwrap(); + +// create Adf +let adf = Adf::from_parser(&parser); + +// cast into custom struct +let my_custom_adf: MyCustomAdf = adf.into(); + +// stringify to json +let json: String = serde_json::to_string(&my_custom_adf).unwrap(); + +// parse json +let parsed_custom_adf: MyCustomAdf = serde_json::from_str(&json).unwrap(); + +// cast into lib struct that resembles the original Adf +let parsed_adf: Adf = parsed_custom_adf.into(); + +# let my_custom_adf2: MyCustomAdf = parsed_adf.into(); +# assert_eq!(my_custom_adf, my_custom_adf2); +``` + */ #![deny( missing_debug_implementations, diff --git a/lib/src/nogoods.rs b/lib/src/nogoods.rs index de25bbe..1f39edc 100644 --- a/lib/src/nogoods.rs +++ b/lib/src/nogoods.rs @@ -82,7 +82,7 @@ impl NoGood { visit.then_some(result) } - /// Creates an updated [Vec], based on the given [&[Term]] and the [NoGood]. + /// Creates an updated [`Vec`], based on the given [&[Term]] and the [NoGood]. /// The parameter _update_ is set to [`true`] if there has been an update and to [`false`] otherwise pub fn update_term_vec(&self, term_vec: &[Term], update: &mut bool) -> Vec { *update = false; diff --git a/lib/src/obdd.rs b/lib/src/obdd.rs index a5aae9d..a19fa96 100644 --- a/lib/src/obdd.rs +++ b/lib/src/obdd.rs @@ -13,7 +13,7 @@ use std::{cell::RefCell, cmp::min, collections::HashMap, fmt::Display}; /// Each roBDD is identified by its corresponding [`Term`], which implicitly identifies the root node of a roBDD. #[derive(Debug, Serialize, Deserialize)] pub struct Bdd { - /// The nodes of the [Bdd] with their edges + /// The nodes of the [`Bdd`] with their edges pub nodes: Vec, #[cfg(feature = "variablelist")] #[serde(skip)] @@ -50,6 +50,18 @@ impl Default for Bdd { } } +impl From> for Bdd { + fn from(nodes: Vec) -> Self { + let mut bdd = Self::new(); + + for node in nodes { + bdd.node(node.var(), node.lo(), node.hi()); + } + + bdd + } +} + impl Bdd { /// Instantiate a new roBDD structure. /// Constants for the [`⊤`][crate::datatypes::Term::TOP] and [`⊥`][crate::datatypes::Term::BOT] concepts are prepared in that step too. @@ -101,17 +113,6 @@ impl Bdd { RefCell::new(HashMap::new()) } - /// Construct [Bdd] from a list of nodes by adding one after the other - pub fn from_nodes(nodes: Vec) -> Self { - let mut bdd = Self::new(); - - for node in nodes { - bdd.node(node.var(), node.lo(), node.hi()); - } - - bdd - } - /// Instantiates a [variable][crate::datatypes::Var] and returns the representing roBDD as a [`Term`][crate::datatypes::Term]. pub fn variable(&mut self, var: Var) -> Term { self.node(var, Term::BOT, Term::TOP) diff --git a/server/src/adf.rs b/server/src/adf.rs index 31858b6..c085f32 100644 --- a/server/src/adf.rs +++ b/server/src/adf.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; use adf_bdd::adf::Adf; use adf_bdd::adfbiodivine::Adf as BdAdf; +use adf_bdd::obdd::Bdd; use adf_bdd::parser::AdfParser; use crate::config::{AppState, RunningInfo, Task, ADF_COLL, COMPUTE_TIME, DB_NAME, USER_COLL}; @@ -164,16 +165,38 @@ pub(crate) struct SimplifiedAdf { pub(crate) ac: AcDb, } -impl SimplifiedAdf { - fn from_lib_adf(adf: Adf) -> Self { - SimplifiedAdf { - ordering: adf.ordering.into(), - bdd: adf.bdd.nodes.into_iter().map(Into::into).collect(), - ac: adf.ac.into_iter().map(|t| t.0.to_string()).collect(), +impl From for SimplifiedAdf { + fn from(source: Adf) -> Self { + Self { + ordering: source.ordering.into(), + bdd: source.bdd.nodes.into_iter().map(Into::into).collect(), + ac: source.ac.into_iter().map(|t| t.0.to_string()).collect(), } } } +impl From for Adf { + fn from(source: SimplifiedAdf) -> Self { + let bdd = Bdd::from( + source + .bdd + .into_iter() + .map(Into::into) + .collect::>(), + ); + + Adf::from(( + source.ordering.into(), + bdd, + source + .ac + .into_iter() + .map(|t| Term(t.parse().unwrap())) + .collect(), + )) + } +} + type SimplifiedAdfOpt = OptionWithError; #[derive(Deserialize, Serialize)] @@ -408,7 +431,7 @@ async fn add_adf_problem( graph: DoubleLabeledGraph::from_adf_and_ac(&lib_adf, None), }; - (SimplifiedAdf::from_lib_adf(lib_adf), ac_and_graph) + (SimplifiedAdf::from(lib_adf), ac_and_graph) }); app_state @@ -550,15 +573,7 @@ async fn solve_adf_problem( #[cfg(feature = "mock_long_computations")] std::thread::sleep(Duration::from_secs(20)); - let mut adf: Adf = Adf::from_ord_nodes_and_ac( - simp_adf.ordering.into(), - simp_adf.bdd.into_iter().map(Into::into).collect(), - simp_adf - .ac - .into_iter() - .map(|t| Term(t.parse().unwrap())) - .collect(), - ); + let mut adf: Adf = simp_adf.into(); let acs: Vec = match adf_problem_input.strategy { Strategy::Complete => adf.complete().collect(),