Skip to content

Commit fb87734

Browse files
committed
auto merge of #14063 : TeXitoi/rust/shootout-meteor-improvement, r=pcwalton
- 5-10% of raw speedup - parallelization of the search
2 parents e3c62a2 + 3fa293c commit fb87734

File tree

1 file changed

+111
-90
lines changed

1 file changed

+111
-90
lines changed

src/test/bench/shootout-meteor.rs

+111-90
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -8,11 +8,18 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(phase)]
12+
#[phase(syntax)] extern crate green;
13+
extern crate sync;
14+
15+
use sync::Arc;
16+
17+
green_start!(main)
18+
1119
//
1220
// Utilities.
1321
//
1422

15-
1623
// returns an infinite iterator of repeated applications of f to x,
1724
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
1825
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<Vec<(int, int)>> {
93100
// Takes a piece with minimum coordinate (0, 0) (as generated by
94101
// transform). Returns the corresponding mask if p translated by (dy,
95102
// dx) is on the board.
96-
fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option<u64> {
103+
fn mask(dy: int, dx: int, id: uint, p: &Vec<(int, int)>) -> Option<u64> {
97104
let mut m = 1 << (50 + id);
98105
for &(y, x) in p.iter() {
99106
let x = x + dx + (y + (dy % 2)) / 2;
@@ -105,7 +112,7 @@ fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option<u64> {
105112
Some(m)
106113
}
107114

108-
// Makes every possible masks. masks[id][i] correspond to every
115+
// Makes every possible masks. masks[i][id] correspond to every
109116
// possible masks for piece with identifier id with minimum coordinate
110117
// (i/5, i%5).
111118
fn make_masks() -> Vec<Vec<Vec<u64> > > {
@@ -120,168 +127,182 @@ fn make_masks() -> Vec<Vec<Vec<u64> > > {
120127
vec!((0,0),(0,1),(0,2),(1,0),(1,2)),
121128
vec!((0,0),(0,1),(0,2),(1,2),(1,3)),
122129
vec!((0,0),(0,1),(0,2),(0,3),(1,2)));
123-
let mut res = Vec::new();
124-
for (id, p) in pieces.move_iter().enumerate() {
125-
// To break the central symetry of the problem, every
126-
// transformation must be taken except for one piece (piece 3
127-
// here).
128-
let trans = transform(p, id != 3);
129-
let mut cur_piece = Vec::new();
130-
for dy in range(0, 10) {
131-
for dx in range(0, 5) {
132-
let masks =
133-
trans.iter()
134-
.filter_map(|t| mask(dy, dx, id, t.as_slice()))
135-
.collect();
136-
cur_piece.push(masks);
137-
}
138-
}
139-
res.push(cur_piece);
140-
}
141-
res
130+
131+
// To break the central symetry of the problem, every
132+
// transformation must be taken except for one piece (piece 3
133+
// here).
134+
let transforms: Vec<Vec<Vec<(int, int)>>> =
135+
pieces.move_iter().enumerate()
136+
.map(|(id, p)| transform(p, id != 3))
137+
.collect();
138+
139+
range(0, 50).map(|yx| {
140+
transforms.iter().enumerate().map(|(id, t)| {
141+
t.iter().filter_map(|p| mask(yx / 5, yx % 5, id, p)).collect()
142+
}).collect()
143+
}).collect()
142144
}
143145

144146
// Check if all coordinates can be covered by an unused piece and that
145147
// all unused piece can be placed on the board.
146-
fn is_board_unfeasible(board: u64, masks: &[Vec<Vec<u64> > ]) -> bool {
148+
fn is_board_unfeasible(board: u64, masks: &Vec<Vec<Vec<u64>>>) -> bool {
147149
let mut coverable = board;
148-
for i in range(0, 50).filter(|&i| board & 1 << i == 0) {
149-
for (cur_id, pos_masks) in masks.iter().enumerate() {
150-
if board & 1 << (50 + cur_id) != 0 {continue;}
151-
for &cur_m in pos_masks.get(i as uint).iter() {
152-
if cur_m & board == 0 {coverable |= cur_m;}
150+
for (i, masks_at) in masks.iter().enumerate() {
151+
if board & 1 << i != 0 { continue; }
152+
for (cur_id, pos_masks) in masks_at.iter().enumerate() {
153+
if board & 1 << (50 + cur_id) != 0 { continue; }
154+
for &cur_m in pos_masks.iter() {
155+
if cur_m & board != 0 { continue; }
156+
coverable |= cur_m;
157+
// if every coordinates can be covered and every
158+
// piece can be used.
159+
if coverable == (1 << 60) - 1 { return false; }
153160
}
154161
}
155-
if coverable & (1 << i) == 0 {return true;}
162+
if coverable & 1 << i == 0 { return true; }
156163
}
157-
// check if every coordinates can be covered and every piece can
158-
// be used.
159-
coverable != (1 << 60) - 1
164+
true
160165
}
161166

162167
// Filter the masks that we can prove to result to unfeasible board.
163-
fn filter_masks(masks: &[Vec<Vec<u64> > ]) -> Vec<Vec<Vec<u64> > > {
164-
masks.iter().map(
165-
|p| p.iter().map(
166-
|p| p.iter()
167-
.map(|&m| m)
168+
fn filter_masks(masks: &mut Vec<Vec<Vec<u64>>>) {
169+
for i in range(0, masks.len()) {
170+
for j in range(0, masks.get(i).len()) {
171+
*masks.get_mut(i).get_mut(j) =
172+
masks.get(i).get(j).iter().map(|&m| m)
168173
.filter(|&m| !is_board_unfeasible(m, masks))
169-
.collect())
170-
.collect())
171-
.collect()
174+
.collect();
175+
}
176+
}
172177
}
173178

174179
// Gets the identifier of a mask.
175180
fn get_id(m: u64) -> u8 {
176-
for id in range(0, 10) {
177-
if m & (1 << (id + 50)) != 0 {return id as u8;}
181+
for id in range(0u8, 10) {
182+
if m & (1 << (id + 50)) != 0 {return id;}
178183
}
179184
fail!("{:016x} does not have a valid identifier", m);
180185
}
181186

182187
// Converts a list of mask to a ~str.
183-
fn to_utf8(raw_sol: &List<u64>) -> ~str {
184-
let mut sol: Vec<u8> = Vec::from_elem(50, '.' as u8);
188+
fn to_vec(raw_sol: &List<u64>) -> Vec<u8> {
189+
let mut sol = Vec::from_elem(50, '.' as u8);
185190
for &m in raw_sol.iter() {
186-
let id = get_id(m);
187-
for i in range(0, 50) {
191+
let id = '0' as u8 + get_id(m);
192+
for i in range(0u, 50) {
188193
if m & 1 << i != 0 {
189-
*sol.get_mut(i as uint) = '0' as u8 + id;
194+
*sol.get_mut(i) = id;
190195
}
191196
}
192197
}
193-
std::str::from_utf8(sol.as_slice()).unwrap().to_owned()
198+
sol
194199
}
195200

196201
// Prints a solution in ~str form.
197-
fn print_sol(sol: &str) {
198-
for (i, c) in sol.chars().enumerate() {
202+
fn print_sol(sol: &Vec<u8>) {
203+
for (i, c) in sol.iter().enumerate() {
199204
if (i) % 5 == 0 { println!(""); }
200205
if (i + 5) % 10 == 0 { print!(" "); }
201-
print!("{} ", c);
206+
print!("{} ", *c as char);
202207
}
203208
println!("");
204209
}
205210

206211
// The data managed during the search
207212
struct Data {
208-
// If more than stop_after is found, stop the search.
209-
stop_after: int,
210213
// Number of solution found.
211214
nb: int,
212215
// Lexicographically minimal solution found.
213-
min: ~str,
216+
min: Vec<u8>,
214217
// Lexicographically maximal solution found.
215-
max: ~str
218+
max: Vec<u8>
219+
}
220+
impl Data {
221+
fn new() -> Data {
222+
Data {nb: 0, min: vec!(), max: vec!()}
223+
}
224+
fn reduce_from(&mut self, other: Data) {
225+
self.nb += other.nb;
226+
let Data { min: min, max: max, ..} = other;
227+
if min < self.min { self.min = min; }
228+
if max > self.max { self.max = max; }
229+
}
216230
}
217231

218232
// Records a new found solution. Returns false if the search must be
219233
// stopped.
220-
fn handle_sol(raw_sol: &List<u64>, data: &mut Data) -> bool {
234+
fn handle_sol(raw_sol: &List<u64>, data: &mut Data) {
221235
// because we break the symetry, 2 solutions correspond to a call
222236
// to this method: the normal solution, and the same solution in
223237
// reverse order, i.e. the board rotated by half a turn.
224238
data.nb += 2;
225-
let sol1 = to_utf8(raw_sol);
226-
let sol2: ~str = sol1.chars().rev().collect();
239+
let sol1 = to_vec(raw_sol);
240+
let sol2: Vec<u8> = sol1.iter().rev().map(|x| *x).collect();
227241

228242
if data.nb == 2 {
229243
data.min = sol1.clone();
230244
data.max = sol1.clone();
231245
}
232246

233-
if sol1 < data.min {data.min = sol1.clone();}
234-
if sol2 < data.min {data.min = sol2.clone();}
235-
if sol1 > data.max {data.max = sol1;}
236-
if sol2 > data.max {data.max = sol2;}
237-
data.nb < data.stop_after
247+
if sol1 < data.min {data.min = sol1;}
248+
else if sol1 > data.max {data.max = sol1;}
249+
if sol2 < data.min {data.min = sol2;}
250+
else if sol2 > data.max {data.max = sol2;}
238251
}
239252

240-
// Search for every solutions. Returns false if the search was
241-
// stopped before the end.
242253
fn search(
243-
masks: &[Vec<Vec<u64> > ],
254+
masks: &Vec<Vec<Vec<u64>>>,
244255
board: u64,
245-
mut i: int,
256+
mut i: uint,
246257
cur: List<u64>,
247258
data: &mut Data)
248-
-> bool
249259
{
250260
// Search for the lesser empty coordinate.
251261
while board & (1 << i) != 0 && i < 50 {i += 1;}
252262
// the board is full: a solution is found.
253263
if i >= 50 {return handle_sol(&cur, data);}
264+
let masks_at = masks.get(i);
254265

255266
// for every unused piece
256-
for id in range(0, 10).filter(|id| board & (1 << (id + 50)) == 0) {
267+
for id in range(0u, 10).filter(|id| board & (1 << (id + 50)) == 0) {
257268
// for each mask that fits on the board
258-
for &m in masks[id as uint].get(i as uint)
259-
.iter()
260-
.filter(|&m| board & *m == 0) {
269+
for &m in masks_at.get(id).iter().filter(|&m| board & *m == 0) {
261270
// This check is too costy.
262271
//if is_board_unfeasible(board | m, masks) {continue;}
263-
if !search(masks, board | m, i + 1, Cons(m, &cur), data) {
264-
return false;
265-
}
272+
search(masks, board | m, i + 1, Cons(m, &cur), data);
266273
}
267274
}
268-
return true;
275+
}
276+
277+
fn par_search(masks: Vec<Vec<Vec<u64>>>) -> Data {
278+
let masks = Arc::new(masks);
279+
let (tx, rx) = channel();
280+
281+
// launching the search in parallel on every masks at minimum
282+
// coordinate (0,0)
283+
for &m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) {
284+
let masks = masks.clone();
285+
let tx = tx.clone();
286+
spawn(proc() {
287+
let mut data = Data::new();
288+
search(&*masks, m, 1, Cons(m, &Nil), &mut data);
289+
tx.send(data);
290+
});
291+
}
292+
293+
// collecting the results
294+
drop(tx);
295+
let mut data = rx.recv();
296+
for d in rx.iter() { data.reduce_from(d); }
297+
data
269298
}
270299

271300
fn main () {
272-
let args = std::os::args();
273-
let args = args.as_slice();
274-
let stop_after = if args.len() <= 1 {
275-
2098
276-
} else {
277-
from_str(args[1]).unwrap()
278-
};
279-
let masks = make_masks();
280-
let masks = filter_masks(masks.as_slice());
281-
let mut data = Data {stop_after: stop_after, nb: 0, min: "".to_owned(), max: "".to_owned()};
282-
search(masks.as_slice(), 0, 0, Nil, &mut data);
301+
let mut masks = make_masks();
302+
filter_masks(&mut masks);
303+
let data = par_search(masks);
283304
println!("{} solutions found", data.nb);
284-
print_sol(data.min);
285-
print_sol(data.max);
305+
print_sol(&data.min);
306+
print_sol(&data.max);
286307
println!("");
287308
}

0 commit comments

Comments
 (0)