Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make function API's consistent #89

Merged
merged 3 commits into from
Mar 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::Duration;

use broute::graphs::algorithms::{
form_abstracted_graph, travelling_salesman, ConnectedComponents, Dijkstra,
form_abstracted_graph, ConnectedComponents, Dijkstra, SimulatedAnnealing,
};
use broute::graphs::datastructures::{Digraph, NodeIndex};
use broute::graphs::input::{get_random_graph, load_pbf_file, load_tsplib_file, load_xgmml_file};
Expand All @@ -24,7 +24,7 @@ fn shortest_path_benchmark(c: &mut Criterion) {
},
);

let dimacs_g = load_tsplib_file("test_data/dimacs_tsp/d1291.tsp", usize::MAX);
let dimacs_g = load_tsplib_file("test_data/dimacs_tsp/d1291.tsp", usize::MAX).unwrap();
group.bench_with_input(
BenchmarkId::new("DIMCAS d1291", &dimacs_g),
&dimacs_g,
Expand All @@ -36,7 +36,7 @@ fn shortest_path_benchmark(c: &mut Criterion) {
},
);

let monaco_g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf");
let monaco_g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf").unwrap();
let mut monaco_cc = ConnectedComponents::new(&monaco_g);
monaco_cc.run();
let monaco_largest_g = monaco_cc.get_largest_connected_subgraphs();
Expand Down Expand Up @@ -73,14 +73,19 @@ fn shortest_path_benchmark(c: &mut Criterion) {
fn travelling_salesman_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("Travelling salesman");

let dimacs_g = load_tsplib_file("test_data/dimacs_tsp/d1291.tsp", usize::MAX);
let dimacs_g = load_tsplib_file("test_data/dimacs_tsp/d1291.tsp", usize::MAX).unwrap();
group.bench_with_input(
BenchmarkId::new("DIMCAS d1291", &dimacs_g),
&dimacs_g,
|b, g| b.iter(|| travelling_salesman(g, false)),
|b, g| {
b.iter(|| {
let mut sa = SimulatedAnnealing::new(g);
sa.run();
})
},
);

let monaco_g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf");
let monaco_g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf").unwrap();

let mut monaco_cc = ConnectedComponents::new(&monaco_g);
monaco_cc.run();
Expand All @@ -95,14 +100,19 @@ fn travelling_salesman_benchmark(c: &mut Criterion) {
group.bench_with_input(
BenchmarkId::new("OSM Monaco - 5 random nodes", &abstracted_graph),
&abstracted_graph,
|b, g| b.iter(|| travelling_salesman(g, false)),
|b, g| {
b.iter(|| {
let mut sa = SimulatedAnnealing::new(g);
sa.run();
})
},
);

group.finish();
}

fn connected_components_benchmark(c: &mut Criterion) {
let g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf");
let g = load_pbf_file("test_data/geofabrik/monaco-latest.osm.pbf").unwrap();

let mut group = c.benchmark_group("Connected components");

Expand Down
2 changes: 1 addition & 1 deletion src/graphs/algorithms/shortest_path.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::super::algorithms::PriorityQueue;
use crate::algorithms::PriorityQueue;
use crate::graphs::datastructures::GraphPath;
use crate::graphs::datastructures::{Digraph, NodeIndex};

Expand Down
146 changes: 80 additions & 66 deletions src/graphs/algorithms/travelling_salesman.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,97 +34,111 @@ pub fn form_abstracted_graph(g: &dyn Digraph, node_ids: &Vec<NodeID>) -> AMDigra
abstracted_graph
}

fn get_potential_new_path(
rng: &mut ThreadRng,
g: &dyn Digraph,
current_path: &GraphPath,
) -> GraphPath {
let mut potential_new_path = current_path.clone();

let node_index_to_mutate = rng.gen_range(0..(g.num_vertices() - 1));
pub struct SimulatedAnnealing<'a> {
g: &'a dyn Digraph,
result_data: Vec<(f64, f64)>,
current_path: GraphPath,
path_length: f64,
best_path: GraphPath,
rng: ThreadRng,
}

let reverse_or_transport: bool = rng.gen();
impl<'a> SimulatedAnnealing<'a> {
pub fn new(g: &'a dyn Digraph) -> Self {
let mut rng = thread_rng();

if reverse_or_transport {
let node_index_to_swap_with = if node_index_to_mutate < (g.num_vertices() - 1) {
node_index_to_mutate + 1
} else {
0
let mut current_path = GraphPath {
path: (0..g.num_vertices()).map(NodeIndex).collect(),
};
potential_new_path
.path
.swap(node_index_to_mutate, node_index_to_swap_with);
} else {
// Cyclic permutation
let node_to_move = potential_new_path.path[node_index_to_mutate];
// -2 because we are looking for new position with 1 node missing
let new_node_position = rng.gen_range(0..(g.num_vertices() - 2));
potential_new_path.path.remove(node_index_to_mutate);
potential_new_path
.path
.insert(new_node_position, node_to_move)
current_path.path.shuffle(&mut rng);

let path_length = current_path.get_length_on_graph(g);

let best_path = current_path.clone();
SimulatedAnnealing {
g,
result_data: vec![],
current_path,
path_length,
best_path,
rng,
}
}

potential_new_path
}

pub fn travelling_salesman(g: &dyn Digraph, output_graph: bool) -> GraphPath {
let mut result_data: Vec<(f64, f64)> = vec![];

let mut rng = thread_rng();
pub fn run(&mut self) {
let mut temp = f64::sqrt(self.g.num_vertices() as f64);
let mut iterations = 0;
while temp > 1e-8_f64 && iterations < (100 * self.g.num_vertices()) {
let potential_new_path = self.get_potential_new_path();

let new_path_length = potential_new_path.get_length_on_graph(self.g);
if new_path_length < self.path_length {
self.current_path = potential_new_path;
self.best_path.clone_from(&self.current_path);
self.path_length = new_path_length;
} else {
// TODO: Is this between 0 and 1?
if f64::exp(-f64::abs(new_path_length - self.path_length) / temp)
> self.rng.gen::<f64>()
{
self.current_path = potential_new_path;
self.path_length = new_path_length;
}
}

let mut current_path = GraphPath {
path: (0..g.num_vertices()).map(NodeIndex).collect(),
};
current_path.path.shuffle(&mut rng);
let mut path_length = current_path.get_length_on_graph(g);
temp *= 0.995;
iterations += 1;
self.result_data.push((temp, self.path_length));
}
}

let mut best_path = current_path.clone();
fn get_potential_new_path(&mut self) -> GraphPath {
let mut potential_new_path = self.current_path.clone();

// println!("Initial state");
//
// println!("\t{:?}", best_path.path);
// println!("\t{}", path_length);
let node_index_to_mutate = self.rng.gen_range(0..(self.g.num_vertices() - 1));

let mut temp = f64::sqrt(g.num_vertices() as f64);
let mut iterations = 0;
while temp > 1e-8_f64 && iterations < (100 * g.num_vertices()) {
// println!("{}", temp);
let potential_new_path = get_potential_new_path(&mut rng, g, &current_path);
let reverse_or_transport: bool = self.rng.gen();

let new_path_length = potential_new_path.get_length_on_graph(g);
if new_path_length < path_length {
current_path = potential_new_path;
best_path.clone_from(&current_path);
path_length = new_path_length;
if reverse_or_transport {
let node_index_to_swap_with = if node_index_to_mutate < (self.g.num_vertices() - 1) {
node_index_to_mutate + 1
} else {
0
};
potential_new_path
.path
.swap(node_index_to_mutate, node_index_to_swap_with);
} else {
// TODO: Is this between 0 and 1?
if f64::exp(-f64::abs(new_path_length - path_length) / temp) > rng.gen::<f64>() {
current_path = potential_new_path;
path_length = new_path_length;
}
// Cyclic permutation
let node_to_move = potential_new_path.path[node_index_to_mutate];
// -2 because we are looking for new position with 1 node missing
let new_node_position = self.rng.gen_range(0..(self.g.num_vertices() - 2));
potential_new_path.path.remove(node_index_to_mutate);
potential_new_path
.path
.insert(new_node_position, node_to_move)
}

temp *= 0.995;
iterations += 1;
result_data.push((temp, path_length));
potential_new_path
}

pub fn get_best_path(&self) -> &GraphPath {
&self.best_path
}

if output_graph {
pub fn output_graph(&self) {
// We create our scatter plot from the data
let s1: Plot =
Plot::new(result_data.clone()).line_style(LineStyle::new().colour("#DD3355"));
Plot::new(self.result_data.clone()).line_style(LineStyle::new().colour("#DD3355"));

// The 'view' describes what set of data is drawn
let v = ContinuousView::new()
.add(s1)
.x_label("Temperature")
.y_label("Path length")
.y_range(0.0, result_data[0].1 + 100.0);
.y_range(0.0, self.result_data[0].1 + 100.0);

// A page with a single view is then saved to an SVG file
Page::single(&v).save("out/tsp_test_1.svg").unwrap();
}

best_path
}
Loading