1use crate::{clause::Clause, literal::Literal};
2
3use bool_vec::{boolvec, BoolVec};
4
5#[cfg(feature = "rand")]
6use rand::{distributions::Standard, Rng, SeedableRng};
7
8use std::{fs, io::Write, path::Path};
9
10#[derive(Debug)]
12pub struct Instance {
13 pub vars: BoolVec,
14 clauses: Vec<Clause>,
15}
16
17impl Clone for Instance {
18 fn clone(&self) -> Self {
19 let mut bvec_clone = BoolVec::with_capacity(self.vars.capacity());
20 for origin in &self.vars {
21 bvec_clone.push(origin);
22 }
23
24 Self {
25 vars: bvec_clone,
26 clauses: self.clauses.clone(),
27 }
28 }
29}
30
31impl Instance {
32 pub fn new(vars: BoolVec, clauses: Vec<Clause>) -> Self {
34 Self { vars, clauses }
35 }
36
37 pub fn with_clauses(n: usize, clauses: Vec<Clause>) -> Self {
39 Self {
40 vars: boolvec![false; n],
41 clauses,
42 }
43 }
44
45 pub fn from_file<P>(path: P) -> std::io::Result<Self>
48 where
49 P: AsRef<Path>,
50 {
51 let content = fs::read_to_string(path)?;
54
55 let mut lines = content.trim().lines().skip_while(|x| x.starts_with('c'));
56
57 let mut param_line = lines
58 .next()
59 .ok_or(std::io::ErrorKind::InvalidInput)?
60 .split_whitespace()
61 .skip(1);
62
63 let problem_type = param_line.next().ok_or(std::io::ErrorKind::InvalidInput)?;
64 if problem_type != "cnf" {
65 return Err(std::io::ErrorKind::InvalidInput.into());
66 }
67
68 let n = param_line
69 .next()
70 .ok_or(std::io::ErrorKind::InvalidInput)?
71 .parse()
72 .map_err(|_| std::io::ErrorKind::InvalidInput)?;
73 let m = param_line
74 .next()
75 .ok_or(std::io::ErrorKind::InvalidInput)?
76 .parse()
77 .map_err(|_| std::io::ErrorKind::InvalidInput)?;
78
79 let clauses = lines
80 .take(m)
81 .map(str::split_whitespace)
82 .map(|clause| {
83 clause
84 .map(|x| x.parse())
85 .take_while(|r| r.as_ref().map_or(false, |x| *x != 0))
86 .map(|r| r.map(Literal::from_cnf))
87 .collect::<Result<Clause, _>>()
88 })
89 .collect::<Result<_, _>>()
90 .map_err(|_| std::io::ErrorKind::InvalidInput)?;
91
92 Ok(Self {
93 vars: boolvec![false; n],
94 clauses,
95 })
96 }
97
98 #[cfg(feature = "rand")]
100 pub fn new_random<R: Rng + SeedableRng>(n: usize, m: usize, k: usize) -> Self {
101 let mut rng = R::from_entropy();
102
103 let mut chosen_indices = vec![];
104
105 let vars = BoolVec::from((&mut rng).sample_iter(Standard).take(n).collect::<Vec<_>>());
106 let clauses = (0..m)
107 .map(|_| {
108 let mut var_indices: Vec<usize> = vec![0; k];
109 let mut negates = boolvec![false; k];
110
111 for i in 0..k {
112 let mut idx = rng.gen_range(0..n);
113 while chosen_indices.contains(&idx) {
114 idx = rng.gen_range(0..n);
115 }
116 chosen_indices.push(idx);
117
118 var_indices[i] = idx;
119 negates.set(i, rng.gen());
120 }
121 chosen_indices.clear();
122
123 Clause::from_indices(var_indices, &negates)
124 })
125 .collect();
126
127 Self { vars, clauses }
128 }
129
130 pub fn to_file<P>(&self, path: P) -> std::io::Result<()>
132 where
133 P: AsRef<Path>,
134 {
135 let mut file = fs::File::create(path)?;
136
137 writeln!(file, "p cnf {} {}", self.vars.len(), self.clauses.len())?;
138 for clause in &self.clauses {
139 for elem in clause.get_literals() {
140 write!(file, "{} ", elem.as_cnf())?;
141 }
142 writeln!(file, "0")?;
143 }
144
145 Ok(())
146 }
147
148 #[cfg(feature = "rand")]
150 pub fn sample_new_variables(&mut self) -> &BoolVec {
151 let mut rng = rand::thread_rng();
152 self.sample_new_variables_with(&mut rng)
153 }
154
155 #[cfg(feature = "rand")]
157 pub fn sample_new_variables_with<T: Rng>(&mut self, rng: &mut T) -> &BoolVec {
158 self.vars = BoolVec::from(
159 rng.sample_iter(Standard)
160 .take(self.vars.len())
161 .collect::<Vec<_>>(),
162 );
163
164 &self.vars
165 }
166
167 pub fn count_sat(&self) -> usize {
169 self.clauses
170 .iter()
171 .filter(|clause| clause.test_sat(&self.vars))
172 .count()
173 }
174
175 pub fn is_sat(&self) -> bool {
177 self.count_sat() == self.clauses.len()
178 }
179
180 pub fn clause_to_vars(&self) -> f32 {
182 self.clauses.len() as f32 / self.vars.len() as f32
183 }
184
185 pub fn get_clauses(&self) -> &Vec<Clause> {
187 &self.clauses
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 #[test]
194 fn test() {}
195}