Skip to main content

dtrees_rs/parsers/
examples.rs

1//! Command line arguments and result files shared by the anytime examples.
2
3use crate::algorithms::common::types::{OptimalDepth2Policy, SearchHeuristic, SearchStepStrategy};
4use crate::tree::Tree;
5use clap::Parser;
6use serde::{Deserialize, Serialize};
7use std::fs;
8use std::fs::{remove_file, File};
9use std::io::{BufReader, BufWriter, Write};
10use std::path::PathBuf;
11
12/// Command line arguments of the anytime examples.
13#[derive(Debug, Parser)]
14#[clap(name = "dt-trees", version, author, about)]
15pub struct ExampleParser {
16    /// Dataset file: one instance per line, label first, binary features
17    #[clap(short, long, value_parser)]
18    pub input: PathBuf,
19
20    /// Minimum number of instances in each leaf
21    #[arg(short, long, default_value_t = 5)]
22    pub support: usize,
23
24    /// Maximum depth of the tree
25    #[arg(short, long)]
26    pub depth: usize,
27
28    /// Time limit in seconds
29    #[arg(short, long, default_value_t = 300.0)]
30    pub timeout: f64,
31
32    /// Not used by the current examples
33    #[arg(short, long, default_value_t = 1.0)]
34    pub metric: f64,
35
36    /// Step of the gain and purity rules
37    #[arg(long, default_value_t = 0.002)]
38    pub epsilon: f64,
39
40    /// Whether to use the depth-2 solver
41    #[arg(long, value_enum, default_value_t = OptimalDepth2Policy::Enabled)]
42    pub fast_d2: OptimalDepth2Policy,
43
44    /// Print the search statistics
45    #[arg(long, default_value_t = false)]
46    pub print_stats: bool,
47
48    /// Sort the features by the heuristic at every node
49    #[arg(long, default_value_t = true)]
50    pub always_sort: bool,
51
52    /// Heuristic used to order the features
53    #[arg(long, value_enum, default_value_t = SearchHeuristic::NoHeuristic)]
54    pub heuristic: SearchHeuristic,
55
56    /// How the budget of the search rule grows between passes
57    #[arg(long, value_enum, default_value_t = SearchStepStrategy::Monotonic)]
58    pub step: SearchStepStrategy,
59
60    /// Directory where the JSON results are written
61    #[arg(short, long)]
62    pub result: PathBuf,
63
64    /// Print the tree
65    #[arg(long, default_value_t = false)]
66    pub print_tree: bool,
67
68    /// Overwrite existing results
69    #[arg(long, default_value_t = false)]
70    pub overwrite: bool,
71}
72
73/// The results of one run, saved as JSON.
74#[derive(Serialize, Deserialize, Clone)]
75pub struct Res {
76    pub name: String,
77    pub method: String,
78    pub depth: usize,
79    pub support: usize,
80    pub completed: bool,
81    pub one_time_sort: bool,
82    pub fast_d2: bool,
83    pub metric: Vec<f64>,
84    pub runtimes: Vec<f64>,
85    pub errors: Vec<f64>,
86    pub cache: Vec<usize>,
87    pub tree: Tree,
88}
89
90/// Writes `result` to `result_path`, creating its directory.
91pub fn save_results(result: &Res, result_path: &PathBuf) -> std::io::Result<()> {
92    if let Some(parent) = result_path.parent() {
93        fs::create_dir_all(parent)?;
94    }
95
96    let file = File::create(result_path)?;
97    let mut writer = BufWriter::new(file);
98    serde_json::to_writer_pretty(&mut writer, result)?;
99    writer.flush()
100}
101
102/// Reads results saved earlier, if the file exists and parses.
103pub fn load_results(result_path: &PathBuf) -> Option<Res> {
104    if !result_path.exists() {
105        return None;
106    }
107
108    File::open(result_path).ok().and_then(|file| {
109        let reader = BufReader::new(file);
110        serde_json::from_reader(reader).ok()
111    })
112}
113
114/// Deletes a result file if it exists.
115pub fn remove_results(result_path: &PathBuf) -> std::io::Result<()> {
116    if result_path.exists() {
117        remove_file(result_path)?
118    }
119    Ok(())
120}