adapton_lab/
labrun.rs

1extern crate time;
2extern crate rand;
3
4use std::fmt::Debug;
5use labdef::*;
6use std::marker::PhantomData;
7
8use adapton::engine::*;
9use adapton::reflect;
10use adapton::engine::manage::*;
11use rand::{Rng, SeedableRng};
12use std::mem::swap;
13
14pub trait SampleGen {
15  fn sample(self:&mut Self) -> Option<Sample>;
16}
17
18pub struct LabEngineState<Input,EditSt,Output,
19                           Editor:Generate<Input>+Edit<Input,EditSt>,
20                           Archivist:ComputeDemand<Input,Output>> {
21  pub engine:   Engine,
22  pub input:    Option<(Input,EditSt)>,
23  inputdist:    PhantomData<Editor>,
24  computer:     PhantomData<Archivist>,
25  output:       PhantomData<Output>,
26}
27
28pub struct LabState<R:Rng+Clone,
29                     Input,EditSt,Output,
30                     Editor:Generate<Input>+Edit<Input,EditSt>,
31                     Archivist:ComputeDemand<Input,Output>> {
32  pub params:           LabParams,
33  pub rng:              Box<R>,
34  pub change_batch_num: usize,
35  pub dcg_state:   LabEngineState<Input,EditSt,Output,Editor,Archivist>,
36  pub naive_state: LabEngineState<Input,EditSt,Output,Editor,Archivist>,
37  pub samples:     Vec<Sample>,
38}
39
40      
41fn get_engine_metrics<X,F:FnOnce() -> X> (params:&SampleParams, thunk:F) -> (X,EngineMetrics)
42{
43  if params.reflect_trace { reflect::dcg_reflect_begin(); };
44  let time_start = time::precise_time_ns();
45  let x = (thunk)();
46  let time_end = time::precise_time_ns();
47  let traces = if params.reflect_trace { reflect::dcg_reflect_end() } else { vec![ ] };
48  let dcg    = if params.reflect_dcg   { reflect::dcg_reflect_now() } else { None };
49  return (x, EngineMetrics{
50    time_ns:time_end - time_start,
51    //engine_cnt:cnt,
52    reflect_traces:traces,
53    reflect_dcg:dcg,
54  })
55}
56
57fn get_engine_sample
58  <R:Rng+Clone,
59   Input:Clone+Debug,
60   EditSt,Output:Debug,   
61   Editor:Generate<Input>+Edit<Input,EditSt>,
62   Archivist:ComputeDemand<Input,Output>
63   > 
64  (rng:&mut R, params:&SampleParams, input:Option<(Input,EditSt)>) -> (Output,Input,EditSt,EngineSample) 
65{
66  let mut rng2 = rng;
67  
68  let ((edited_input, editst), process_input) : ((Input,EditSt),EngineMetrics) = 
69    match input {
70      None => 
71        get_engine_metrics( params,
72          move || ( Editor::generate(&mut rng2, &params.generate_params), 
73                    Editor::edit_init(&mut rng2, &params.generate_params ))),
74      Some((input, editst)) => 
75        get_engine_metrics( params,
76          move || Editor::edit(input, editst, &mut rng2, &params.generate_params))
77    };
78
79  let input2  = edited_input.clone();
80  
81  let input2r = 
82    if params.reflect_dcg { 
83      Some(reflect::reflect_val(&input2)) 
84    } else { None };
85
86  let (output, compute_output): (Output,EngineMetrics) 
87    = ns(name_of_str("compute"),
88         move || 
89         get_engine_metrics( 
90           params, move || 
91             Archivist::compute(input2, params.demand) 
92         ));
93
94  let outputr = 
95    if params.reflect_dcg { 
96      Some(reflect::reflect_val(&output)) 
97    } else { None };
98  
99  let engine_sample = EngineSample{
100    process_input,
101    input: input2r,
102    compute_output,
103    output: outputr,
104  };
105
106  return (output, edited_input, editst, engine_sample)
107}
108
109fn get_sample_gen
110  <Input:Clone+Debug,
111   EditSt,
112   Output:Eq+Debug,
113   Editor:Generate<Input>+Edit<Input,EditSt>,
114   Archivist:ComputeDemand<Input,Output>> 
115  (params:&LabParams) 
116   -> LabState<rand::StdRng,Input,EditSt,Output,Editor,Archivist> 
117{
118  // Create empty DCG; TODO-Minor-- Make the API for this better.
119  let _ = init_dcg(); assert!(engine_is_dcg());
120  let empty_dcg = use_engine(Engine::Naive); // TODO-Minor: Rename this operation: "engine_swap" or something 
121  let rng = SeedableRng::from_seed(params.sample_params.input_seeds.as_slice());
122  //let editst_init = Editor::edit_init(&mut rng, & params.sample_params.generate_params);
123  LabState{
124    params:params.clone(),
125    rng:Box::new(rng),
126    dcg_state:LabEngineState{
127      input:  None,
128      engine: empty_dcg, // empty DCG      
129      output: PhantomData, inputdist: PhantomData, computer: PhantomData,      
130    },
131    naive_state:LabEngineState{
132      input:  None,
133      engine: Engine::Naive, // A constant
134      output: PhantomData, inputdist: PhantomData, computer: PhantomData,
135    },
136    change_batch_num: 0,
137    samples:vec![],
138  }
139}
140
141/// Advances the LabState forward by one sample of each engine.  For
142/// each engine, we process the current input (either generating it,
143/// or editing it) and we compute a new output over this processed input.
144/// Optionally, we compare the outputs of the engines for equality.
145impl<Input:Clone+Debug,EditSt,Output:Eq+Debug,
146     Editor:Generate<Input>+Edit<Input,EditSt>,
147     Archivist:ComputeDemand<Input,Output>>
148  SampleGen for LabState<rand::StdRng,Input,EditSt,Output,Editor,Archivist> {
149    fn sample (self:&mut Self) -> Option<Sample> {
150      if self.change_batch_num > self.params.change_batch_loopc {
151        None 
152      } else { // Collect the next sample, for each engine, using get_engine_sample.
153        let mut dcg_state = LabEngineState{ input: None, engine: Engine::Naive, 
154                                             output: PhantomData, inputdist: PhantomData, computer: PhantomData };
155        swap(&mut dcg_state, &mut self.dcg_state );
156        let mut naive_state = LabEngineState{ input: None, engine: Engine::Naive, 
157                                               output: PhantomData, inputdist: PhantomData, computer: PhantomData };
158        swap(&mut naive_state, &mut self.naive_state );
159
160        // Run Naive Version
161        //println!("Naive - - - - - ({:?} / {:?})", self.change_batch_num, self.params.change_batch_loopc );
162        let _ = use_engine(Engine::Naive); assert!(engine_is_naive());
163        let mut rng = self.rng.clone(); // Restore Rng
164        let (naive_output, naive_input_edited, naive_editst, naive_sample) = 
165          get_engine_sample::<rand::StdRng,Input,EditSt,Output,Editor,Archivist>
166          (&mut rng, &self.params.sample_params, naive_state.input);
167        self.naive_state.input = Some((naive_input_edited, naive_editst)); // Save the input and input-editing state
168
169        // Run DCG Version
170        //println!("DCG - - - - - ");
171        let _ = use_engine(dcg_state.engine); // Restore saved DCG
172        assert!(engine_is_dcg()); // This really is the DCG version
173        let mut rng = self.rng.clone(); // Restore Rng
174        let (dcg_output, dcg_input_edited, dcg_editst, dcg_sample) = 
175          get_engine_sample::<rand::StdRng,Input,EditSt,Output,Editor,Archivist>
176          (&mut rng, &self.params.sample_params, dcg_state.input);
177        self.dcg_state.engine = use_engine(Engine::Naive); // Swap out the DCG
178        self.dcg_state.input = Some((dcg_input_edited, dcg_editst)); // Save the input and input-editing state
179        
180        // Save the Rng for the next sample.
181        self.rng = Box::new(*rng);
182
183        // Compare the two outputs for equality
184        let output_valid = if self.params.sample_params.validate_output { 
185          Some ( dcg_output == naive_output )
186        } else { None } ;
187
188        let sample = Sample{
189          //params:self.params.sample_params.clone(),
190          batch_name:self.change_batch_num,
191          dcg_sample,
192          naive_sample,
193          output_valid,
194        };
195        self.change_batch_num += 1;
196        Some(sample)
197      }
198    }
199  }
200
201/// Lab experiment implementation: Implements the LabDef trait for any
202/// LabArchivist instantiation.
203impl<Input:Clone+Debug,EditSt,Output:Eq+Debug,
204     Editor:'static+Generate<Input>+Edit<Input,EditSt>,
205     Archivist:'static+ComputeDemand<Input,Output>>
206  Lab for LabDef<Input,EditSt,Output,Editor,Archivist> {
207    fn name(self:&Self) -> Name { self.identity.clone() }
208    fn url(self:&Self) -> &Option<String> { &self.url }
209    fn run(self:&Self, params:&LabParams) -> LabResults 
210    {            
211      let mut st = get_sample_gen::<Input,EditSt,Output,Editor,Archivist>(params);
212      loop {
213        //println!("{:?}", self.name());
214        let sample = (&mut st).sample();
215        //println!("{:?}", sample);        
216
217        // TODO: Dump to CSV/Tab-separated file; e.g., for GNUPLOT
218        match sample {
219          Some(s) => {st.samples.push(s); continue},
220          None => break,
221        }
222      };
223      return LabResults {
224        samples: st.samples,
225      }
226    }
227  }