Commit 12e578eb authored by tleydxdy's avatar tleydxdy

use more rust features

parent c9eced8e
......@@ -16,102 +16,251 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pub trait Cost {
fn cost(&self) -> usize;
}
impl Cost for usize {
fn cost(&self) -> usize {
*self
}
}
pub mod CGA {
use super::Cost;
use std::cmp::Ordering;
use std::collections::btree_set::Iter;
use std::collections::BTreeSet;
fn get_cost(sol: &BTreeSet<(usize, usize, Vec<usize>)>) -> usize {
#[derive(Debug)]
struct Solution<'a, T: Cost>(BTreeSet<Bin<'a, T>>);
impl<'a, T> Solution<'a, T>
where
T: Cost,
{
fn new(item: &'a T) -> Self {
let mut set = BTreeSet::new();
set.insert(Bin::new(0, item));
Self(set)
}
fn insert(&mut self, bin: Bin<'a, T>) -> bool {
self.0.insert(bin)
}
fn insert_into(&mut self, bin: &Bin<'a, T>, item: &'a T) -> bool {
let mut bin = self.0.take(bin).unwrap();
bin.push(item);
self.0.insert(bin)
}
fn len(&self) -> usize {
self.0.len()
}
fn iter(&self) -> Iter<Bin<'a, T>> {
self.0.iter()
}
}
impl<'a, T> Cost for Solution<'a, T>
where
T: Cost,
{
// The cost of the biggest bin is the cost of the solution
fn cost(&self) -> usize {
self.iter().next_back().unwrap().cost()
}
}
impl<'a, T> Clone for Solution<'a, T>
where
T: Cost,
{
// The cost of the biggest bin is the cost of the solution
sol.iter().next_back().unwrap().0
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
fn is_perfect(k: usize, total: usize, sol: &BTreeSet<(usize, usize, Vec<usize>)>) -> bool {
// perfect partitions are either all the same, or the difference are 1
get_cost(sol) * k <= total + k
#[derive(Debug)]
struct Bin<'a, T: Cost> {
id: usize,
cost: usize,
vec: Vec<&'a T>,
}
fn _solve(
impl<'a, T> Bin<'a, T>
where
T: Cost,
{
fn new(id: usize, item: &T) -> Bin<T> {
Bin {
id,
cost: item.cost(),
vec: vec![item],
}
}
fn push(&mut self, item: &'a T) {
self.cost += item.cost();
self.vec.push(item);
}
}
impl<'a, T> Cost for Bin<'a, T>
where
T: Cost,
{
fn cost(&self) -> usize {
self.cost
}
}
impl<'a, T> Clone for Bin<'a, T>
where
T: Cost,
{
fn clone(&self) -> Self {
Self {
id: self.id,
cost: self.cost,
vec: self.vec.clone(),
}
}
}
impl<'a, T> Ord for Bin<'a, T>
where
T: Cost,
{
fn cmp(&self, other: &Self) -> Ordering {
match self.cost.cmp(&other.cost) {
Ordering::Equal => self.id.cmp(&other.id),
r @ _ => r,
}
}
}
impl<'a, T> PartialOrd for Bin<'a, T>
where
T: Cost,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a, T> Eq for Bin<'a, T> where T: Cost {}
impl<'a, T> PartialEq for Bin<'a, T>
where
T: Cost,
{
fn eq(&self, other: &Self) -> bool {
self.cost == other.cost && self.id == other.id
}
}
// perfect partitions are either all the same, or the difference are 1
fn is_perfect<T>(k: usize, total: usize, sol: &Option<Solution<T>>) -> bool
where
T: Cost,
{
match sol.as_ref() {
Some(s) => s.cost() * k <= total + k,
None => false,
}
}
fn update_best<T>(old_best: usize, potential: &Option<Solution<T>>) -> usize
where
T: Cost,
{
potential.as_ref().map_or(old_best, |x| x.cost())
}
fn _solve<'a, T>(
k: usize,
mut input: Vec<usize>,
mut input: Vec<&'a T>,
total: usize,
mut part: BTreeSet<(usize, usize, Vec<usize>)>,
mut best: usize,
) -> Option<BTreeSet<(usize, usize, Vec<usize>)>> {
mut part: Solution<'a, T>,
best: &mut Option<Solution<'a, T>>,
) -> bool
where
T: Cost,
{
match input.pop() {
Some(n) => {
let mut result = None;
Some(item) => {
let mut found = false;
let mut cur_best = update_best(total, best);
// If there's still empty bins, use the empty bin first.
// If there's still empty bins, try the empty bin first.
if part.len() < k {
let mut new_part = part.clone();
new_part.insert((n, part.len(), vec![n]));
match _solve(k, input.clone(), total, new_part, best) {
Some(sol) => {
if is_perfect(k, total, &sol) {
return Some(sol);
}
best = get_cost(&sol);
result = Some(sol);
let mut part = part.clone();
part.insert(Bin::new(part.len(), item));
if _solve(k, input.clone(), total, part, best) {
if is_perfect(k, total, best) {
return true;
}
None => (),
found = true;
cur_best = update_best(cur_best, best);
}
}
let mut first_bin = part.iter().next().cloned().unwrap();
let cur_max = get_cost(&part);
let cur_max = part.cost();
// If all the bins are the same, just use the first one.
if first_bin.0 == cur_max && first_bin.0 + n < best {
part.remove(&first_bin);
first_bin.0 += n;
first_bin.2.push(n);
part.insert(first_bin);
return _solve(k, input.clone(), total, part, best);
}
// If even if we perfect partition the rest of the k-1 bins we
// still won't lower the best, we can stop.
// Proceed if lowering the best is possible.
// Use ((a - 1) / b) + 1 for always round up division.
if ((total - cur_max - 1) / k) + 1 < best {
// Try putting the next item in all the bins one by one,
// for the last i item they only need to be put in the last
// i smallest bins.
if ((total - cur_max - 1) / k) + 1 < cur_best {
// If all the bins are the same, just use the first one.
let first_bin = part.iter().next().unwrap();
let cur_min = first_bin.cost();
if cur_min == cur_max && cur_min + item.cost() < cur_best {
let first_bin = first_bin.clone();
part.insert_into(&first_bin, item);
return _solve(k, input.clone(), total, part, best);
}
// Try all the bins one by one,
for (i, bin) in part.iter().enumerate() {
// for the last i item they only need to be put in the
// i smallest bins.
if input.len() < i {
break;
}
// If improving the best is even possible
if bin.0 + n < best {
let mut new_part = part.clone();
let mut new_bin = new_part.take(&bin).unwrap();
new_bin.0 += n;
new_bin.2.push(n);
new_part.insert(new_bin);
match _solve(k, input.clone(), total, new_part, best) {
Some(sol) => {
if is_perfect(k, total, &sol) {
return Some(sol);
}
best = get_cost(&sol);
result = Some(sol);
if bin.cost() + item.cost() < cur_best {
let mut part = part.clone();
part.insert_into(bin, item);
if _solve(k, input.clone(), total, part, best) {
if is_perfect(k, total, best) {
return true;
}
None => (),
found = true;
cur_best = update_best(cur_best, best);
}
}
}
}
// Return the best result we found in the sub-tree.
return result;
// Return the best result from the childs.
return found;
}
// Leaf node, we are done.
// Leaf node, nothing to do.
None => {
return Some(part);
*best = Some(part);
return true;
}
}
}
pub fn solve(k: usize, mut input: Vec<usize>) -> Vec<Vec<usize>> {
pub fn solve<T>(k: usize, mut input: Vec<&T>) -> Vec<Vec<&T>>
where
T: Cost,
{
// Deal with dumb inputs.
let total = input.iter().sum();
let total = input.iter().map(|x| x.cost()).sum();
if k == 1 || total == 0 {
return vec![input];
} else if input.len() <= k {
......@@ -119,18 +268,14 @@ pub mod CGA {
}
// Sort by increasing order, so pop() gives decreasing number.
input.sort_unstable();
input.sort_unstable_by_key(|x| x.cost());
// First number always goes in the "first" bin, so don't need to search a tree.
let mut part = BTreeSet::new();
let n = input.pop().unwrap();
part.insert((n, 0, vec![n]));
let part = Solution::new(input.pop().unwrap());
_solve(k, input, total, part, total)
.unwrap()
.iter()
.map(|bin| bin.2.clone())
.collect()
let mut result = None;
_solve(k, input, total, part, &mut result);
result.unwrap().iter().map(|bin| bin.vec.clone()).collect()
}
}
......@@ -140,23 +285,26 @@ mod tests {
#[test]
fn test_cga() {
assert_eq!(CGA::solve(1, vec![1, 3, 2]), vec![vec![1, 3, 2]]);
assert_eq!(CGA::solve(2, vec![1, 3, 2]), vec![vec![3], vec![2, 1]]);
assert_eq!(CGA::solve(1, vec![&1, &3, &2]), vec![vec![&1, &3, &2]]);
assert_eq!(
CGA::solve(2, vec![&1, &3, &2]),
vec![vec![&3], vec![&2, &1]]
);
assert_eq!(
CGA::solve(3, vec![1, 3, 2]),
vec![vec![1], vec![3], vec![2]]
CGA::solve(3, vec![&1, &3, &2]),
vec![vec![&1], vec![&3], vec![&2]]
);
assert_eq!(
CGA::solve(4, vec![1, 3, 2]),
vec![vec![1], vec![3], vec![2]]
CGA::solve(4, vec![&1, &3, &2]),
vec![vec![&1], vec![&3], vec![&2]]
);
assert_eq!(
CGA::solve(3, vec![8, 4, 7, 5, 6]),
vec![vec![8], vec![7, 4], vec![6, 5]]
CGA::solve(3, vec![&8, &4, &7, &5, &6]),
vec![vec![&8], vec![&7, &4], vec![&6, &5]]
);
assert_eq!(
CGA::solve(4, vec![8, 4, 7, 5, 6]),
vec![vec![6], vec![7], vec![8], vec![5, 4]]
CGA::solve(4, vec![&8, &4, &7, &5, &6]),
vec![vec![&6], vec![&7], vec![&8], vec![&5, &4]]
);
}
......@@ -167,20 +315,20 @@ mod tests {
CGA::solve(
8,
vec![
32525, 17303, 7084, 24185, 2233, 23788, 20717, 25841, 14545, 14807, 30030,
23001, 310, 10096, 27283, 8125, 28625, 21273, 19109, 25831, 3628, 25627, 15169,
26692,
&32525, &17303, &7084, &24185, &2233, &23788, &20717, &25841, &14545, &14807,
&30030, &23001, &310, &10096, &27283, &8125, &28625, &21273, &19109, &25831,
&3628, &25627, &15169, &26692,
]
),
vec![
vec![25841, 15169, 14807],
vec![26692, 19109, 10096],
vec![25831, 23001, 7084],
vec![30030, 25627, 310],
vec![32525, 21273, 2233],
vec![24185, 17303, 14545],
vec![28625, 23788, 3628],
vec![27283, 20717, 8125]
vec![&25841, &15169, &14807],
vec![&26692, &19109, &10096],
vec![&25831, &23001, &7084],
vec![&30030, &25627, &310],
vec![&32525, &21273, &2233],
vec![&24185, &17303, &14545],
vec![&28625, &23788, &3628],
vec![&27283, &20717, &8125]
]
);
// random small numbers, realistic in some applications
......@@ -188,23 +336,25 @@ mod tests {
CGA::solve(
8,
vec![
13, 151, 172, 121, 185, 236, 237, 241, 209, 215, 78, 217, 54, 112, 147, 189,
209, 25, 165, 231, 44, 27, 65, 68, 150, 127, 241, 129, 235, 85, 49, 248, 236,
220, 112, 164, 199, 92, 148, 152, 50, 225, 112, 103, 80, 2, 36, 32, 26, 200, 6,
70, 227, 71, 137, 120, 197, 122, 248, 175, 206, 40, 166, 185, 3, 22, 92, 201,
113, 239, 96, 163, 208, 207, 9, 31, 208, 44, 63, 234, 244, 68, 47, 214, 138,
183, 77, 78, 48, 68, 253, 254, 107, 162, 182, 109, 183, 18, 53, 40,
&13, &151, &172, &121, &185, &236, &237, &241, &209, &215, &78, &217, &54,
&112, &147, &189, &209, &25, &165, &231, &44, &27, &65, &68, &150, &127, &241,
&129, &235, &85, &49, &248, &236, &220, &112, &164, &199, &92, &148, &152, &50,
&225, &112, &103, &80, &2, &36, &32, &26, &200, &6, &70, &227, &71, &137, &120,
&197, &122, &248, &175, &206, &40, &166, &185, &3, &22, &92, &201, &113, &239,
&96, &163, &208, &207, &9, &31, &208, &44, &63, &234, &244, &68, &47, &214,
&138, &183, &77, &78, &48, &68, &253, &254, &107, &162, &182, &109, &183, &18,
&53, &40,
]
),
vec![
vec![248, 231, 209, 206, 166, 163, 121, 109, 78, 54, 49, 27],
vec![241, 236, 217, 189, 183, 151, 129, 103, 85, 53, 48, 26],
vec![241, 236, 215, 199, 172, 162, 113, 112, 78, 68, 40, 25],
vec![254, 225, 214, 197, 182, 148, 122, 112, 71, 68, 47, 13, 9],
vec![253, 227, 208, 207, 165, 164, 120, 112, 70, 68, 44, 18, 6],
vec![248, 234, 208, 200, 175, 152, 137, 96, 80, 65, 36, 31],
vec![244, 235, 209, 201, 183, 147, 127, 107, 77, 63, 44, 22, 3],
vec![239, 237, 220, 185, 185, 150, 138, 92, 92, 50, 40, 32, 2]
vec![&248, &231, &209, &206, &166, &163, &121, &109, &78, &54, &49, &27],
vec![&241, &236, &217, &189, &183, &151, &129, &103, &85, &53, &48, &26],
vec![&241, &236, &215, &199, &172, &162, &113, &112, &78, &68, &40, &25],
vec![&254, &225, &214, &197, &182, &148, &122, &112, &71, &68, &47, &13, &9],
vec![&253, &227, &208, &207, &165, &164, &120, &112, &70, &68, &44, &18, &6],
vec![&248, &234, &208, &200, &175, &152, &137, &96, &80, &65, &36, &31],
vec![&244, &235, &209, &201, &183, &147, &127, &107, &77, &63, &44, &22, &3],
vec![&239, &237, &220, &185, &185, &150, &138, &92, &92, &50, &40, &32, &2]
]
);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment