extern crate rand;
use rand::thread_rng;
use rand::distributions::{Distribution, Uniform};
use rand::rngs::ThreadRng;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy)]
pub struct ErModel {
n: usize,
p: f64,
digraph: bool,
self_loops: bool
}
impl ErModel {
pub fn new(n: usize, p: f64) -> Self {
ErModel {n, p, self_loops: false, digraph: false}
}
pub fn digraph(self) -> Self {
ErModel{n: self.n, p: self.p, self_loops: self.self_loops, digraph: true}
}
pub fn with_self_loops(self) -> Self {
ErModel{n: self.n, p: self.p, self_loops: true, digraph: self.digraph}
}
pub fn generator(self) -> ErGenerator {
ErGenerator::new(self)
}
fn nb_possible_edges(self) -> u128 {
let sources = self.n as u128;
let dests = if self.self_loops { self.n } else { self.n - 1 } as u128;
if self.digraph {
sources * dests
} else {
(sources * dests) / 2
}
}
fn nb_edges_to_pick(self) -> usize {
(self.p * self.nb_possible_edges() as f64).round() as usize
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Vertex {
id: isize
}
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Edge {
src : Vertex,
dst : Vertex,
}
impl Edge {
pub fn is_self_loop(self) -> bool {
self.src == self.dst
}
pub fn rev(self) -> Self {
Edge {src: self.dst, dst: self.src}
}
}
#[derive(Debug, Clone)]
pub struct Graph {
model: ErModel,
n : usize,
list : HashMap<Edge, isize>
}
impl Graph {
pub fn pluck_random_weights(&mut self, from: &[isize]) {
let mut rng = thread_rng();
let dist= Uniform::new(0, from.len());
for (_e, w) in self.list.iter_mut() {
*w = from[dist.sample(&mut rng)];
}
}
pub fn to_dimacs(&self) -> String {
let mut out = vec![];
let gtype = if self.model.digraph { "digraph" } else {"graph"};
let loops = if self.model.self_loops { "" } else { " NOT"};
out.push(format!("c Pseudo-random Erdos-Renyi {} G({}, {})", gtype, self.model.n, self.model.p));
out.push(format!("c it was generated to{} allow self loops", loops));
out.push(format!("c This graph has {} vertices and {} edges", self.n, self.list.len()));
out.push("c ".to_string());
out.push("c Generated w/ graph_gen: https://github.com/xgillard/graph_gen".to_string());
out.push(format!("{} {}", self.n, self.list.len()));
for (edge, w) in self.list.iter() {
out.push(format!("{} {} {}", edge.src.id, edge.dst.id, w));
}
out.join("\n")
}
pub fn to_dot(&self) -> String {
let mut out = vec![];
let gtype = if self.model.digraph { "digraph" } else {"graph"};
let connector = if self.model.digraph { "->" } else { "--" };
out.push(format!("{} g {{", gtype));
for v in 1..=self.n {
out.push(format!(" {};", v));
}
for (edge, w) in self.list.iter() {
out.push(format!(" {} {} {} [label={}];", edge.src.id, connector, edge.dst.id, w));
}
out.push("}".to_owned());
out.join("\n")
}
}
#[derive(Debug, Clone)]
pub struct Max2SatGraph {
g: Graph
}
impl Max2SatGraph {
pub fn new(g: Graph) -> Max2SatGraph {
Max2SatGraph{g}
}
pub fn to_dimacs(&self) -> String {
let mut out = vec![];
let loops = if self.g.model.self_loops { "" } else { " NOT"};
out.push(format!("c Pseudo-random max2sat instance generated w/ Erdos-Renyi G({}, {}) model", self.g.model.n, self.g.model.p));
out.push(format!("c it was generated to{} allow self loops", loops));
out.push(format!("c This instance has {} variables and {} clauses", self.g.n/2, self.g.list.len()));
out.push("c ".to_string());
out.push("c Each clause reads <weight> <source> <dest> 0".to_string());
out.push("c ".to_string());
out.push("c Generated w/ graph_gen: https://github.com/xgillard/graph_gen".to_string());
out.push(format!("p wcnf {} {}", self.g.n/2, self.g.list.len()));
for (edge, w) in self.g.list.iter() {
out.push(format!("{} {} {} 0", w, self.literal(edge.src), self.literal(edge.dst)));
}
out.join("\n")
}
pub fn to_dot(&self) -> String {
let mut out = vec![];
out.push("graph wcnf {".to_string());
for v in 1..=self.g.n/2 {
out.push(format!(" {};", v));
}
for (edge, w) in self.g.list.iter() {
out.push(format!(" {} -- {} [label={}];", self.literal(edge.src), self.literal(edge.dst), w));
}
out.push("}".to_owned());
out.join("\n")
}
fn literal(&self, v: Vertex) -> isize {
let v_id = v.id;
if v_id > self.g.n as isize / 2 {
-(v_id/2)
} else {
v_id
}
}
}
pub enum Generatable {
GenGraph{g: Graph},
GenSat {s: Max2SatGraph}
}
impl Generatable {
pub fn to_dimacs(&self) -> String {
match self {
Generatable::GenGraph {g} => g.to_dimacs(),
Generatable::GenSat {s} => s.to_dimacs()
}
}
pub fn to_dot(&self) -> String {
match self {
Generatable::GenGraph {g} => g.to_dot(),
Generatable::GenSat {s} => s.to_dot()
}
}
}
#[derive(Debug)]
pub struct ErGenerator {
model: ErModel,
rng : ThreadRng,
dist : Uniform<u128>
}
impl ErGenerator {
fn new(model: ErModel) -> ErGenerator {
ErGenerator {
model,
rng : thread_rng(),
dist : Uniform::new(0, model.n as u128 * model.n as u128)
}
}
fn next_edge(&mut self) -> Edge {
let dist = &mut self.dist;
let rng = &mut self.rng;
let number = dist.sample(rng);
let src = (number / self.model.n as u128) as isize;
let dst = (number % self.model.n as u128) as isize;
Edge { src: Vertex{id: src + 1}, dst: Vertex{id: dst + 1} }
}
pub fn gen(&mut self) -> Graph {
let mut g = Graph{model: self.model, n: self.model.n, list: Default::default()};
let nb_edges = self.model.nb_edges_to_pick();
g.list.reserve(nb_edges);
while g.list.len() < nb_edges {
let edge = self.next_edge();
if edge.is_self_loop() && !self.model.self_loops {
continue;
}
if g.list.contains_key(&edge) || g.list.contains_key(&edge.rev()) {
continue;
}
g.list.insert(edge, 1);
}
g
}
}
impl Iterator for ErGenerator {
type Item = Graph;
fn next(&mut self) -> Option<Graph> {
Some(self.gen())
}
}