Skip to content

Commit

Permalink
feat(cli): add heuristics command
Browse files Browse the repository at this point in the history
  • Loading branch information
uulm-janbaudisch committed Jan 26, 2025
1 parent 02d5695 commit f133cb2
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 46 deletions.
85 changes: 46 additions & 39 deletions ddnnife/src/ddnnf/heuristics.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use super::{node::NodeType::*, Ddnnf};
use crate::Node;
use log::info;
use std::io::Write;

impl Ddnnf {
/// Computes and prints some heuristics including:
/// 1) The distribution of the different types of nodes
/// 2) The number of child nodes (averages, ...)
/// 3) The length of paths starting from the root to the leafs (averages, ...)
pub fn print_all_heuristics(&mut self) {
self.get_nodetype_numbers();
self.get_child_number();
self.get_depths()
pub fn write_heuristics(&mut self, mut output: impl Write) -> std::io::Result<()> {
self.write_nodetype_numbers(&mut output)?;
self.write_child_number(&mut output)?;
self.get_depths(output)
}

// computes the occurences of different node types (number of and nodes, or, positive literal, negative literal, true, false)
fn get_nodetype_numbers(&mut self) {
fn write_nodetype_numbers(&mut self, mut output: impl Write) -> std::io::Result<()> {
let mut and_counter = 0;
let mut or_counter = 0;
let mut literal_counter = 0;
Expand All @@ -32,33 +32,36 @@ impl Ddnnf {
}

let node_count: u64 = self.nodes.len() as u64;
info!(
"\nThe d-DNNF consists out of the following node types:\n\
output.write_all(
format!(
"The 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\
\t |-> {:?} out of {:?} are Literal nodes (≈{:.2}% of total)\n\
\t |-> {:?} out of {:?} are True nodes (≈{:.2}% of total)\n\
\t |-> {:?} out of {:?} are False nodes (≈{:.2}% of total)\n",
and_counter,
node_count,
(f64::from(and_counter) / node_count as f64) * 100_f64,
or_counter,
node_count,
(f64::from(or_counter) / node_count as f64) * 100_f64,
literal_counter,
node_count,
(f64::from(literal_counter) / node_count as f64) * 100_f64,
true_counter,
node_count,
(f64::from(true_counter) / node_count as f64) * 100_f64,
false_counter,
node_count,
(f64::from(false_counter) / node_count as f64) * 100_f64
);
and_counter,
node_count,
(f64::from(and_counter) / node_count as f64) * 100_f64,
or_counter,
node_count,
(f64::from(or_counter) / node_count as f64) * 100_f64,
literal_counter,
node_count,
(f64::from(literal_counter) / node_count as f64) * 100_f64,
true_counter,
node_count,
(f64::from(true_counter) / node_count as f64) * 100_f64,
false_counter,
node_count,
(f64::from(false_counter) / node_count as f64) * 100_f64
)
.as_bytes(),
)
}

// computes the number of childs for the differnt nodes (count of total nodes, childs relativ to number of nodes)
fn get_child_number(&mut self) {
fn write_child_number(&mut self, mut output: impl Write) -> std::io::Result<()> {
let mut total_child_counter: u64 = 0;

let mut and_child_counter: u64 = 0;
Expand All @@ -84,27 +87,31 @@ impl Ddnnf {
}

let node_count: u64 = self.nodes.len() as u64;
info!(
"\nThe d-DNNF has the following information regarding node count:\n\

output.write_all(
format!(
"\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\
\t |-> There are {:.2} times as much connections as nodes\n\
\t |-> Each of the {:?} And nodes has an average of ≈{:.2} child nodes\n\
\t |-> Each of the {:?} Or nodes has an average of ≈{:.5} child nodes\n",
total_child_counter,
node_count,
total_child_counter as f64 / node_count as f64,
and_counter,
and_child_counter as f64 / and_counter as f64,
or_counter,
or_child_counter as f64 / or_counter as f64
);
total_child_counter,
node_count,
total_child_counter as f64 / node_count as f64,
and_counter,
and_child_counter as f64 / and_counter as f64,
or_counter,
or_child_counter as f64 / or_counter as f64
)
.as_bytes(),
)
}

// the standard deviation (s_x) is defined as sqrt((1/n) * sum over (length of a path - length of the mean path)² for each path)
// (lowest, highest, mean, s_x, #paths)
#[inline]
fn get_depths(&mut self) {
fn get_depths(&mut self, mut output: impl Write) -> std::io::Result<()> {
let mut lowest: u64 = u64::MAX;
let mut highest: u64 = 0;
let mut mean: f64 = 0.0;
Expand All @@ -131,13 +138,13 @@ impl Ddnnf {

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

info!("\nThe d-DNNF has the following length attributes:\n\
output.write_all(format!("\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\
\t |-> The standard derivation is ≈{:.2} units\n\
\t |-> There are {:?} different paths. (different paths can sometimes just differ by one node)\n",
lowest, highest, mean, s_x, length);
lowest, highest, mean, s_x, length).as_bytes())
}
}

Expand Down Expand Up @@ -168,7 +175,7 @@ fn get_depth(nodes: &[Node], indize: usize, count: u64) -> Vec<u64> {
}

// Functions that are currently not used but necessary to collect data regarding marking percentages,...
// With them we can compute the average, median and stdev.
// With them, we can compute the average, median and stdev.
// They were used to collect the data about the nodes visited when using the marking algorithm
#[allow(dead_code)]
fn average(data: &[u64]) -> f64 {
Expand Down
6 changes: 4 additions & 2 deletions ddnnife/tests/cardinalities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ddnnife::parser;
use file_diff::diff_files;
use serial_test::serial;
use std::fs::{self, File};
use std::io::BufWriter;
use std::io::{stdout, BufWriter};

#[test]
fn card_of_features_c2d() {
Expand Down Expand Up @@ -120,5 +120,7 @@ fn card_of_pc_cnf() {
#[test]
fn heuristics_test() {
let mut ddnnf: Ddnnf = parser::build_ddnnf("./tests/data/auto1_c2d.nnf", None);
ddnnf.print_all_heuristics();
ddnnf
.write_heuristics(BufWriter::new(stdout()))
.expect("Failed to write heuristics.");
}
10 changes: 5 additions & 5 deletions ddnnife_bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ enum Operation {
#[clap(short, long, allow_negative_numbers = true, num_args = 0.., verbatim_doc_comment)]
assumptions: Vec<i32>,
},
/// Computes and prints heuristics on the d-DNNF.
Heuristics,
}

fn main() {
Expand Down Expand Up @@ -384,6 +386,9 @@ fn main() {
Operation::Mermaid { assumptions } => {
write_as_mermaid_md(&mut ddnnf, assumptions, &mut writer).unwrap();
}
Operation::Heuristics => {
ddnnf.write_heuristics(&mut writer).unwrap();
}
}

writer.flush().unwrap();
Expand All @@ -397,11 +402,6 @@ fn main() {
path
);
}

// prints heuristics
if cli.heuristics {
ddnnf.print_all_heuristics();
}
}

fn compute_queries<T: ToString + Ord + Send + 'static>(
Expand Down

0 comments on commit f133cb2

Please sign in to comment.