philsupertramp/game-math
Loading...
Searching...
No Matches
Equation.h
Go to the documentation of this file.
1
7#pragma once
8
9
10#include <cassert>
11#include <cmath>
12#include <functional>
13#include <iostream>
14#include <regex>
15#include <sstream>
16#include <unordered_set>
17#include <utility>
18
19#include "../format.h"
20#include "EquationParser.h"
21#include "MathNode.h"
22#include "Operand.h"
23#include "Operator.h"
24
25
30{
31public:
33 std::vector<std::shared_ptr<Symbolic>> symbols;
34
36 std::shared_ptr<MathNode> baseNode = nullptr;
37
39 int degree = 1;
40
45
50 explicit Equation(const char* val) {
51 std::string eq(val);
52 EquationParser parser(eq);
53 baseNode = parser.createAST();
54 symbols = parser.symbols;
56 }
61 explicit Equation(const std::string& val) {
62 EquationParser parser(val);
63 baseNode = parser.createAST();
64 symbols = parser.symbols;
66 }
67
68 int GetDegree(const std::shared_ptr<MathNode>& node) {
69 if(node == nullptr) return 0;
70
71 if(node->type == NodeType_Operator) {
72 if(node->value[0] == '^' && node->left->type == NodeType_Symbolic) { return (int)node->right->Evaluate(); }
73 auto left = GetDegree(node->left);
74 auto right = GetDegree(node->right);
75 return left > right ? left : right;
76 }
77 return 1;
78 }
79
83 void Print(std::ostream& ostr = std::cout) {
84 ostr << baseNode;
85 ostr << std::endl;
86 }
87
98 template<typename... VArgs>
99 double operator()(VArgs... args) {
100 assert(sizeof...(args) == symbols.size());
101 SetSymbols(0, args...);
102 return baseNode->Evaluate();
103 }
108 double operator()() { return baseNode->Evaluate(); }
109
117 template<typename... VArgs>
118 void SetSymbols(const int& index, double val, VArgs... args) {
119 symbols[index]->evaluationValue = val;
120 SetSymbols(index + 1, args...);
121 }
126 void SetSymbols([[maybe_unused]] const int& index) { }
127
134 void SetSymbols(const std::vector<double>& values) {
135 assert(values.size() == symbols.size());
136
137 for(size_t i = 0; i < symbols.size(); ++i) { symbols[i]->evaluationValue = values[i]; }
138 }
139
144 [[nodiscard]] std::string GetString() const { return baseNode->GetString(); }
145
149 void PrintTree() const {
150 size_t row = 0;
151 size_t elems = GetDepth(baseNode, row) + 1;
152 std::vector<std::vector<std::string>> levels(elems, std::vector<std::string>(elems));
153 row = 0;
154 size_t col = 0;
155 PrintNode(baseNode, levels, row, col);
156 std::vector<std::vector<std::string>> realLevels(elems, std::vector<std::string>(elems * 2));
160 bool eol = false;
161 std::vector<size_t> padding(elems);
162 size_t index = 0;
163 for(const auto& line : levels) {
164 for(const auto& elem : line) {
165 if(elem == " " || elem.empty()) {
166 if(eol) { padding[index]++; }
167 eol = true;
168 } else {
169 padding[index] = 0;
170 }
171 }
172 index++;
173 }
174
175 for(size_t paddIndex = 0; paddIndex < elems; ++paddIndex) {
176 for(index = 0; index < elems + padding[paddIndex]; ++index) {
177 if(index < padding[paddIndex]) {
178 std::cout << " ";
179 } else {
180 std::cout << levels[paddIndex][index - padding[paddIndex]];
181 }
182 }
183 std::cout << std::endl;
184 }
185 }
186
192 const std::shared_ptr<MathNode>& node,
193 std::vector<std::vector<std::string>>& levels,
194 const size_t& row,
195 const size_t& column) const {
196 switch(node->connectionType) {
197 case NodeConnectionType::ConnectionType_Dual:
198 {
199 /* op
200 * / \
201 * left right
202 */
203 levels[row][column] += " ";
204 levels[row][column + 1] += node->value;
205 levels[row][column + 2] += " ";
206 levels[row + 1][column] += " /";
207 levels[row + 1][column + 2] += " \\";
208 auto childIndex = row + 2;
209 levels[childIndex][column + 1] += " ";
210 PrintNode(node->left, levels, childIndex, column);
211 PrintNode(node->right, levels, childIndex, column + 2);
212 levels[childIndex][column + 2] += " ";
213 }
214 break;
215 case NodeConnectionType::ConnectionType_Left:
216 {
217 /* fun
218 * /
219 * left
220 */
221 levels[row][column] += " ";
222 levels[row][column + 1] += node->value;
223 levels[row][column + 2] += " ";
224 levels[row + 1][column] += " /";
225 levels[row + 1][column + 2] += " ";
226 auto childIndex = row + 2;
227 levels[childIndex][column + 1] += " ";
228 levels[childIndex][column + 2] += " ";
229 PrintNode(node->left, levels, childIndex, column);
230 }
231 break;
232 case NodeConnectionType::ConnectionType_Right:
233 {
234 /* fun
235 * \
236 * right
237 */
238 levels[row][column] += " ";
239 levels[row][column + 1] += node->value;
240 levels[row][column + 2] += " ";
241 levels[row + 1][column] += " ";
242 levels[row + 1][column + 2] += " \\";
243 auto childIndex = row + 2;
244 levels[childIndex][column] += " ";
245 levels[childIndex][column + 1] += " ";
246 PrintNode(node->right, levels, childIndex, column + 2);
247 levels[childIndex][column + 2] += " ";
248 }
249 break;
250 case NodeConnectionType::ConnectionType_None:
251 {
252 //value
253 levels[row][column] += std::string(" ") + node->value;
254 }
255 break;
256 case NodeConnectionType::ConnectionType_Unknown:
257 default: break;
258 }
259 }
260
267 size_t GetDepth(const std::shared_ptr<MathNode>& node, size_t& current_depth) const {
268 current_depth++;
269 auto leftDep = std::numeric_limits<size_t>::min();
270 auto rightDep = std::numeric_limits<size_t>::min();
271 if(node->left) { leftDep = GetDepth(node->left, current_depth); }
272 if(node->right) { rightDep = GetDepth(node->right, current_depth); }
273
274 return std::max(std::max(leftDep, current_depth), rightDep);
275 }
276
283 void PrintTree(const std::shared_ptr<MathNode>& node, int& level, std::vector<std::string>& tree) const {
284 tree[level] += "\t";
285 tree[level] += std::string(node->value);
286 if(node->left) {
287 PrintTree(node->left, level, tree);
288 tree[level] += "\t";
289 PrintTree(node->right, level, tree);
290 tree[level] += "\t";
291 level += 1;
292 }
293 }
294
305 static Equation Chain(const Equation& left, const Equation& right, const std::shared_ptr<Operator>& op) {
306 Equation out;
307 op->left = left.baseNode;
308 op->right = right.baseNode;
309 out.baseNode = op;
311 return out;
312 }
313
317 void Simplify() {
318 // Early exit for constants
319 switch(baseNode->type) {
321 case NodeType_Numeric:
323 case NodeType_Any: break;
328 }
329 }
330
331private:
337 [[nodiscard]] std::shared_ptr<MathNode> SimplifyTree(const std::shared_ptr<MathNode>& node) const {
338 auto out = node;
339 if(
340 out->type == NodeType_Numeric || out->type == NodeType_Operator || out->type == NodeType_DefaultSymbol
341 || out->type == NodeType_Symbolic || out->type == NodeType_Functional) {
342 out = simplifyOP(out);
343 }
344
345 // early exit
346 if(out->type == NodeType_Numeric || out->type == NodeType_Symbolic) return out;
347
348 if(out->type == NodeType_Operator) {
349 auto op = EquationParser::GetOperator(out->value);
350 // resolve line operators +/-
351 if(op->priority == OPClassLine || op->priority == OPClassDot) { resolveOP(out, op); }
352 }
353 return out;
354 }
355
356
362 void resolveOP(std::shared_ptr<MathNode>& out, const std::shared_ptr<Operator>& op) const {
363 // left value is numeric. Search for left side of right operand
364 if(out->left->type == NodeType_Numeric) {
365 auto rightNode = out->right;
366 while(rightNode != nullptr) {
367 if(rightNode->type == NodeType_Numeric) {
368 out = ApplyOperator(rightNode, op, out->left->Evaluate(), true);
369 break;
370 }
371 rightNode = rightNode->left;
372 }
373 } else if(out->right->type == NodeType_Numeric) {
374 if(EquationParser::GetOperator(out->value)->priority != OperatorPriority::OPClassLine) { return; }
375 auto leftNode = out->left;
376 auto parent = out;
377 while(leftNode != nullptr) {
378 if(leftNode->type == NodeType_Numeric) {
379 parent->right = ApplyOperator(leftNode, op, out->right->Evaluate(), false);
380 out = out->left;
381 break;
382 }
383 parent = leftNode;
384 leftNode = leftNode->right;
385 }
386 }
387 }
388
403 [[nodiscard]] std::shared_ptr<MathNode> simplifyOP(const std::shared_ptr<MathNode>& node) const {
404 std::shared_ptr<MathNode> nodeOut = node;
405 // node is function, simplify f(x) -> y
406 if(nodeOut->type == NodeType_Functional && nodeOut->left->type == NodeType_Numeric) {
407 return std::make_shared<Number>(std::to_string(nodeOut->Evaluate()));
408 }
409
410 // left is Operator, simplify left := f(x) -> y
411 if(nodeOut->left->type == NodeType_Operator || nodeOut->left->type == NodeType_Functional) {
412 nodeOut->left = SimplifyTree(nodeOut->left);
413 }
414
415 // All done
416 if(nodeOut->type != NodeType_Operator) return nodeOut;
417
418 // from now on right is required
419 assert(nodeOut->right != nullptr);
420
421 // left and right are both Number, evaluate op
422 if(nodeOut->left->type == NodeType_Numeric && nodeOut->right->type == NodeType_Numeric) {
423 return std::make_shared<Number>(std::to_string(nodeOut->Evaluate()));
424 }
425
426 // right is Operator, simplify right := f(x) -> y
427 if(nodeOut->right->type == NodeType_Operator || nodeOut->right->type == NodeType_Functional) {
428 nodeOut->right = SimplifyTree(nodeOut->right);
429 }
430
431 return nodeOut;
432 }
433
447 [[nodiscard]] std::shared_ptr<MathNode> ApplyOperator(
448 const std::shared_ptr<MathNode>& node, const std::shared_ptr<Operator>& op, const double& val, bool isLeft) const {
449 auto out = node;
450 switch(out->connectionType) {
452 if(isLeft) out->left = ApplyOperator(out->left, op, val, true);
453 else
454 out->right = ApplyOperator(out->right, op, val, false);
455 break;
457 if(isLeft) out->left = ApplyOperator(out->left, op, val, true);
458 break;
460 if(!isLeft) out->right = ApplyOperator(out->right, op, val, false);
461 break;
463 {
464 if(out->type == NodeType_Numeric) {
465 if(isLeft) return std::make_shared<Number>(std::to_string(op->op(out->Evaluate(), val)));
466 else
467 return std::make_shared<Number>(std::to_string(op->op(val, out->Evaluate())));
468 }
469 }
470 break;
471 case ConnectionType_Unknown: break;
472 }
473 return out;
474 }
475};
476
@ ConnectionType_Right
Definition: MathNode.h:26
@ ConnectionType_Dual
Definition: MathNode.h:24
@ ConnectionType_None
Definition: MathNode.h:27
@ ConnectionType_Unknown
Definition: MathNode.h:28
@ ConnectionType_Left
Definition: MathNode.h:25
@ NodeType_Operator
Definition: MathNode.h:13
@ NodeType_Symbolic
Definition: MathNode.h:14
@ NodeType_Any
Definition: MathNode.h:19
@ NodeType_Functional
Definition: MathNode.h:17
@ NodeType_DefaultSymbol
Definition: MathNode.h:18
@ NodeType_Operator_or_Parentheses
Definition: MathNode.h:20
@ NodeType_Parentheses
Definition: MathNode.h:16
@ NodeType_Numeric
Definition: MathNode.h:15
@ OPClassLine
Definition: Operator.h:17
@ OPClassDot
Definition: Operator.h:18
Definition: EquationParser.h:15
std::shared_ptr< MathNode > createAST()
std::vector< std::shared_ptr< Symbolic > > symbols
storage for symbols, gets cleared on EquationParser::createAST
Definition: EquationParser.h:31
static std::shared_ptr< Operator > GetOperator(const std::string &valString)
Definition: EquationParser.h:80
static std::vector< std::shared_ptr< Symbolic > > buildSymbolSuperSet(const std::vector< std::shared_ptr< Symbolic > > &a, const std::vector< std::shared_ptr< Symbolic > > &b)
Definition: EquationParser.h:45
Definition: Equation.h:30
void Simplify()
Definition: Equation.h:317
double operator()()
Definition: Equation.h:108
void SetSymbols(const int &index, double val, VArgs... args)
Definition: Equation.h:118
std::shared_ptr< MathNode > SimplifyTree(const std::shared_ptr< MathNode > &node) const
Definition: Equation.h:337
std::vector< std::shared_ptr< Symbolic > > symbols
storage for containing symbols
Definition: Equation.h:33
Equation(const char *val)
Definition: Equation.h:50
Equation(const std::string &val)
Definition: Equation.h:61
void SetSymbols(const int &index)
Definition: Equation.h:126
std::string GetString() const
Definition: Equation.h:144
void SetSymbols(const std::vector< double > &values)
Definition: Equation.h:134
Equation()
Definition: Equation.h:44
std::shared_ptr< MathNode > simplifyOP(const std::shared_ptr< MathNode > &node) const
Definition: Equation.h:403
void PrintTree(const std::shared_ptr< MathNode > &node, int &level, std::vector< std::string > &tree) const
Definition: Equation.h:283
void resolveOP(std::shared_ptr< MathNode > &out, const std::shared_ptr< Operator > &op) const
Definition: Equation.h:362
void Print(std::ostream &ostr=std::cout)
Definition: Equation.h:83
static Equation Chain(const Equation &left, const Equation &right, const std::shared_ptr< Operator > &op)
Definition: Equation.h:305
int degree
degree of equation. Linear equation = 1, quadratic = 2, ...
Definition: Equation.h:39
void PrintTree() const
Definition: Equation.h:149
std::shared_ptr< MathNode > ApplyOperator(const std::shared_ptr< MathNode > &node, const std::shared_ptr< Operator > &op, const double &val, bool isLeft) const
Definition: Equation.h:447
void PrintNode(const std::shared_ptr< MathNode > &node, std::vector< std::vector< std::string > > &levels, const size_t &row, const size_t &column) const
Definition: Equation.h:191
std::shared_ptr< MathNode > baseNode
Holds the base node of the abstract syntax tree.
Definition: Equation.h:36
size_t GetDepth(const std::shared_ptr< MathNode > &node, size_t &current_depth) const
Definition: Equation.h:267
double operator()(VArgs... args)
Definition: Equation.h:99
int GetDegree(const std::shared_ptr< MathNode > &node)
Definition: Equation.h:68