Solving MAXSAT and saying a few words about it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

223 lines
6.8 KiB

// vim: ts=4 sw=4 et
#![feature(specialization)]
#![feature(non_ascii_idents)]
extern crate nalgebra;
#[macro_use]
/// Variables -- both boolean, and otherwise.
pub mod variable;
#[macro_use]
/// Useful for disjunctive clauses.
pub mod clause;
mod clause_gen;
/// I made this before I knew I didn't need it. :/
pub mod hash_wrapper;
/// Affine scaling, linear systems and inequalities, etc.
pub mod karmarkar;
mod maxsat;
pub mod messy_minsat;
use crate::clause_gen::*;
use crate::maxsat::*;
use std::env;
use std::fs::File;
use std::io::{self, BufWriter, Write};
use std::mem::drop;
use std::process::exit;
use std::sync::mpsc::{channel, sync_channel};
use std::thread;
use std::time::{Duration, Instant};
fn main() -> io::Result<()> {
let mut log = BufWriter::new(File::create("log.txt")?);
let args: Vec<String> = env::args().collect();
if args.len() != 5 {
println!("can't accept {} arguments!", args.len());
println!("Usage: {} <clause count max> <variable count max> <clause size> <samples per parameter set>", args[0]);
println!("ah ah ah ... you didn't say the magic word");
std::thread::sleep(Duration::from_millis(2000));
println!("ah ah ah ... you didn't say the magic word");
std::thread::sleep(Duration::from_millis(2000));
loop {
println!("ah ah ah ...");
std::thread::sleep(Duration::from_millis(800));
}
}
let max_clause_count: usize = args[1].parse().unwrap();
let max_var_count: usize = args[2].parse().unwrap();
let max_clause_size: usize = args[3].parse().unwrap();
let num_samples: usize = args[4].parse().unwrap();
println!("===== TRIAL RUN =====");
let rand_clause_list = gen_clause_list(max_clause_count, max_var_count, max_clause_size);
println!("{}", rand_clause_list);
let solution = solve_by_bfs(&rand_clause_list);
println!("MAXSAT (By BFS): {}", solution);
let weights = vec![Some(1); rand_clause_list.len()];
let list = rand_clause_list.copy();
crate::karmarkar::ilp_maxsat(list, &weights);
println!(
"MAXSAT (By ILP): {}",
rand_clause_list
.iter()
.filter(|c| matches!(c.eval(), Some(true)))
.count()
);
println!("=== END TRIAL RUN ===");
let job_runner_generator = || {
|(clause_count, var_count, clause_size, which)| {
let rand_clause_list = gen_clause_list(clause_count, var_count, clause_size);
let time;
match which {
0 => {
let tick = Instant::now();
let _solution = solve_by_bfs(&rand_clause_list);
time = tick.elapsed().as_secs_f64();
}
1 => {
let weights = vec![Some(1); rand_clause_list.len()];
let list = rand_clause_list.clone();
let tick = Instant::now();
crate::karmarkar::ilp_maxsat(list, &weights);
time = tick.elapsed().as_secs_f64();
}
_ => panic!("unexpected job type"),
}
(clause_count, var_count, clause_size, which, time)
}
};
let (jtx, jrx) = sync_channel(0);
thread::spawn(move || {
for clause_count in 1..=max_clause_count {
for var_count in 1..=max_var_count {
for jobtype in 0..=1 {
for _ in 0..num_samples {
let _ = jtx.send((
clause_count,
var_count,
usize::min(max_clause_size, var_count),
jobtype,
));
}
}
}
}
});
let get_job = move || match jrx.recv() {
Ok(job) => Some(job),
_ => None,
};
let (rtx, rrx) = channel();
let mut result_map = std::collections::HashMap::new();
let result_loop = thread::spawn(move || {
while let Ok(Some(result)) = rrx.recv() {
let _: (usize, usize, usize, usize, f64) = result; // helping the type inference engine
result_map
.entry((result.0, result.1, result.2, result.3))
.and_modify(|i| *i += result.4)
.or_insert(result.4);
println!("{:?}", result);
}
for (k, v) in &result_map {
if k.3 == 0 {
let mut k = k.clone();
k.3 = 1;
let v2 = result_map.get(&k).unwrap();
writeln!(
log,
"{} {} {} {}",
k.0,
k.1,
v / num_samples as f64,
v2 / num_samples as f64
)
.unwrap();
}
}
});
let handler = move |result: Option<(usize, usize, usize, usize, f64)>| {
let _ = rtx.send(result);
};
//dispatcher(16, 10, job_runner_generator, get_job, handler);
// let _ = result_loop.join();
exit(0);
}
fn dispatcher<Fw, J, R>(
nthreads: usize,
bufsize: usize,
worker_generator: impl Fn() -> Fw,
get_job: impl Fn() -> Option<J>,
handler: impl Fn(Option<R>),
) where
Fw: Fn(J) -> R + Send + 'static,
J: Send + 'static,
R: Send + 'static,
{
use std::thread::spawn;
let mut threads = Vec::new();
let (result_tx, result_rx) = channel();
for i in 0..nthreads {
let worker = worker_generator();
let (tx, rx) = channel();
let result_chan = result_tx.clone();
threads.push((
Some(tx),
spawn(move || loop {
match rx.recv() {
Ok(job) => {
let result = worker(job);
let _ = result_chan.send((i, result));
}
_ => break,
}
}),
));
}
drop(result_tx);
'outer: for _ in 0..bufsize {
for thread in threads.iter() {
match get_job() {
Some(job) => {
let _ = thread.0.as_ref().unwrap().send(job);
}
None => break 'outer,
}
}
}
loop {
let next_job = get_job();
match next_job {
Some(job) => {
let (i, result) = result_rx.recv().unwrap();
let _ = threads[i].0.as_ref().unwrap().send(job);
handler(Some(result));
}
None => break,
}
}
for thread in threads.iter_mut() {
thread.0.take();
}
loop {
match result_rx.recv() {
Ok((_, result)) => handler(Some(result)),
_ => break,
}
}
handler(None);
for thread in threads {
let _ = thread.1.join();
}
}