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