Skip to content

Commit

Permalink
"Player 0x0bf860653e4a21553d9507dde3f9e59c88e8514a submitted 'clarke_…
Browse files Browse the repository at this point in the history
…wright' for challenge vehicle_routing"
  • Loading branch information
0x0bf860653e4a21553d9507dde3f9e59c88e8514a committed May 16, 2024
1 parent 39e40f4 commit c8c728a
Show file tree
Hide file tree
Showing 7 changed files with 513 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
*/

use tig_challenges::vehicle_routing::*;

pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let d = &challenge.distance_matrix;
let c = challenge.max_capacity;
let n = challenge.difficulty.num_nodes;

// Clarke-Wright heuristic for node pairs based on their distances to depot
// vs distance between each other
let mut scores: Vec<(i32, usize, usize)> = Vec::new();
for i in 1..n {
for j in (i + 1)..n {
scores.push((d[i][0] + d[0][j] - d[i][j], i, j));
}
}
scores.sort_by(|a, b| b.0.cmp(&a.0)); // Sort in descending order by score

// Create a route for every node
let mut routes: Vec<Option<Vec<usize>>> = (0..n).map(|i| Some(vec![i])).collect();
routes[0] = None;
let mut route_demands: Vec<i32> = challenge.demands.clone();

// Iterate through node pairs, starting from greatest score
for (s, i, j) in scores {
// Stop if score is negative
if s < 0 {
break;
}

// Skip if joining the nodes is not possible
if routes[i].is_none() || routes[j].is_none() {
continue;
}

let left_route = routes[i].as_ref().unwrap();
let right_route = routes[j].as_ref().unwrap();
let mut left_startnode = left_route[0];
let right_startnode = right_route[0];
let left_endnode = left_route[left_route.len() - 1];
let mut right_endnode = right_route[right_route.len() - 1];
let merged_demand = route_demands[left_startnode] + route_demands[right_startnode];

if left_startnode == right_startnode || merged_demand > c {
continue;
}

let mut left_route = routes[i].take().unwrap();
let mut right_route = routes[j].take().unwrap();
routes[left_startnode] = None;
routes[right_startnode] = None;
routes[left_endnode] = None;
routes[right_endnode] = None;

// reverse it
if left_startnode == i {
left_route.reverse();
left_startnode = left_endnode;
}
if right_endnode == j {
right_route.reverse();
right_endnode = right_startnode;
}

let mut new_route = left_route;
new_route.extend(right_route);

// Only the start and end nodes of routes are kept
routes[left_startnode] = Some(new_route.clone());
routes[right_endnode] = Some(new_route);
route_demands[left_startnode] = merged_demand;
route_demands[right_endnode] = merged_demand;
}

Ok(Some(Solution {
routes: routes
.into_iter()
.enumerate()
.filter(|(i, x)| x.as_ref().is_some_and(|x| x[0] == *i))
.map(|(_, mut x)| {
let mut route = vec![0];
route.append(x.as_mut().unwrap());
route.push(0);
route
})
.collect(),
}))
}
102 changes: 102 additions & 0 deletions tig-algorithms/src/vehicle_routing/clarke_wright/commercial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
*/

use tig_challenges::vehicle_routing::*;

pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let d = &challenge.distance_matrix;
let c = challenge.max_capacity;
let n = challenge.difficulty.num_nodes;

// Clarke-Wright heuristic for node pairs based on their distances to depot
// vs distance between each other
let mut scores: Vec<(i32, usize, usize)> = Vec::new();
for i in 1..n {
for j in (i + 1)..n {
scores.push((d[i][0] + d[0][j] - d[i][j], i, j));
}
}
scores.sort_by(|a, b| b.0.cmp(&a.0)); // Sort in descending order by score

// Create a route for every node
let mut routes: Vec<Option<Vec<usize>>> = (0..n).map(|i| Some(vec![i])).collect();
routes[0] = None;
let mut route_demands: Vec<i32> = challenge.demands.clone();

