diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index cb46c542f5bc8..45f8b1b9a839c 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,11 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(phase)] +#[phase(syntax)] extern crate green; +extern crate sync; + +use sync::Arc; + +green_start!(main) + // // Utilities. // - // returns an infinite iterator of repeated applications of f to x, // i.e. [x, f(x), f(f(x)), ...], as haskell iterate function. fn iterate<'a, T>(x: T, f: |&T|: 'a -> T) -> Iterate<'a, T> { @@ -93,7 +100,7 @@ fn transform(piece: Vec<(int, int)> , all: bool) -> Vec> { // Takes a piece with minimum coordinate (0, 0) (as generated by // transform). Returns the corresponding mask if p translated by (dy, // dx) is on the board. -fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option { +fn mask(dy: int, dx: int, id: uint, p: &Vec<(int, int)>) -> Option { let mut m = 1 << (50 + id); for &(y, x) in p.iter() { let x = x + dx + (y + (dy % 2)) / 2; @@ -105,7 +112,7 @@ fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option { Some(m) } -// Makes every possible masks. masks[id][i] correspond to every +// Makes every possible masks. masks[i][id] correspond to every // possible masks for piece with identifier id with minimum coordinate // (i/5, i%5). fn make_masks() -> Vec > > { @@ -120,168 +127,182 @@ fn make_masks() -> Vec > > { vec!((0,0),(0,1),(0,2),(1,0),(1,2)), vec!((0,0),(0,1),(0,2),(1,2),(1,3)), vec!((0,0),(0,1),(0,2),(0,3),(1,2))); - let mut res = Vec::new(); - for (id, p) in pieces.move_iter().enumerate() { - // To break the central symetry of the problem, every - // transformation must be taken except for one piece (piece 3 - // here). - let trans = transform(p, id != 3); - let mut cur_piece = Vec::new(); - for dy in range(0, 10) { - for dx in range(0, 5) { - let masks = - trans.iter() - .filter_map(|t| mask(dy, dx, id, t.as_slice())) - .collect(); - cur_piece.push(masks); - } - } - res.push(cur_piece); - } - res + + // To break the central symetry of the problem, every + // transformation must be taken except for one piece (piece 3 + // here). + let transforms: Vec>> = + pieces.move_iter().enumerate() + .map(|(id, p)| transform(p, id != 3)) + .collect(); + + range(0, 50).map(|yx| { + transforms.iter().enumerate().map(|(id, t)| { + t.iter().filter_map(|p| mask(yx / 5, yx % 5, id, p)).collect() + }).collect() + }).collect() } // Check if all coordinates can be covered by an unused piece and that // all unused piece can be placed on the board. -fn is_board_unfeasible(board: u64, masks: &[Vec > ]) -> bool { +fn is_board_unfeasible(board: u64, masks: &Vec>>) -> bool { let mut coverable = board; - for i in range(0, 50).filter(|&i| board & 1 << i == 0) { - for (cur_id, pos_masks) in masks.iter().enumerate() { - if board & 1 << (50 + cur_id) != 0 {continue;} - for &cur_m in pos_masks.get(i as uint).iter() { - if cur_m & board == 0 {coverable |= cur_m;} + for (i, masks_at) in masks.iter().enumerate() { + if board & 1 << i != 0 { continue; } + for (cur_id, pos_masks) in masks_at.iter().enumerate() { + if board & 1 << (50 + cur_id) != 0 { continue; } + for &cur_m in pos_masks.iter() { + if cur_m & board != 0 { continue; } + coverable |= cur_m; + // if every coordinates can be covered and every + // piece can be used. + if coverable == (1 << 60) - 1 { return false; } } } - if coverable & (1 << i) == 0 {return true;} + if coverable & 1 << i == 0 { return true; } } - // check if every coordinates can be covered and every piece can - // be used. - coverable != (1 << 60) - 1 + true } // Filter the masks that we can prove to result to unfeasible board. -fn filter_masks(masks: &[Vec > ]) -> Vec > > { - masks.iter().map( - |p| p.iter().map( - |p| p.iter() - .map(|&m| m) +fn filter_masks(masks: &mut Vec>>) { + for i in range(0, masks.len()) { + for j in range(0, masks.get(i).len()) { + *masks.get_mut(i).get_mut(j) = + masks.get(i).get(j).iter().map(|&m| m) .filter(|&m| !is_board_unfeasible(m, masks)) - .collect()) - .collect()) - .collect() + .collect(); + } + } } // Gets the identifier of a mask. fn get_id(m: u64) -> u8 { - for id in range(0, 10) { - if m & (1 << (id + 50)) != 0 {return id as u8;} + for id in range(0u8, 10) { + if m & (1 << (id + 50)) != 0 {return id;} } fail!("{:016x} does not have a valid identifier", m); } // Converts a list of mask to a ~str. -fn to_utf8(raw_sol: &List) -> ~str { - let mut sol: Vec = Vec::from_elem(50, '.' as u8); +fn to_vec(raw_sol: &List) -> Vec { + let mut sol = Vec::from_elem(50, '.' as u8); for &m in raw_sol.iter() { - let id = get_id(m); - for i in range(0, 50) { + let id = '0' as u8 + get_id(m); + for i in range(0u, 50) { if m & 1 << i != 0 { - *sol.get_mut(i as uint) = '0' as u8 + id; + *sol.get_mut(i) = id; } } } - std::str::from_utf8(sol.as_slice()).unwrap().to_owned() + sol } // Prints a solution in ~str form. -fn print_sol(sol: &str) { - for (i, c) in sol.chars().enumerate() { +fn print_sol(sol: &Vec) { + for (i, c) in sol.iter().enumerate() { if (i) % 5 == 0 { println!(""); } if (i + 5) % 10 == 0 { print!(" "); } - print!("{} ", c); + print!("{} ", *c as char); } println!(""); } // The data managed during the search struct Data { - // If more than stop_after is found, stop the search. - stop_after: int, // Number of solution found. nb: int, // Lexicographically minimal solution found. - min: ~str, + min: Vec, // Lexicographically maximal solution found. - max: ~str + max: Vec +} +impl Data { + fn new() -> Data { + Data {nb: 0, min: vec!(), max: vec!()} + } + fn reduce_from(&mut self, other: Data) { + self.nb += other.nb; + let Data { min: min, max: max, ..} = other; + if min < self.min { self.min = min; } + if max > self.max { self.max = max; } + } } // Records a new found solution. Returns false if the search must be // stopped. -fn handle_sol(raw_sol: &List, data: &mut Data) -> bool { +fn handle_sol(raw_sol: &List, data: &mut Data) { // because we break the symetry, 2 solutions correspond to a call // to this method: the normal solution, and the same solution in // reverse order, i.e. the board rotated by half a turn. data.nb += 2; - let sol1 = to_utf8(raw_sol); - let sol2: ~str = sol1.chars().rev().collect(); + let sol1 = to_vec(raw_sol); + let sol2: Vec = sol1.iter().rev().map(|x| *x).collect(); if data.nb == 2 { data.min = sol1.clone(); data.max = sol1.clone(); } - if sol1 < data.min {data.min = sol1.clone();} - if sol2 < data.min {data.min = sol2.clone();} - if sol1 > data.max {data.max = sol1;} - if sol2 > data.max {data.max = sol2;} - data.nb < data.stop_after + if sol1 < data.min {data.min = sol1;} + else if sol1 > data.max {data.max = sol1;} + if sol2 < data.min {data.min = sol2;} + else if sol2 > data.max {data.max = sol2;} } -// Search for every solutions. Returns false if the search was -// stopped before the end. fn search( - masks: &[Vec > ], + masks: &Vec>>, board: u64, - mut i: int, + mut i: uint, cur: List, data: &mut Data) - -> bool { // Search for the lesser empty coordinate. while board & (1 << i) != 0 && i < 50 {i += 1;} // the board is full: a solution is found. if i >= 50 {return handle_sol(&cur, data);} + let masks_at = masks.get(i); // for every unused piece - for id in range(0, 10).filter(|id| board & (1 << (id + 50)) == 0) { + for id in range(0u, 10).filter(|id| board & (1 << (id + 50)) == 0) { // for each mask that fits on the board - for &m in masks[id as uint].get(i as uint) - .iter() - .filter(|&m| board & *m == 0) { + for &m in masks_at.get(id).iter().filter(|&m| board & *m == 0) { // This check is too costy. //if is_board_unfeasible(board | m, masks) {continue;} - if !search(masks, board | m, i + 1, Cons(m, &cur), data) { - return false; - } + search(masks, board | m, i + 1, Cons(m, &cur), data); } } - return true; +} + +fn par_search(masks: Vec>>) -> Data { + let masks = Arc::new(masks); + let (tx, rx) = channel(); + + // launching the search in parallel on every masks at minimum + // coordinate (0,0) + for &m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) { + let masks = masks.clone(); + let tx = tx.clone(); + spawn(proc() { + let mut data = Data::new(); + search(&*masks, m, 1, Cons(m, &Nil), &mut data); + tx.send(data); + }); + } + + // collecting the results + drop(tx); + let mut data = rx.recv(); + for d in rx.iter() { data.reduce_from(d); } + data } fn main () { - let args = std::os::args(); - let args = args.as_slice(); - let stop_after = if args.len() <= 1 { - 2098 - } else { - from_str(args[1]).unwrap() - }; - let masks = make_masks(); - let masks = filter_masks(masks.as_slice()); - let mut data = Data {stop_after: stop_after, nb: 0, min: "".to_owned(), max: "".to_owned()}; - search(masks.as_slice(), 0, 0, Nil, &mut data); + let mut masks = make_masks(); + filter_masks(&mut masks); + let data = par_search(masks); println!("{} solutions found", data.nb); - print_sol(data.min); - print_sol(data.max); + print_sol(&data.min); + print_sol(&data.max); println!(""); }