Commit 8bdae45e authored by tleydxdy's avatar tleydxdy

now works with generic type T, change to BTreeMap

parent 12e578eb
......@@ -16,6 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![feature(test)]
extern crate test;
pub trait Cost {
fn cost(&self) -> usize;
}
......@@ -26,232 +30,183 @@ impl Cost for usize {
}
}
pub mod CGA {
impl<T: Cost> Cost for &T {
fn cost(&self) -> usize {
(**self).cost()
}
}
pub mod cga {
use super::Cost;
use std::cmp::Ordering;
use std::collections::btree_set::Iter;
use std::collections::BTreeSet;
use std::collections::btree_map::Keys;
use std::collections::btree_map::Values;
use std::collections::BTreeMap;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Key(usize, usize);
impl Cost for Key {
fn cost(&self) -> usize {
self.0
}
}
#[derive(Debug)]
struct Solution<'a, T: Cost>(BTreeSet<Bin<'a, T>>);
struct Solution<T: Cost + Copy>(BTreeMap<Key, Vec<T>>);
impl<'a, T> Solution<'a, T>
impl<T> Solution<T>
where
T: Cost,
T: Cost + Copy,
{
fn new(item: &'a T) -> Self {
let mut set = BTreeSet::new();
set.insert(Bin::new(0, item));
Self(set)
fn new() -> Self {
Self(BTreeMap::new())
}
fn insert(&mut self, bin: Bin<'a, T>) -> bool {
self.0.insert(bin)
fn add_bin(&mut self, id: usize, item: T) -> Key {
let key = Key(item.cost(), id);
self.0.insert(key, vec![item]);
key
}
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 remove_bin(&mut self, key: Key) {
self.0.remove(&key);
}
fn len(&self) -> usize {
self.0.len()
fn push(&mut self, mut key: Key, item: T) -> Key {
let mut vec = self.0.remove(&key).unwrap();
key.0 += item.cost();
vec.push(item);
self.0.insert(key, vec);
key
}
fn iter(&self) -> Iter<Bin<'a, T>> {
self.0.iter()
fn pop(&mut self, mut key: Key) {
let mut vec = self.0.remove(&key).unwrap();
let item = vec.pop().unwrap();
key.0 -= item.cost();
self.0.insert(key, vec);
}
}
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()
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a, T> Clone for Solution<'a, T>
where
T: Cost,
{
// The cost of the biggest bin is the cost of the solution
fn clone(&self) -> Self {
Self(self.0.clone())
fn values(&self) -> Values<Key, Vec<T>> {
self.0.values()
}
}
#[derive(Debug)]
struct Bin<'a, T: Cost> {
id: usize,
cost: usize,
vec: Vec<&'a T>,
}
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 keys(&self) -> Keys<Key, Vec<T>> {
self.0.keys()
}
fn push(&mut self, item: &'a T) {
self.cost += item.cost();
self.vec.push(item);
// perfect partitions are either all the same, or the difference are 1
fn is_perfect(&self, k: usize, total: usize) -> bool {
self.cost() * k <= total + k
}
}
impl<'a, T> Cost for Bin<'a, T>
impl<T> Cost for Solution<T>
where
T: Cost,
T: Cost + Copy,
{
// The cost of the biggest bin is the cost of the solution
fn cost(&self) -> usize {
self.cost
self.keys().next_back().unwrap().cost()
}
}
impl<'a, T> Clone for Bin<'a, T>
impl<T> Clone for Solution<T>
where
T: Cost,
T: Cost + Copy,
{
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
Self(self.0.clone())
}
}
// 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
fn is_perfect<T>(best: &Option<Solution<T>>, k: usize, total: usize) -> bool
where
T: Cost,
T: Cost + Copy,
{
match sol.as_ref() {
Some(s) => s.cost() * k <= total + k,
None => false,
}
best.as_ref().map_or(false, |s| s.is_perfect(k, total))
}
fn update_best<T>(old_best: usize, potential: &Option<Solution<T>>) -> usize
fn best_cost<T>(best: &Option<Solution<T>>, bound: usize) -> usize
where
T: Cost,
T: Cost + Copy,
{
potential.as_ref().map_or(old_best, |x| x.cost())
best.as_ref().map_or(bound, |s| s.cost())
}
fn _solve<'a, T>(
fn _solve<T>(
k: usize,
mut input: Vec<&'a T>,
input: &Vec<T>,
cur: usize,
total: usize,
mut part: Solution<'a, T>,
best: &mut Option<Solution<'a, T>>,
) -> bool
part: &mut Solution<T>,
best: &mut Option<Solution<T>>,
) -> usize
where
T: Cost,
T: Cost + Copy,
{
match input.pop() {
Some(item) => {
let mut found = false;
let mut cur_best = update_best(total, best);
// If there's still empty bins, try the empty bin first.
if part.len() < k {
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;
}
found = true;
cur_best = update_best(cur_best, best);
if cur < input.len() {
let item = input[cur];
let mut cur_best = best_cost(best, total);
// If there's still empty bins, try the empty bin first.
if part.len() < k {
let key = part.add_bin(part.len(), item);
let ret = _solve(k, input, cur + 1, cur_best, part, best);
part.remove_bin(key);
if ret < cur_best {
if is_perfect(best, k, total) {
return ret;
}
cur_best = best_cost(best, cur_best);
}
}
let cur_max = part.cost();
// Proceed if lowering the best is possible.
// Use ((a - 1) / b) + 1 for always round up division.
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);
}
let cur_max = part.cost();
// Proceed if lowering the best is possible.
// Use ((a - 1) / b) + 1 for always round up division.
if ((total - cur_max - 1) / k) + 1 < cur_best {
// If all the bins are the same, just use the first one.
let &key = part.keys().next().unwrap();
let cur_min = key.cost();
if cur_min == cur_max && cur_min + item.cost() < cur_best {
let key = part.push(key, item);
let ret = _solve(k, input, cur + 1, cur_best, part, best);
part.pop(key);
return ret;
}
// 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;
}
// Try all the bins one by one,
for (i, &key) in part.clone().keys().enumerate() {
// for the last i item they only need to be put in the
// i smallest bins.
if input.len() - cur < i {
break;
}
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;
}
found = true;
cur_best = update_best(cur_best, best);
if key.cost() + item.cost() < cur_best {
let key = part.push(key, item);
let ret = _solve(k, input, cur + 1, cur_best, part, best);
part.pop(key);
if ret < cur_best {
if is_perfect(best, k, total) {
return ret;
}
cur_best = best_cost(best, cur_best);
}
}
}
// Return the best result from the childs.
return found;
}
// Leaf node, nothing to do.
None => {
*best = Some(part);
return true;
}
cur_best
} else {
// Leaf node, update best.
*best = Some(part.clone());
part.cost()
}
}
......@@ -267,95 +222,105 @@ pub mod CGA {
return input.iter().map(|x| vec![*x]).collect();
}
// Sort by increasing order, so pop() gives decreasing number.
input.sort_unstable_by_key(|x| x.cost());
// Sort by decreasing order.
input.sort_unstable_by(|a, b| b.cost().cmp(&a.cost()));
// First number always goes in the "first" bin, so don't need to search a tree.
let part = Solution::new(input.pop().unwrap());
let mut part = Solution::new();
part.add_bin(0, input[0]);
let mut result = None;
_solve(k, input, total, part, &mut result);
result.unwrap().iter().map(|bin| bin.vec.clone()).collect()
_solve(k, &input, 1, total, &mut part, &mut result);
result.unwrap().values().map(|v| v.clone()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[test]
fn test_cga() {
assert_eq!(CGA::solve(1, vec![&1, &3, &2]), vec![vec![&1, &3, &2]]);
assert_eq!(cga::solve(1, vec![&1, &3, &2]), vec![vec![&1, &3, &2]]);
assert_eq!(
CGA::solve(2, vec![&1, &3, &2]),
cga::solve(2, vec![&1, &3, &2]),
vec![vec![&3], vec![&2, &1]]
);
assert_eq!(
CGA::solve(3, vec![&1, &3, &2]),
cga::solve(3, vec![&1, &3, &2]),
vec![vec![&1], vec![&3], vec![&2]]
);
assert_eq!(
CGA::solve(4, vec![&1, &3, &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]),
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]),
cga::solve(4, vec![&8, &4, &7, &5, &6]),
vec![vec![&6], vec![&7], vec![&8], vec![&5, &4]]
);
}
#[test]
fn test_cga_big() {
#[bench]
fn test_cga_big(b: &mut Bencher) {
// random big numbers, to avoid perfect partition
assert_eq!(
CGA::solve(
8,
b.iter(|| {
assert_eq!(
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,
]
),
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,
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![
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]
]
);
)
});
}
#[bench]
fn test_cga_many(b: &mut Bencher) {
// random small numbers, realistic in some applications
assert_eq!(
CGA::solve(
8,
b.iter(|| {
assert_eq!(
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,
]
),
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,
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![
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