mirror of
https://github.com/ellmau/adf-obdd.git
synced 2025-12-19 09:29:36 +01:00
Implement non-deprecated cli with structopts and adf-state-safer (#14)
Rework of the CLI methods. Added import/export functionality for ADFs in BDD representation (via JSON serialisation)
This commit is contained in:
parent
07d15167fe
commit
bfd0aa4a68
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -4,7 +4,7 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adf_bdd"
|
name = "adf_bdd"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
@ -18,6 +18,7 @@ dependencies = [
|
|||||||
"quickcheck_macros",
|
"quickcheck_macros",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"structopt",
|
||||||
"test-log",
|
"test-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -229,6 +230,15 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@ -387,6 +397,30 @@ dependencies = [
|
|||||||
"termtree",
|
"termtree",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.32"
|
||||||
@ -560,6 +594,30 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"lazy_static",
|
||||||
|
"structopt-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt-derive"
|
||||||
|
version = "0.4.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.81"
|
version = "1.0.81"
|
||||||
@ -629,6 +687,12 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
|||||||
@ -15,6 +15,7 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.*"
|
clap = "2.33.*"
|
||||||
|
structopt = "0.3.25"
|
||||||
log = { version = "0.4", features = [ "max_level_trace", "release_max_level_info" ] }
|
log = { version = "0.4", features = [ "max_level_trace", "release_max_level_info" ] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
nom = "7.1.0"
|
nom = "7.1.0"
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
|
|||||||
|
|
||||||
use super::{Term, Var};
|
use super::{Term, Var};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize,Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub(crate) struct VarContainer {
|
pub(crate) struct VarContainer {
|
||||||
names: Rc<RefCell<Vec<String>>>,
|
names: Rc<RefCell<Vec<String>>>,
|
||||||
mapping: Rc<RefCell<HashMap<String, usize>>>,
|
mapping: Rc<RefCell<HashMap<String, usize>>>,
|
||||||
|
|||||||
179
src/main.rs
179
src/main.rs
@ -3,88 +3,121 @@ pub mod datatypes;
|
|||||||
pub mod obdd;
|
pub mod obdd;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::{fs::File, path::PathBuf};
|
||||||
|
|
||||||
use adf::Adf;
|
use adf::Adf;
|
||||||
|
|
||||||
use clap::{clap_app, crate_authors, crate_description, crate_name, crate_version};
|
use clap::{crate_authors, crate_description, crate_name, crate_version};
|
||||||
use parser::AdfParser;
|
use parser::AdfParser;
|
||||||
|
|
||||||
fn main() {
|
use structopt::StructOpt;
|
||||||
let matches = clap_app!(myapp =>
|
|
||||||
(version: crate_version!())
|
#[derive(StructOpt, Debug)]
|
||||||
(author: crate_authors!())
|
#[structopt(name = crate_name!(), about = crate_description!(), author = crate_authors!(), version = crate_version!())]
|
||||||
(name: crate_name!())
|
struct App {
|
||||||
(about: crate_description!())
|
/// Input filename
|
||||||
//(@arg fast: -f --fast "fast algorithm instead of the direct fixpoint-computation")
|
#[structopt(parse(from_os_str))]
|
||||||
(@arg verbose: -v +multiple "Sets log verbosity")
|
input: PathBuf,
|
||||||
(@arg INPUT: +required "Input file")
|
/// Sets the verbosity to 'warn', 'info', 'debug' or 'trace' if -v and -q are not use
|
||||||
(@group sorting =>
|
#[structopt(long = "rust_log", env)]
|
||||||
(@arg sort_lex: --lx "Sorts variables in a lexicographic manner")
|
rust_log: Option<String>,
|
||||||
(@arg sort_alphan: --an "Sorts variables in an alphanumeric manner")
|
/// Sets log verbosity (multiple times means more verbose)
|
||||||
)
|
#[structopt(short, parse(from_occurrences), group = "verbosity")]
|
||||||
(@arg grounded: --grd "Compute the grounded model")
|
verbose: u8,
|
||||||
(@arg stable: --stm "Compute the stable models")
|
/// Sets log verbosity to only errors
|
||||||
)
|
#[structopt(short, group = "verbosity")]
|
||||||
.get_matches_safe()
|
quiet: bool,
|
||||||
.unwrap_or_else(|e| match e.kind {
|
/// Sorts variables in an lexicographic manner
|
||||||
clap::ErrorKind::HelpDisplayed => {
|
#[structopt(long = "lx", group = "sorting")]
|
||||||
e.exit();
|
sort_lex: bool,
|
||||||
}
|
/// Sorts variables in an alphanumeric manner
|
||||||
clap::ErrorKind::VersionDisplayed => {
|
#[structopt(long = "an", group = "sorting")]
|
||||||
e.exit();
|
sort_alphan: bool,
|
||||||
}
|
/// Compute the grounded model
|
||||||
_ => {
|
#[structopt(long = "grd")]
|
||||||
eprintln!("{} Version {{{}}}", crate_name!(), crate_version!());
|
grounded: bool,
|
||||||
e.exit();
|
/// Compute the stable models
|
||||||
}
|
#[structopt(long = "stm")]
|
||||||
});
|
stable: bool,
|
||||||
let filter_level = match matches.occurrences_of("verbose") {
|
/// Import an adf- bdd state instead of an adf
|
||||||
1 => log::LevelFilter::Info,
|
#[structopt(long)]
|
||||||
2 => log::LevelFilter::Debug,
|
import: bool,
|
||||||
3 => log::LevelFilter::Trace,
|
/// Export the adf-bdd state after parsing and BDD instantiation to the given filename
|
||||||
_ => {
|
#[structopt(long)]
|
||||||
match std::env::vars().find_map(|(var, val)| {
|
export: Option<PathBuf>,
|
||||||
if var.eq("RUST_LOG") {
|
}
|
||||||
Some(log::LevelFilter::from_str(val.as_str()))
|
|
||||||
|
impl App {
|
||||||
|
fn run(&self) {
|
||||||
|
let filter_level = match self.verbose {
|
||||||
|
1 => log::LevelFilter::Info,
|
||||||
|
2 => log::LevelFilter::Debug,
|
||||||
|
3 => log::LevelFilter::Trace,
|
||||||
|
_ => {
|
||||||
|
if self.quiet {
|
||||||
|
log::LevelFilter::Error
|
||||||
|
} else if let Some(rust_log) = self.rust_log.clone() {
|
||||||
|
match rust_log.as_str() {
|
||||||
|
"error" => log::LevelFilter::Error,
|
||||||
|
"info" => log::LevelFilter::Info,
|
||||||
|
"debug" => log::LevelFilter::Debug,
|
||||||
|
"trace" => log::LevelFilter::Trace,
|
||||||
|
_ => log::LevelFilter::Warn,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
log::LevelFilter::Warn
|
||||||
}
|
}
|
||||||
}) {
|
}
|
||||||
Some(v) => v.unwrap_or(log::LevelFilter::Error),
|
};
|
||||||
None => log::LevelFilter::Error,
|
env_logger::builder().filter_level(filter_level).init();
|
||||||
|
log::info!("Version: {}", crate_version!());
|
||||||
|
let input = std::fs::read_to_string(self.input.clone()).expect("Error Reading File");
|
||||||
|
let mut adf = if self.import {
|
||||||
|
serde_json::from_str(&input).unwrap()
|
||||||
|
} else {
|
||||||
|
let parser = AdfParser::default();
|
||||||
|
parser.parse()(&input).unwrap();
|
||||||
|
log::info!("[Done] parsing");
|
||||||
|
if self.sort_lex {
|
||||||
|
parser.varsort_lexi();
|
||||||
|
}
|
||||||
|
if self.sort_alphan {
|
||||||
|
parser.varsort_alphanum();
|
||||||
|
}
|
||||||
|
Adf::from_parser(&parser)
|
||||||
|
};
|
||||||
|
if let Some(export) = &self.export {
|
||||||
|
if export.exists() {
|
||||||
|
log::error!(
|
||||||
|
"Cannot write JSON file <{}>, as it already exists",
|
||||||
|
export.to_string_lossy()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let export_file = match File::create(&export) {
|
||||||
|
Err(reason) => {
|
||||||
|
panic!("couldn't create {}: {}", export.to_string_lossy(), reason)
|
||||||
|
}
|
||||||
|
Ok(file) => file,
|
||||||
|
};
|
||||||
|
serde_json::to_writer(export_file, &adf).unwrap_or_else(|_| {
|
||||||
|
panic!("Writing JSON file {} failed", export.to_string_lossy())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
if self.grounded {
|
||||||
env_logger::builder().filter_level(filter_level).init();
|
let grounded = adf.grounded();
|
||||||
log::info!("Version: {}", crate_version!());
|
println!("{}", adf.print_interpretation(&grounded));
|
||||||
|
}
|
||||||
let input = std::fs::read_to_string(
|
if self.stable {
|
||||||
matches
|
let stable = adf.stable(0);
|
||||||
.value_of("INPUT")
|
for model in stable {
|
||||||
.expect("Input Filename should be given"),
|
println!("{}", adf.print_interpretation(&model));
|
||||||
)
|
}
|
||||||
.expect("Error Reading File");
|
|
||||||
let parser = AdfParser::default();
|
|
||||||
parser.parse()(&input).unwrap();
|
|
||||||
log::info!("[Done] parsing");
|
|
||||||
|
|
||||||
if matches.is_present("sort_lex") {
|
|
||||||
parser.varsort_lexi();
|
|
||||||
}
|
|
||||||
if matches.is_present("sort_alphan") {
|
|
||||||
parser.varsort_alphanum();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut adf = Adf::from_parser(&parser);
|
|
||||||
if matches.is_present("grounded") {
|
|
||||||
let grounded = adf.grounded();
|
|
||||||
println!("{}", adf.print_interpretation(&grounded));
|
|
||||||
}
|
|
||||||
if matches.is_present("stable") {
|
|
||||||
let stable = adf.stable(1);
|
|
||||||
for model in stable {
|
|
||||||
println!("{}", adf.print_interpretation(&model));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = App::from_args();
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|||||||
64
tests/cli.rs
64
tests/cli.rs
@ -51,6 +51,12 @@ fn runs() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
"u(7) F(4) u(8) u(3) F(5) u(9) u(10) u(1) u(6) u(2)",
|
"u(7) F(4) u(8) u(3) F(5) u(9) u(10) u(1) u(6) u(2)",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(file.path()).arg("-q").arg("--grd");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(7) F(4) u(8) u(3) F(5) u(9) u(10) u(1) u(6) u(2)",
|
||||||
|
));
|
||||||
|
|
||||||
cmd = Command::cargo_bin("adf_bdd")?;
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
cmd.arg(file.path()).arg("--lx").arg("-v").arg("--grd");
|
cmd.arg(file.path()).arg("--lx").arg("-v").arg("--grd");
|
||||||
cmd.assert().success().stdout(predicate::str::contains(
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
@ -62,5 +68,63 @@ fn runs() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
cmd.assert().success().stdout(predicate::str::contains(
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.env_clear();
|
||||||
|
cmd.arg(file.path()).arg("--an").arg("--grd");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(file.path())
|
||||||
|
.arg("--an")
|
||||||
|
.arg("--grd")
|
||||||
|
.arg("--rust_log")
|
||||||
|
.arg("trace");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(file.path())
|
||||||
|
.arg("--an")
|
||||||
|
.arg("--grd")
|
||||||
|
.arg("--rust_log")
|
||||||
|
.arg("warn");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
|
|
||||||
|
let tempdir = assert_fs::TempDir::new()?;
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(file.path())
|
||||||
|
.arg("--an")
|
||||||
|
.arg("--grd")
|
||||||
|
.arg("--export")
|
||||||
|
.arg(tempdir.path().with_file_name("test.json"));
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(file.path())
|
||||||
|
.arg("--an")
|
||||||
|
.arg("--grd")
|
||||||
|
.arg("--export")
|
||||||
|
.arg(tempdir.path().with_file_name("test.json"));
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
|
|
||||||
|
cmd = Command::cargo_bin("adf_bdd")?;
|
||||||
|
cmd.arg(tempdir.path().with_file_name("test.json"))
|
||||||
|
.arg("--an")
|
||||||
|
.arg("--grd")
|
||||||
|
.arg("--import");
|
||||||
|
cmd.assert().success().stdout(predicate::str::contains(
|
||||||
|
"u(1) u(2) u(3) F(4) F(5) u(6) u(7) u(8) u(9) u(10) \n\n",
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user