// Iterate through node pairs, starting from greatest score
for (s, i, j) in scores {
// Stop if score is negative
if s < 0 {
break;
}

// Skip if joining the nodes is not possible
if routes[i].is_none() || routes[j].is_none() {
continue;
}

let left_route = routes[i].as_ref().unwrap();
let right_route = routes[j].as_ref().unwrap();
let mut left_startnode = left_route[0];
let right_startnode = right_route[0];
let left_endnode = left_route[left_route.len() - 1];
let mut right_endnode = right_route[right_route.len() - 1];
let merged_demand = route_demands[left_startnode] + route_demands[right_startnode];

if left_startnode == right_startnode || merged_demand > c {
continue;
}

let mut left_route = routes[i].take().unwrap();
let mut right_route = routes[j].take().unwrap();
routes[left_startnode] = None;
routes[right_startnode] = None;
routes[left_endnode] = None;
routes[right_endnode] = None;

// reverse it
if left_startnode == i {
left_route.reverse();
left_startnode = left_endnode;
}
if right_endnode == j {
right_route.reverse();
right_endnode = right_startnode;
}

let mut new_route = left_route;
new_route.extend(right_route);

// Only the start and end nodes of routes are kept
routes[left_startnode] = Some(new_route.clone());
routes[right_endnode] = Some(new_route);
route_demands[left_startnode] = merged_demand;
route_demands[right_endnode] = merged_demand;
}

Ok(Some(Solution {
routes: routes
.into_iter()
.enumerate()
.filter(|(i, x)| x.as_ref().is_some_and(|x| x[0] == *i))
.map(|(_, mut x)| {
let mut route = vec![0];
route.append(x.as_mut().unwrap());
route.push(0);
route
})
.collect(),
}))
}
102 changes: 102 additions & 0 deletions tig-algorithms/src/vehicle_routing/clarke_wright/inbound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
*/

use tig_challenges::vehicle_routing::*;

pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let d = &challenge.distance_matrix;
let c = challenge.max_capacity;
let n = challenge.difficulty.num_nodes;

// Clarke-Wright heuristic for node pairs based on their distances to depot
// vs distance between each other
let mut scores: Vec<(i32, usize, usize)> = Vec::new();
for i in 1..n {
for j in (i + 1)..n {
scores.push((d[i][0] + d[0][j] - d[i][j], i, j));
}
}
scores.sort_by(|a, b| b.0.cmp(&a.0)); // Sort in descending order by score

// Create a route for every node
let mut routes: Vec<Option<Vec<usize>>> = (0..n).map(|i| Some(vec![i])).collect();
routes[0] = None;
let mut route_demands: Vec<i32> = challenge.demands.clone();

// Iterate through node pairs, starting from greatest score
for (s, i, j) in scores {
// Stop if score is negative
if s < 0 {
break;
}

// Skip if joining the nodes is not possible
if routes[i].is_none() || routes[j].is_none() {
continue;
}

let left_route = routes[i].as_ref().unwrap();
let right_route = routes[j].as_ref().unwrap();
let mut left_startnode = left_route[0];
let right_startnode = right_route[0];
let left_endnode = left_route[left_route.len() - 1];
let mut right_endnode = right_route[right_route.len() - 1];
let merged_demand = route_demands[left_startnode] + route_demands[right_startnode];

if left_startnode == right_startnode || merged_demand > c {
continue;
}

let mut left_route = routes[i].take().unwrap();
let mut right_route = routes[j].take().unwrap();
routes[left_startnode] = None;
routes[right_startnode] = None;
routes[left_endnode] = None;
routes[right_endnode] = None;

// reverse it
if left_startnode == i {
left_route.reverse();
left_startnode = left_endnode;
}
if right_endnode == j {
right_route.reverse();
right_endnode = right_startnode;
}

let mut new_route = left_route;
new_route.extend(right_route);

// Only the start and end nodes of routes are kept
routes[left_startnode] = Some(new_route.clone());
routes[right_endnode] = Some(new_route);
route_demands[left_startnode] = merged_demand;
route_demands[right_endnode] = merged_demand;
}

Ok(Some(Solution {
routes: routes
.into_iter()
.enumerate()
.filter(|(i, x)| x.as_ref().is_some_and(|x| x[0] == *i))
.map(|(_, mut x)| {
let mut route = vec![0];
route.append(x.as_mut().unwrap());
route.push(0);
route
})
.collect(),
}))
}
Loading

0 comments on commit c8c728a

Please sign in to comment.