Skip to main content

shuffledimacs/
shuffledimacs.rs

1//! # `shuffledimacs`
2//!
3//! A small tool for shuffling the order of constraints and the variable
4//! indexing in a DIMACS file.
5//!
6//! Usage: `shuffledimacs [dimacs [m,w]cnf file] [output path]`
7
8use std::path::{Path, PathBuf};
9
10use anyhow::Context;
11use rustsat::instances::{self, BasicVarManager, RandReindVarManager};
12
13macro_rules! print_usage {
14    () => {{
15        eprintln!("Usage: shuffledimacs [dimacs [m,w]cnf file] [output path]");
16        panic!()
17    }};
18}
19
20enum FileType {
21    Cnf,
22    Wcnf,
23    Mcnf,
24}
25
26fn main() -> anyhow::Result<()> {
27    let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!()));
28    let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!()));
29
30    match determine_file_type(&in_path) {
31        FileType::Cnf => {
32            let inst = instances::SatInstance::<BasicVarManager>::from_dimacs_path(in_path)
33                .context("Could not parse CNF")?;
34            let n_vars = inst.n_vars();
35            let rand_reindexer = RandReindVarManager::init(n_vars);
36            inst.reindex(rand_reindexer)
37                .shuffle()
38                .write_dimacs_path(out_path)
39                .context("Could not write CNF")?;
40        }
41        FileType::Wcnf => {
42            let inst = instances::OptInstance::<BasicVarManager>::from_dimacs_path(in_path)
43                .context("Could not parse WCNF")?;
44            let n_vars = inst.constraints_ref().n_vars();
45            let rand_reindexer = RandReindVarManager::init(n_vars);
46            inst.reindex(rand_reindexer)
47                .shuffle()
48                .write_dimacs_path(out_path)
49                .context("Could not write WCNF")?;
50        }
51        FileType::Mcnf => {
52            let inst = instances::MultiOptInstance::<BasicVarManager>::from_dimacs_path(in_path)
53                .context("Could not parse MCNF")?;
54            let n_vars = inst.constraints_ref().n_vars();
55            let rand_reindexer = RandReindVarManager::init(n_vars);
56            inst.reindex(rand_reindexer)
57                .shuffle()
58                .write_dimacs_path(out_path)
59                .context("Could not write MCNF")?;
60        }
61    }
62    Ok(())
63}
64
65macro_rules! is_one_of {
66    ($a:expr, $($b:expr),*) => {
67        $( $a == $b || )* false
68    }
69}
70
71fn determine_file_type(in_path: &Path) -> FileType {
72    if let Some(ext) = in_path.extension() {
73        let path_without_compr = in_path.with_extension("");
74        let ext = if is_one_of!(ext, "gz", "bz2") {
75            // Strip compression extension
76            match path_without_compr.extension() {
77                Some(ext) => ext,
78                None => return FileType::Cnf, // Fallback default
79            }
80        } else {
81            ext
82        };
83        if "wcnf" == ext {
84            return FileType::Wcnf;
85        };
86        if "mcnf" == ext {
87            return FileType::Mcnf;
88        };
89        return FileType::Cnf; // Fallback default
90    };
91    FileType::Cnf // Fallback default
92}