Skip to content
This repository was archived by the owner on Nov 21, 2018. It is now read-only.

Commit 56ce552

Browse files
committed
Add pathalogical parser benchmark
1 parent 9a26982 commit 56ce552

File tree

12 files changed

+710
-4
lines changed

12 files changed

+710
-4
lines changed

inflate-0.1.0/Cargo.lock

Lines changed: 0 additions & 4 deletions
This file was deleted.

jld-day15-parser/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "day15"
3+
version = "0.1.0"
4+
authors = ["Jed Davis <[email protected]>"]
5+
[dependencies]
6+
combine = "1.2.0"

jld-day15-parser/makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
all:
2+
$(CARGO_BUILD)
3+
touch:
4+
rm target/debug/*
5+
clean:
6+
rm target -rf
7+
rm Cargo.lock

jld-day15-parser/src/main.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extern crate combine;
2+
3+
mod parser;
4+
5+
pub type Num = i64;
6+
7+
pub struct Stats {
8+
pub capacity: Num,
9+
pub durability: Num,
10+
pub flavor: Num,
11+
pub texture: Num,
12+
pub calories: Num,
13+
}
14+
impl Stats {
15+
fn zero() -> Stats {
16+
Stats { capacity: 0, durability: 0, flavor: 0, texture: 0, calories: 0 }
17+
}
18+
}
19+
20+
fn main() {
21+
println!("Hello, world!");
22+
}

jld-day15-parser/src/parser.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::collections::HashMap;
2+
use std::iter::FromIterator;
3+
use std::str::FromStr;
4+
5+
use combine::{digit,letter,sep_by,many1,char,string,not_followed_by,any,
6+
Parser,ParserExt,ParseError};
7+
8+
use ::{Num,Stats};
9+
10+
pub enum SemanticError {
11+
DupStat(String, Num, Num),
12+
MissingStat(&'static str),
13+
}
14+
pub type SyntaxError<'a> = ParseError<&'a str>;
15+
16+
struct MaybeStats(Result<Stats, SemanticError>);
17+
impl FromIterator<(String,Num)> for MaybeStats {
18+
fn from_iter<T>(ii: T) -> Self where T: IntoIterator<Item=(String,Num)> {
19+
let squash_plist = move || {
20+
let mut tab: HashMap<String,Num> = HashMap::new();
21+
for (key, val) in ii {
22+
if let Some(oldval) = tab.insert(key.clone(), val) {
23+
return Err(SemanticError::DupStat(key, oldval, val));
24+
}
25+
}
26+
let get = |key| {
27+
tab.get(key).ok_or(SemanticError::MissingStat(key))
28+
};
29+
Ok(Stats {
30+
capacity: *try!(get("capacity")),
31+
durability: *try!(get("durability")),
32+
flavor: *try!(get("flavor")),
33+
texture: *try!(get("texture")),
34+
calories: *try!(get("calories")),
35+
})
36+
};
37+
MaybeStats(squash_plist())
38+
}
39+
}
40+
41+
pub fn parse(s: &str) -> Result<(String, Result<Stats, SemanticError>), SyntaxError> {
42+
let num = many1(digit().or(char('-'))).and_then(|s: String| Num::from_str(&s));
43+
let prop = (many1(letter())).skip(char(' ')).and(num);
44+
let plist = sep_by::<MaybeStats, _, _>(prop, string(", "));
45+
let mut ingred = many1(letter()).skip(string(": ")).and(plist).skip(not_followed_by(any()));
46+
47+
let ((name, MaybeStats(ms)), rest) = try!(ingred.parse(s));
48+
assert!(rest == "");
49+
Ok((name, ms))
50+
}

jld-day15-parser/src/search.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::cmp::{min,max};
2+
3+
use util::best;
4+
use ::{Stats,Num,Qty};
5+
6+
type Best = best::Best<Num, Vec<Qty>, best::Largest>;
7+
8+
trait CookieMonitor {
9+
fn judge(&self, after: usize, left: Qty, acc: &Stats) -> bool;
10+
}
11+
12+
struct Whatever;
13+
impl CookieMonitor for Whatever {
14+
fn judge(&self, _after: usize, _left: Qty, _acc: &Stats) -> bool {
15+
true
16+
}
17+
}
18+
19+
struct CalorieCounter {
20+
mincals: Vec<Num>,
21+
maxcals: Vec<Num>,
22+
target: Num,
23+
}
24+
impl CalorieCounter {
25+
fn new(stats: &[Stats], target: Num) -> CalorieCounter {
26+
let c0 = stats[0].calories;
27+
let (imin, imax) = stats.iter().scan((c0, c0), |state, stat| {
28+
let (lmin, lmax) = *state;
29+
*state = (min(lmin, stat.calories), max(lmax, stat.calories));
30+
Some(*state)
31+
}).unzip();
32+
CalorieCounter {
33+
mincals: imin,
34+
maxcals: imax,
35+
target: target
36+
}
37+
}
38+
}
39+
impl CookieMonitor for CalorieCounter {
40+
fn judge(&self, after: usize, left: Qty, acc: &Stats) -> bool {
41+
let left = Num::from(left);
42+
let rest = self.target - acc.calories;
43+
rest >= self.mincals[after] * left && rest <= self.maxcals[after] * left
44+
}
45+
}
46+
47+
struct ExhCtx<'s> {
48+
stats: &'s [Stats],
49+
qtys: Vec<Qty>,
50+
best: Best,
51+
}
52+
53+
fn exh_recur<M: CookieMonitor>(ctx: &mut ExhCtx, mon: &M, i: usize, left: Qty, acc: Stats) {
54+
if !mon.judge(i, left, &acc) {
55+
return;
56+
}
57+
if i == 0 {
58+
ctx.qtys[i] = left;
59+
ctx.best.add((acc + ctx.stats[i].clone() * left).eval(), &ctx.qtys);
60+
} else {
61+
for this in 0..(left+1) {
62+
ctx.qtys[i] = this;
63+
exh_recur(ctx, mon, i - 1, left - this, acc.clone() + ctx.stats[i].clone() * this);
64+
}
65+
}
66+
}
67+
68+
pub fn exhaustive(stats: &[Stats], total: Qty, opt_cals: Option<Num>) -> (Num, Vec<Qty>) {
69+
assert!(stats.len() >= 1);
70+
let mut ctx = ExhCtx {
71+
stats: stats,
72+
qtys: vec![!0; stats.len()],
73+
best: Best::new(best::Largest),
74+
};
75+
let n1 = stats.len() - 1;
76+
match opt_cals {
77+
None => exh_recur(&mut ctx, &Whatever, n1, total, Stats::zero()),
78+
Some(cals) => {
79+
let mon = CalorieCounter::new(stats, cals);
80+
exh_recur(&mut ctx, &mon, n1, total, Stats::zero())
81+
},
82+
};
83+
ctx.best.unwrap()
84+
}
85+
86+
// Conjecture: this problem is amenable to hill-climbing. ...without
87+
// the part 2 addendum, at least. Probably still is even with it,
88+
// with a little more subtlety, since everything except the final
89+
// metric is linear.
90+
91+
#[cfg(test)]
92+
mod tests {
93+
use super::exhaustive;
94+
use ::{Stats};
95+
96+
#[test]
97+
fn example1() {
98+
let bt = Stats { capacity: -1, durability: -2, flavor: 6, texture: 3, calories: 8 };
99+
let cn = Stats { capacity: 2, durability: 3, flavor: -2, texture: -1, calories: 3 };
100+
assert_eq!(exhaustive(&[bt, cn], 100, None), (62842880, vec![44, 56]));
101+
}
102+
103+
#[test]
104+
fn example2() {
105+
let bt = Stats { capacity: -1, durability: -2, flavor: 6, texture: 3, calories: 8 };
106+
let cn = Stats { capacity: 2, durability: 3, flavor: -2, texture: -1, calories: 3 };
107+
assert_eq!(exhaustive(&[bt, cn], 100, Some(500)), (57600000, vec![40, 60]));
108+
}
109+
}

jld-day15-parser/src/util/autovec.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::ops::Deref;
2+
3+
#[derive(Debug, Clone)]
4+
pub struct AutoVec<T: Default>(Vec<T>);
5+
6+
impl<T: Default> AutoVec<T> {
7+
pub fn new() -> Self { AutoVec(Vec::new()) }
8+
fn ensure_len(&mut self, len: usize) {
9+
while len > self.0.len() {
10+
self.0.push(T::default());
11+
}
12+
}
13+
pub fn into_boxed_slice(mut self, len: usize) -> Box<[T]> {
14+
self.ensure_len(len);
15+
self.0.into_boxed_slice()
16+
}
17+
pub fn at(&mut self, i: usize) -> &mut T {
18+
self.ensure_len(i + 1);
19+
&mut self.0[i]
20+
}
21+
}
22+
23+
impl<T: Default> Default for AutoVec<T> {
24+
fn default() -> Self {
25+
Self::new()
26+
}
27+
}
28+
29+
impl <T: Default> Deref for AutoVec<T> {
30+
type Target = Vec<T>;
31+
fn deref(&self) -> &Vec<T> {
32+
&self.0
33+
}
34+
}
35+
36+
impl <T: Default> IntoIterator for AutoVec<T> {
37+
type Item = T;
38+
type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
39+
fn into_iter(self) -> Self::IntoIter {
40+
self.0.into_iter()
41+
}
42+
}
43+
44+
#[cfg(test)]
45+
mod tests {
46+
use super::AutoVec;
47+
48+
#[test]
49+
fn empty() {
50+
let v: AutoVec<i32> = AutoVec::new();
51+
assert_eq!(v.0, vec![]);
52+
}
53+
54+
#[test]
55+
fn one() {
56+
let mut v = AutoVec::new();
57+
*v.at(0) = 17;
58+
assert_eq!(v.0, vec![17]);
59+
}
60+
61+
#[test]
62+
fn two() {
63+
let mut v = AutoVec::new();
64+
*v.at(1) = 17;
65+
assert_eq!(*v, vec![0, 17]);
66+
*v.at(0) = 23;
67+
assert_eq!(v.0, vec![23, 17]);
68+
}
69+
70+
#[test]
71+
fn sadness() {
72+
let mut v = AutoVec::new();
73+
let _: &mut i32 = v.at(5);
74+
assert_eq!(v.0, vec![0,0,0,0,0,0]);
75+
}
76+
77+
#[test]
78+
fn autoderef() {
79+
let mut v = AutoVec::new();
80+
assert_eq!(v.len(), 0);
81+
*v.at(3) = 1000;
82+
assert_eq!(v.iter().collect::<Vec<_>>(), vec![&0, &0, &0, &1000]);
83+
}
84+
85+
#[test]
86+
fn move_iter() {
87+
let mut v = AutoVec::new();
88+
*v.at(3) = 1000;
89+
assert_eq!(v.into_iter().collect::<Vec<_>>(), vec![0, 0, 0, 1000]);
90+
}
91+
}

0 commit comments

Comments
 (0)