AutoPas  3.0.0
Loading...
Searching...
No Matches
RuleVM.h
1#pragma once
2
3#include <variant>
4
6
7namespace autopas {
17class RuleVM {
18 public:
22 using MemoryCell = std::variant<bool, double, size_t, ContainerOption, TraversalOption, LoadEstimatorOption,
23 DataLayoutOption, Newton3Option>;
24
28 enum CMD {
104 NOT
105 };
106
112 struct Instruction {
121
128 };
129
134 struct Program {
138 std::vector<Instruction> instructions;
143 };
144
151 std::vector<size_t> execute(const Program &program, const std::vector<MemoryCell> &initialStack) {
152 _programCounter = 0;
153 _removedPatterns.clear();
154 _stack = initialStack;
155 _stack.resize(program.neededStackSize + initialStack.size());
156 _stackPointer = initialStack.size() - 1;
157 _halt = false;
158
159 while (not _halt) {
160 executeInstruction(program.instructions.at(_programCounter++));
161 }
162
163 return _removedPatterns;
164 }
165
166 private:
167 void executeInstruction(Instruction instruction) {
168 switch (instruction.cmd) {
169 case LOADC:
170 _stack.at(++_stackPointer) = instruction.payload;
171 break;
172 case LOADA:
173 _stack.at(++_stackPointer) = _stack.at(std::get<size_t>(instruction.payload));
174 break;
175 case STOREA:
176 _stack.at(std::get<size_t>(instruction.payload)) = _stack.at(_stackPointer--);
177 break;
178 case RESERVE:
179 _stackPointer += std::get<size_t>(instruction.payload);
180 break;
181 case LESS: {
182 bool res = compare<std::less>();
183 _stackPointer--;
184 _stack.at(_stackPointer) = res;
185 break;
186 }
187 case GREATER: {
188 bool res = compare<std::greater>();
189 _stackPointer--;
190 _stack.at(_stackPointer) = res;
191 break;
192 }
193 case EQUAL: {
194 bool res = compare<std::equal_to>();
195 _stackPointer--;
196 _stack.at(_stackPointer) = res;
197 break;
198 }
199 case JUMPZERO: {
200 bool shouldJump = not std::get<bool>(_stack.at(_stackPointer--));
201 if (shouldJump) {
202 _programCounter = std::get<size_t>(instruction.payload);
203 }
204 break;
205 }
206 case OUTPUTC:
207 _removedPatterns.push_back(std::get<size_t>(instruction.payload));
208 break;
209 case CONDOUTPUTC:
210 if (std::get<bool>(_stack.at(_stackPointer))) {
211 _removedPatterns.push_back(std::get<size_t>(instruction.payload));
212 }
213 break;
214 case HALT:
215 _halt = true;
216 break;
217 case AND: {
218 bool res = std::get<bool>(_stack.at(_stackPointer)) and std::get<bool>(_stack.at(_stackPointer - 1));
219 _stack.at(--_stackPointer) = res;
220 break;
221 } break;
222 case OR: {
223 bool res = std::get<bool>(_stack.at(_stackPointer)) or std::get<bool>(_stack.at(_stackPointer - 1));
224 _stack.at(--_stackPointer) = res;
225 break;
226 }
227 case POP:
228 _stackPointer--;
229 break;
230 case MUL: {
231 auto res =
232 computeBinary(_stack.at(_stackPointer - 1), _stack.at(_stackPointer), [](auto l, auto r) { return l * r; });
233 _stack.at(--_stackPointer) = res;
234 break;
235 }
236 case DIV: {
237 auto res = computeBinary(_stack.at(_stackPointer - 1), _stack.at(_stackPointer), [](auto l, auto r) {
238 // even though this is mathematically not correct it usually yields the intended result in boolean
239 // expressions, e.g.: define isDomainExtremelyEmpty = numEmptyCells / numParticles > threshold;
240 return r == 0 ? std::numeric_limits<decltype(l / r)>::max() : l / r;
241 });
242 _stack.at(--_stackPointer) = res;
243 break;
244 }
245 case ADD: {
246 auto res =
247 computeBinary(_stack.at(_stackPointer - 1), _stack.at(_stackPointer), [](auto l, auto r) { return l + r; });
248 _stack.at(--_stackPointer) = res;
249 break;
250 }
251 case SUB: {
252 auto res =
253 computeBinary(_stack.at(_stackPointer - 1), _stack.at(_stackPointer), [](auto l, auto r) { return l - r; });
254 _stack.at(--_stackPointer) = res;
255 break;
256 }
257 case NOT:
258 _stack.at(_stackPointer) = not std::get<bool>(_stack.at(_stackPointer));
259 break;
260 }
261 }
262
263 template <class T>
264 static constexpr auto isNumericVal() {
265 using type = std::remove_cv_t<std::remove_reference_t<T>>;
266 return std::is_same_v<type, double> or std::is_same_v<type, size_t>;
267 }
268
269 template <template <class> typename Compare>
270 [[nodiscard]] bool compare() {
271 bool res = std::visit(
272 [](auto &&left, auto &&right) {
273 if constexpr (std::is_same_v<decltype(left), decltype(right)>) {
274 return Compare{}(left, right);
275 } else if constexpr (isNumericVal<decltype(left)>() and isNumericVal<decltype(right)>()) {
276 return Compare{}(left, right);
277 } else {
278 throw std::runtime_error("RuleVM: cannot compare");
279 return false;
280 }
281 },
282 _stack.at(_stackPointer - 1), _stack.at(_stackPointer));
283 return res;
284 }
285
286 template <class Functor>
287 [[nodiscard]] MemoryCell computeBinary(const MemoryCell &left, const MemoryCell &right, Functor op) {
288 return std::visit(
289 [&op](auto &&l, auto &&r) {
290 if constexpr (isNumericVal<decltype(l)>() and isNumericVal<decltype(r)>()) {
291 return MemoryCell{op(l, r)};
292 } else {
293 throw std::runtime_error("RuleVM: cannot compute binary operator with these operators");
294 return MemoryCell{};
295 }
296 },
297 left, right);
298 }
299
300 private:
304 size_t _programCounter;
308 size_t _stackPointer;
312 bool _halt;
313
317 std::vector<MemoryCell> _stack;
321 std::vector<size_t> _removedPatterns;
322};
323} // namespace autopas
Class representing the load estimator choices.
Definition: LoadEstimatorOption.h:18
A VM that is capable of executing a program with simple instructions on a stack of MemoryCells.
Definition: RuleVM.h:17
std::vector< size_t > execute(const Program &program, const std::vector< MemoryCell > &initialStack)
Executes a program on a given initial stack.
Definition: RuleVM.h:151
CMD
An enum with all commands that this VM supports.
Definition: RuleVM.h:28
@ JUMPZERO
Payload is program address.
Definition: RuleVM.h:60
@ NOT
Unary operator.
Definition: RuleVM.h:104
@ OUTPUTC
Outputs payload.
Definition: RuleVM.h:64
@ AND
Binary operator.
Definition: RuleVM.h:76
@ ADD
Binary operator.
Definition: RuleVM.h:96
@ OR
Binary operator.
Definition: RuleVM.h:80
@ HALT
Halts program execution.
Definition: RuleVM.h:72
@ LOADA
Payload is absolute stack address.
Definition: RuleVM.h:36
@ LESS
Binary comparison.
Definition: RuleVM.h:48
@ EQUAL
Binary comparison.
Definition: RuleVM.h:56
@ POP
Pops one value from the stack.
Definition: RuleVM.h:84
@ MUL
Binary operator.
Definition: RuleVM.h:88
@ CONDOUTPUTC
Executes OUTPUTC if top of the stack is True.
Definition: RuleVM.h:68
@ SUB
Binary operator.
Definition: RuleVM.h:100
@ LOADC
Load a constant on top of the stack (payload).
Definition: RuleVM.h:32
@ RESERVE
Payload is number of stack cells to reserve.
Definition: RuleVM.h:44
@ DIV
Binary operator.
Definition: RuleVM.h:92
@ STOREA
Payload is absolute stack address.
Definition: RuleVM.h:40
@ GREATER
Binary comparison.
Definition: RuleVM.h:52
std::variant< bool, double, size_t, ContainerOption, TraversalOption, LoadEstimatorOption, DataLayoutOption, Newton3Option > MemoryCell
The type of a memory cell in the stack the VM operates on.
Definition: RuleVM.h:23
This is the main namespace of AutoPas.
Definition: AutoPasDecl.h:32
An instruction to execute in the VM.
Definition: RuleVM.h:112
CMD cmd
The command to execute.
Definition: RuleVM.h:116
Instruction(CMD cmd, MemoryCell payload=MemoryCell{0ul})
Constructs an Instruction.
Definition: RuleVM.h:127
MemoryCell payload
The payload the instruction can have.
Definition: RuleVM.h:120
A program that can be executed by this VM.
Definition: RuleVM.h:134
size_t neededStackSize
The maximum stack size needed to execute the instructions.
Definition: RuleVM.h:142
std::vector< Instruction > instructions
The instructions the program consists of.
Definition: RuleVM.h:138