]> git.lizzy.rs Git - rust.git/blob - src/test/bench/shootout-fasta-redux.rs
auto merge of #21132 : sfackler/rust/wait_timeout, r=alexcrichton
[rust.git] / src / test / bench / shootout-fasta-redux.rs
1 // The Computer Language Benchmarks Game
2 // http://benchmarksgame.alioth.debian.org/
3 //
4 // contributed by the Rust Project Developers
5
6 // Copyright (c) 2013-2014 The Rust Project Developers
7 //
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 // - Redistributions of source code must retain the above copyright
15 //   notice, this list of conditions and the following disclaimer.
16 //
17 // - Redistributions in binary form must reproduce the above copyright
18 //   notice, this list of conditions and the following disclaimer in
19 //   the documentation and/or other materials provided with the
20 //   distribution.
21 //
22 // - Neither the name of "The Computer Language Benchmarks Game" nor
23 //   the name of "The Computer Language Shootout Benchmarks" nor the
24 //   names of its contributors may be used to endorse or promote
25 //   products derived from this software without specific prior
26 //   written permission.
27 //
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 // OF THE POSSIBILITY OF SUCH DAMAGE.
40
41 use std::cmp::min;
42 use std::io::{stdout, IoResult};
43 use std::iter::repeat;
44 use std::os;
45 use std::slice::bytes::copy_memory;
46
47 const LINE_LEN: uint = 60;
48 const LOOKUP_SIZE: uint = 4 * 1024;
49 const LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32;
50
51 // Random number generator constants
52 const IM: u32 = 139968;
53 const IA: u32 = 3877;
54 const IC: u32 = 29573;
55
56 const ALU: &'static str = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG\
57                             GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA\
58                             GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA\
59                             AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\
60                             CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC\
61                             CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG\
62                             CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
63
64 const NULL_AMINO_ACID: AminoAcid = AminoAcid { c: ' ' as u8, p: 0.0 };
65
66 static IUB: [AminoAcid;15] = [
67     AminoAcid { c: 'a' as u8, p: 0.27 },
68     AminoAcid { c: 'c' as u8, p: 0.12 },
69     AminoAcid { c: 'g' as u8, p: 0.12 },
70     AminoAcid { c: 't' as u8, p: 0.27 },
71     AminoAcid { c: 'B' as u8, p: 0.02 },
72     AminoAcid { c: 'D' as u8, p: 0.02 },
73     AminoAcid { c: 'H' as u8, p: 0.02 },
74     AminoAcid { c: 'K' as u8, p: 0.02 },
75     AminoAcid { c: 'M' as u8, p: 0.02 },
76     AminoAcid { c: 'N' as u8, p: 0.02 },
77     AminoAcid { c: 'R' as u8, p: 0.02 },
78     AminoAcid { c: 'S' as u8, p: 0.02 },
79     AminoAcid { c: 'V' as u8, p: 0.02 },
80     AminoAcid { c: 'W' as u8, p: 0.02 },
81     AminoAcid { c: 'Y' as u8, p: 0.02 },
82 ];
83
84 static HOMO_SAPIENS: [AminoAcid;4] = [
85     AminoAcid { c: 'a' as u8, p: 0.3029549426680 },
86     AminoAcid { c: 'c' as u8, p: 0.1979883004921 },
87     AminoAcid { c: 'g' as u8, p: 0.1975473066391 },
88     AminoAcid { c: 't' as u8, p: 0.3015094502008 },
89 ];
90
91 // FIXME: Use map().
92 fn sum_and_scale(a: &'static [AminoAcid]) -> Vec<AminoAcid> {
93     let mut result = Vec::new();
94     let mut p = 0f32;
95     for a_i in a.iter() {
96         let mut a_i = *a_i;
97         p += a_i.p;
98         a_i.p = p * LOOKUP_SCALE;
99         result.push(a_i);
100     }
101     let result_len = result.len();
102     result[result_len - 1].p = LOOKUP_SCALE;
103     result
104 }
105
106 struct AminoAcid {
107     c: u8,
108     p: f32,
109 }
110
111 impl Copy for AminoAcid {}
112
113 struct RepeatFasta<'a, W:'a> {
114     alu: &'static str,
115     out: &'a mut W
116 }
117
118 impl<'a, W: Writer> RepeatFasta<'a, W> {
119     fn new(alu: &'static str, w: &'a mut W) -> RepeatFasta<'a, W> {
120         RepeatFasta { alu: alu, out: w }
121     }
122
123     fn make(&mut self, n: uint) -> IoResult<()> {
124         let alu_len = self.alu.len();
125         let mut buf = repeat(0u8).take(alu_len + LINE_LEN).collect::<Vec<_>>();
126         let alu: &[u8] = self.alu.as_bytes();
127
128         copy_memory(buf.as_mut_slice(), alu);
129         let buf_len = buf.len();
130         copy_memory(buf.slice_mut(alu_len, buf_len),
131                     &alu[..LINE_LEN]);
132
133         let mut pos = 0;
134         let mut bytes;
135         let mut n = n;
136         while n > 0 {
137             bytes = min(LINE_LEN, n);
138             try!(self.out.write(buf.slice(pos, pos + bytes)));
139             try!(self.out.write_u8('\n' as u8));
140             pos += bytes;
141             if pos > alu_len {
142                 pos -= alu_len;
143             }
144             n -= bytes;
145         }
146         Ok(())
147     }
148 }
149
150 fn make_lookup(a: &[AminoAcid]) -> [AminoAcid;LOOKUP_SIZE] {
151     let mut lookup = [ NULL_AMINO_ACID;LOOKUP_SIZE ];
152     let mut j = 0;
153     for (i, slot) in lookup.iter_mut().enumerate() {
154         while a[j].p < (i as f32) {
155             j += 1;
156         }
157         *slot = a[j];
158     }
159     lookup
160 }
161
162 struct RandomFasta<'a, W:'a> {
163     seed: u32,
164     lookup: [AminoAcid;LOOKUP_SIZE],
165     out: &'a mut W,
166 }
167
168 impl<'a, W: Writer> RandomFasta<'a, W> {
169     fn new(w: &'a mut W, a: &[AminoAcid]) -> RandomFasta<'a, W> {
170         RandomFasta {
171             seed: 42,
172             out: w,
173             lookup: make_lookup(a),
174         }
175     }
176
177     fn rng(&mut self, max: f32) -> f32 {
178         self.seed = (self.seed * IA + IC) % IM;
179         max * (self.seed as f32) / (IM as f32)
180     }
181
182     fn nextc(&mut self) -> u8 {
183         let r = self.rng(1.0);
184         for a in self.lookup.iter() {
185             if a.p >= r {
186                 return a.c;
187             }
188         }
189         0
190     }
191
192     fn make(&mut self, n: uint) -> IoResult<()> {
193         let lines = n / LINE_LEN;
194         let chars_left = n % LINE_LEN;
195         let mut buf = [0;LINE_LEN + 1];
196
197         for _ in range(0, lines) {
198             for i in range(0u, LINE_LEN) {
199                 buf[i] = self.nextc();
200             }
201             buf[LINE_LEN] = '\n' as u8;
202             try!(self.out.write(&buf));
203         }
204         for i in range(0u, chars_left) {
205             buf[i] = self.nextc();
206         }
207         self.out.write(&buf[..chars_left])
208     }
209 }
210
211 fn main() {
212     let args = os::args();
213     let args = args.as_slice();
214     let n = if args.len() > 1 {
215         args[1].parse::<uint>().unwrap()
216     } else {
217         5
218     };
219
220     let mut out = stdout();
221
222     out.write_line(">ONE Homo sapiens alu").unwrap();
223     {
224         let mut repeat = RepeatFasta::new(ALU, &mut out);
225         repeat.make(n * 2).unwrap();
226     }
227
228     out.write_line(">TWO IUB ambiguity codes").unwrap();
229     let iub = sum_and_scale(&IUB);
230     let mut random = RandomFasta::new(&mut out, iub.as_slice());
231     random.make(n * 3).unwrap();
232
233     random.out.write_line(">THREE Homo sapiens frequency").unwrap();
234     let homo_sapiens = sum_and_scale(&HOMO_SAPIENS);
235     random.lookup = make_lookup(homo_sapiens.as_slice());
236     random.make(n * 5).unwrap();
237
238     random.out.write_str("\n").unwrap();
239 }