Fleet  0.0.9
Inference in the LOT
VirtualMachineState.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <type_traits>
4 #include <map>
5 #include <utility>
6 #include <tuple>
7 #include <typeindex>
8 
9 #include "Errors.h"
10 #include "Program.h"
11 #include "Stack.h"
13 #include "RuntimeCounter.h"
14 #include "VirtualMachineControl.h"
15 
16 #include "VMSRuntimeError.h"
17 
18 // if defined, we do NOT check that the stack sizes are empty at the end.
19 // You might want this if we are using one VirtualMachineState to compute multiple outputs.
20 // NOTE: This is risky to disable because if we mess up something in implementation, this check often
21 // helps to find it
22 //#define NO_CHECK_END_STACK_SIZE 1
23 
24 // These are the only types of classes we are able to memoize in a lexicon
25 // NOTE: We need short because that's the "key" used for LOTHypothesis instead of lexicon
26 #define LEXICON_MEMOIZATION_TYPES short,std::string,int
27 
28 namespace FleetStatistics {}
29 template<typename X> class VirtualMachinePool;
30 extern std::atomic<uintmax_t> FleetStatistics::vm_ops;
31 
45 template<typename _t_input, typename _t_output, typename... VM_TYPES>
47 public:
48 
49  using input_t = _t_input;
50  using output_t = _t_output;
51 
52  using this_t = VirtualMachineState<input_t, output_t, VM_TYPES...>;
53 
54  // Define the function type for instructions and things operating on this VirtualMachineState
55  // This is read a few other places, like in Builtins
56  using FT = std::function<void(this_t*,int)>;
57 
58  // what we use internally for stacks
59  template<typename T>
60  using VMSStack = Stack<T>;
61 
62  Program<this_t> program; // programs are instructions for myself
63  VMSStack<input_t> xstack; //xstackthis stores a stack of the x values (for recursive calls)
64  const output_t& err; // what error output do we return? Just a reference to a value for speed
65  double lp; // the probability of this context
66 
67  unsigned long recursion_depth; // when I was created, what was my depth?
68 
69 private:
70  // these are private and should only be accessed via stack(), mem(), memstack() below
71 
72  // This is a little bit of fancy template metaprogramming that allows us to define a stack
73  // like std::tuple<VMSStack<bool>, VMSStack<std::string> > using a list of type names defined in VM_TYPES
74  template<typename... args>
75  struct stack_t { std::tuple<VMSStack<args>...> value; };
76  stack_t<VM_TYPES...> _stack; // our stacks of different types
77 
78  // same for defining memoization types -- here these are the only ones we allow
79  template<typename... args>
80  struct mem_t { std::tuple<std::map<std::pair<args,input_t>,output_t>...> value; };
81  mem_t<LEXICON_MEMOIZATION_TYPES> _mem;
82 
83  template<typename... args>
84  struct memstack_t { std::tuple< VMSStack<std::pair<args, input_t>>...> value; };
85  memstack_t<LEXICON_MEMOIZATION_TYPES> _memstack;
86 
87 public:
88 
89  vmstatus_t status; // are we still running? Did we get an error?
90 
91  // what do we use to count up instructions
92  // NOTE for now this may be a bit slower and unnecessary but it doesn't seem so bad at the
93  // moment so this may need to be optimized later to be optional
95 
96  // where we place random flips back onto
98 
99  VirtualMachineState(input_t x, const output_t& e, VirtualMachinePool<this_t>* po) :
100  err(e), lp(0.0), recursion_depth(0), status(vmstatus_t::GOOD), pool(po) {
101  xstack.push(x);
102  }
103 
104  template<typename T>
105  std::map<std::pair<T,input_t>,output_t>& mem() { return std::get<std::map<std::pair<T,input_t>,output_t>>(_mem.value); }
106 
107  template<typename T>
108  VMSStack<std::pair<T,input_t>>& memstack() { return std::get<VMSStack<std::pair<T,input_t>>>(_memstack.value); }
109 
116  auto operator<=>(const VirtualMachineState& m) const {
117  return lp <=> m.lp;
118  }
119 
124  template<typename T>
126  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
127  return std::get<VMSStack<T>>(_stack.value);
128  }
129 
134  template<typename T>
135  const VMSStack<T>& stack() const {
136  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
137  return std::get<VMSStack<T>>(_stack.value);
138  }
139 
144  template<typename T>
145  T getpop() {
146  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
147 // print(typeid(T)::name());
148 
149  // Should not happen -- we must not be empty
150  if(stack<T>().size() == 0) {
151  std::type_index a(typeid(T));
152  //print(stack<T>().size());
153  print("*** Cannot pop from an empty stack -- this should not happen! Something is likely wrong with your grammar's argument types, return type, or arities:", a.name());
154  assert(false);
155  }
156 
157  T x = stack<T>().top();
158  stack<T>().pop();
159  return x;
160  }
161 
166  template<size_t n, typename...args>
167  auto getpop_nth() {
168  static_assert( n >= 0 and n < sizeof...(args) && "*** Higher n than args.");
169  return getpop<typename std::tuple_element<n, std::tuple<args...> >::type>();
170  }
171 
176  template<typename T>
177  T gettop() {
178  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
179  assert(stack<T>().size() > 0 && "Cannot gettop from an empty stack -- this should not happen! Something is likely wrong with your grammar's argument types, return type, or arities.");
180  return stack<T>().top();
181  }
182 
183  template<typename T>
184  void push(T& x){
185  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
190  stack<T>().push(x);
191  }
192  template<typename T>
193  void push(T&& x){
194  static_assert(contains_type<T,VM_TYPES...>() && "*** Error type T missing from VM_TYPES");
195  stack<T>().push(std::move(x));
196  }
197 
198  void push_x(input_t x) {
199  xstack.push(x);
200  }
201 
206  template<typename T, typename... args>
207  bool _exactly_one() const {
208  return (... && ((std::is_same<T,args>::value and stack<T>().size()==1) or stack<args>().empty()));
209  }
210  template<typename T>
211  bool exactly_one() const {
212  return this->_exactly_one<T, VM_TYPES...>();
213  }
214 
219  output_t get_output() {
220 
221  if(status == vmstatus_t::ERROR)
222  return err;
223 
224  assert(status == vmstatus_t::COMPLETE && "*** Probably should not be calling this unless we are complete");
225 
226  #ifndef NO_CHECK_END_STACK_SIZE
227  assert( exactly_one<output_t>() and xstack.size() == 1 and "When we return, all of the stacks should be empty or else something is awry.");
228  #endif
229 
230  return gettop<output_t>();
231  }
232 
237  output_t run() {
238  status = vmstatus_t::GOOD;
239  uintmax_t vm_ops = 0;
240 
241  try {
242 
243  while(status == vmstatus_t::GOOD and (not program.empty()) ) {
244 
245  if(program.size() + runtime_counter.total > MAX_RUN_PROGRAM ) { // if we've run too long or we couldn't possibly finish
246  throw VMSRuntimeError();
247  }
248 
249  vm_ops++;
250 
251  Instruction i = program.top(); program.pop();
252 // print("Instruction", i);
253 
254  // keep track of what instruction we've run
255  runtime_counter.increment(i);
256 
257  auto f = reinterpret_cast<FT*>(i.f);
258  (*f)(const_cast<this_t*>(this), i.arg);
259 
260  } // end while loop over ops
261 
262  } catch (VMSRuntimeError& e) {
263  // this may be thrown by a primitive
264  status = vmstatus_t::ERROR;
265  }
266 
267  // Add to global counter once execution is complete.
269 
270  // when we exit, set the status to complete if we are good
271  // otherwise, leave it where it was
272  if(status == vmstatus_t::GOOD) {
273  status = vmstatus_t::COMPLETE;
274  return get_output();
275  }
276  else {
277  // if we get here, there was a problem
278  return err;
279  }
280  }
281 
282 };
Definition: Stack.h:22
void push(T &&x)
Definition: VirtualMachineState.h:193
Definition: VMSRuntimeError.h:13
Definition: VirtualMachineControl.h:13
void push(const T &val)
Push val onto the stack.
Definition: Stack.h:49
void * f
Definition: Instruction.h:24
Definition: VirtualMachineState.h:46
Program< this_t > program
Definition: VirtualMachineState.h:62
VMSStack< std::pair< T, input_t > > & memstack()
Definition: VirtualMachineState.h:108
bool exactly_one() const
Definition: VirtualMachineState.h:211
int arg
Definition: Instruction.h:25
T total
Definition: RuntimeCounter.h:24
Definition: FleetStatistics.h:5
output_t run()
Run.
Definition: VirtualMachineState.h:237
VMSStack< input_t > xstack
Definition: VirtualMachineState.h:63
RuntimeCounter runtime_counter
Definition: VirtualMachineState.h:94
bool _exactly_one() const
There is one element in stack T and the rest are empty. Used to check in returning the output...
Definition: VirtualMachineState.h:207
void increment(Instruction &i, T count=1)
Add count number of items to this instruction&#39;s count.
Definition: RuntimeCounter.h:33
Definition: Instruction.h:20
VirtualMachineState(input_t x, const output_t &e, VirtualMachinePool< this_t > *po)
Definition: VirtualMachineState.h:99
void pop()
Remove top from the stack.
Definition: Stack.h:59
T getpop()
Retrieves and pops the element of type T from the stack.
Definition: VirtualMachineState.h:145
_t_output output_t
Definition: VirtualMachineState.h:50
Instruction top()
Definition: Stack.h:83
double lp
Definition: VirtualMachineState.h:65
void print(FIRST f, ARGS... args)
Lock output_lock and print to std:cout.
Definition: IO.h:53
vmstatus_t
Definition: VMStatus.h:4
std::atomic< uintmax_t > vm_ops(0)
void push(T &x)
Definition: VirtualMachineState.h:184
bool empty() const
Definition: Stack.h:121
VMSStack< T > & stack()
Returns a reference to the stack (of a given type)
Definition: VirtualMachineState.h:125
T gettop()
Retrieves the top of the stack as a copy and does not remove.
Definition: VirtualMachineState.h:177
std::function< void(this_t *, int)> FT
Definition: VirtualMachineState.h:56
size_t size() const
Definition: Stack.h:117
void push_x(input_t x)
Definition: VirtualMachineState.h:198
const auto empty
Definition: DSL.h:8
const output_t & err
Definition: VirtualMachineState.h:64
const VMSStack< T > & stack() const
Const reference to top of stack.
Definition: VirtualMachineState.h:135
_t_input input_t
Definition: VirtualMachineState.h:49
This class manages counting operations at runtime and interfaces operations to a grammar NOTE: Curren...
VirtualMachinePool< this_t > * pool
Definition: VirtualMachineState.h:97
Definition: RuntimeCounter.h:16
unsigned long recursion_depth
Definition: VirtualMachineState.h:67
Definition: Program.h:6
output_t get_output()
Return the output and do some checks that the stacks are as they should be if you&#39;re reading the outp...
Definition: VirtualMachineState.h:219
A program here stores just a stack of instructions which can be executed by the VirtualMachineState_t...
std::map< std::pair< T, input_t >, output_t > & mem()
Definition: VirtualMachineState.h:105
auto getpop_nth()
Getpops the n&#39;th element of args (useful for writing primitives)
Definition: VirtualMachineState.h:167
vmstatus_t status
Definition: VirtualMachineState.h:89
Definition: VirtualMachinePool.h:42
Many things in Fleet are stacks and this is designed to allow for rapid changse to the stack type in ...