Skip to content

Commit

Permalink
refactor: unify input/output files
Browse files Browse the repository at this point in the history
  • Loading branch information
uulm-janbaudisch committed Aug 27, 2024
1 parent 6f0246d commit 6b0a1c9
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 400 deletions.
82 changes: 82 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ resolver = "2"

[workspace.dependencies]
clap = { version = "4.5", features = ["derive"] }
csv = "1.3"
ddnnife = { path = "ddnnife" }
log = "0.4"
mimalloc = "0.1"
uniffi = { version = "0.28" }

Expand Down
3 changes: 2 additions & 1 deletion ddnnife/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ crate-type = ["lib", "cdylib"]

[dependencies]
bitvec = "1.0"
csv = "1.3"
csv = { workspace = true }
file_diff = "1.0.0"
itertools = "0.13"
log = { workspace = true }
nom = "7.1"
num = "0.4"
once_cell = "1.19"
Expand Down
15 changes: 4 additions & 11 deletions ddnnife/src/ddnnf/anomalies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,23 @@ pub mod false_optional;
pub mod sat;
pub mod t_wise_sampling;

use std::{
fs::File,
io::{LineWriter, Write},
};

use crate::Ddnnf;
use std::io::Write;

impl Ddnnf {
/// Takes a d-DNNF and writes the string representation into a file with the provided name
pub fn write_anomalies(&mut self, path_out: &str) -> std::io::Result<()> {
let file = File::create(path_out)?;
let mut file = LineWriter::with_capacity(1000, file);

pub fn write_anomalies(&mut self, mut output: impl Write) -> std::io::Result<()> {
// core/dead features
let mut core = self.core.clone().into_iter().collect::<Vec<i32>>();
core.sort();
file.write_all(format!("core: {core:?}\n").as_bytes())?;
output.write_all(format!("core: {core:?}\n").as_bytes())?;

// false-optionals

// atomic sets
let mut atomic_sets = self.get_atomic_sets(None, &[], false);
atomic_sets.sort_unstable();
file.write_all(format!("atomic sets: {atomic_sets:?}\n").as_bytes())?;
output.write_all(format!("atomic sets: {atomic_sets:?}\n").as_bytes())?;

Ok(())
}
Expand Down
32 changes: 1 addition & 31 deletions ddnnife/src/ddnnf/anomalies/t_wise_sampling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ mod sat_wrapper;
mod t_iterator;
mod t_wise_sampler;

use crate::util::format_vec;
use crate::Ddnnf;
pub use config::Config;
pub use sample::Sample;
use sample_merger::similarity_merger::SimilarityMerger;
use sample_merger::zipping_merger::ZippingMerger;
use sampling_result::SamplingResult;
pub use sampling_result::SamplingResult;
use sat_wrapper::SatWrapper;
use std::path::Path;
use std::{fs, io, iter};
use t_wise_sampler::TWiseSampler;

#[cfg_attr(feature = "uniffi", uniffi::export)]
Expand All @@ -37,33 +34,6 @@ impl Ddnnf {
}
}

pub fn save_sample_to_file(sampling_result: &SamplingResult, file_path: &str) -> io::Result<()> {
let file_path = Path::new(file_path);
if let Some(dir) = file_path.parent() {
fs::create_dir_all(dir)?;
}
let mut wtr = csv::Writer::from_path(file_path)?;

match sampling_result {
/*
Writing "true" and "false" to the file does not really fit the format of the file but we
want to somehow distinguish between true and false sampling results.
True means that the feature model contains no variables and therefore an empty sample
covers all t-wise interactions.
False means that the feature model is void.
*/
SamplingResult::Empty => wtr.write_record(iter::once("true"))?,
SamplingResult::Void => wtr.write_record(iter::once("false"))?,
SamplingResult::ResultWithSample(sample) => {
for (index, config) in sample.iter().enumerate() {
wtr.write_record([index.to_string(), format_vec(config.get_literals().iter())])?;
}
}
}

wtr.flush()
}

#[cfg(test)]
mod test {
use itertools::Itertools;
Expand Down
56 changes: 35 additions & 21 deletions ddnnife/src/ddnnf/counting/features.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
use num::{BigRational, ToPrimitive};
use std::error::Error;

use super::super::Ddnnf;
use num::{BigInt, BigRational, ToPrimitive};
use std::error::Error;

impl Ddnnf {
pub fn card_of_each_feature(&mut self) -> impl Iterator<Item = (i32, BigInt, f64)> + '_ {
self.annotate_partial_derivatives();
let rc = self.rc();
(1_i32..self.number_of_variables as i32 + 1).map(move |variable| {
let cardinality = self.card_of_feature_with_partial_derivatives(variable);
let ratio = BigRational::from((cardinality.clone(), rc.clone()))
.to_f64()
.unwrap();
(variable, cardinality, ratio)
})
}

#[inline]
/// Computes the cardinality of features for all features in a model.
/// The results are saved in the file_path. The .csv ending always gets added to the user input.
Expand All @@ -18,30 +29,29 @@ impl Ddnnf {
/// // create a ddnnf
/// // and run the queries
/// let mut ddnnf: Ddnnf = build_ddnnf("./tests/data/small_ex_c2d.nnf", None);
/// ddnnf.card_of_each_feature("./tests/data/smt_out.csv")
/// ddnnf.card_of_each_feature_csv("./tests/data/smt_out.csv")
/// .unwrap_or_default();
/// let _rm = fs::remove_file("./tests/data/smt_out.csv");
///
/// ```
pub fn card_of_each_feature(&mut self, file_path: &str) -> Result<(), Box<dyn Error>> {
pub fn card_of_each_feature_csv(&mut self, file_path: &str) -> Result<(), Box<dyn Error>> {
self.annotate_partial_derivatives();

// start the csv writer with the file_path
let mut wtr = csv::Writer::from_path(file_path)?;

for work in 1_i32..self.number_of_variables as i32 + 1 {
let cardinality = self.card_of_feature_with_partial_derivatives(work);
wtr.write_record(vec![
work.to_string(),
cardinality.to_string(),
format!(
"{:.10e}",
BigRational::from((cardinality, self.rc()))
.to_f64()
.expect("Failed to convert rational!")
),
])?;
}
self.card_of_each_feature()
.for_each(|(variable, cardinality, ratio)| {
wtr.write_record(vec![
variable.to_string(),
cardinality.to_string(),
format!(
"{:.10e}",
ratio.to_f64().expect("Failed to convert rational!")
),
])
.unwrap();
});

Ok(())
}
Expand All @@ -61,10 +71,14 @@ mod test {
fn card_multi_queries() {
let mut ddnnf: Ddnnf = build_ddnnf("./tests/data/VP9_d4.nnf", Some(42));
ddnnf.max_worker = 1;
ddnnf.card_of_each_feature("./tests/data/fcs.csv").unwrap();
ddnnf
.card_of_each_feature_csv("./tests/data/fcs.csv")
.unwrap();

ddnnf.max_worker = 4;
ddnnf.card_of_each_feature("./tests/data/fcm.csv").unwrap();
ddnnf
.card_of_each_feature_csv("./tests/data/fcm.csv")
.unwrap();

let mut is_single = File::open("./tests/data/fcs.csv").unwrap();
let mut is_multi = File::open("./tests/data/fcm.csv").unwrap();
Expand Down Expand Up @@ -93,7 +107,7 @@ mod test {

let mut ddnnf: Ddnnf = build_ddnnf("./tests/data/VP9_d4.nnf", Some(42));
ddnnf.max_worker = 1;
ddnnf.card_of_each_feature(PD_FILE).unwrap();
ddnnf.card_of_each_feature_csv(PD_FILE).unwrap();

let mut pd: File = File::open(PD_FILE).unwrap();
let mut should_be = File::open(SHOULD_FILE).unwrap();
Expand Down
7 changes: 4 additions & 3 deletions ddnnife/src/ddnnf/heuristics.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{node::NodeType::*, Ddnnf};
use crate::Node;
use log::info;

impl Ddnnf {
/// Computes and prints some heuristics including:
Expand Down Expand Up @@ -31,7 +32,7 @@ impl Ddnnf {
}

let node_count: u64 = self.nodes.len() as u64;
println!(
info!(
"\nThe d-DNNF consists out of the following node types:\n\
\t |-> {:?} out of {:?} are And nodes (≈{:.2}% of total)\n\
\t |-> {:?} out of {:?} are Or nodes (≈{:.2}% of total)\n\
Expand Down Expand Up @@ -83,7 +84,7 @@ impl Ddnnf {
}

let node_count: u64 = self.nodes.len() as u64;
println!(
info!(
"\nThe d-DNNF has the following information regarding node count:\n\
\t |-> The overall count of child connections is {:?}\n\
\t |-> The overall node count is {:?}.\n\
Expand Down Expand Up @@ -130,7 +131,7 @@ impl Ddnnf {

let s_x: f64 = (derivation / length as f64).sqrt();

println!("\nThe d-DNNF has the following length attributes:\n\
info!("\nThe d-DNNF has the following length attributes:\n\
\t |-> The shortest path is {:?} units long\n\
\t |-> The longest path is {:?} units long\n\
\t |-> The mean path is ≈{:.2} units long\n\
Expand Down
Loading

0 comments on commit 6b0a1c9

Please sign in to comment.