-
Notifications
You must be signed in to change notification settings - Fork 0
/
ExpressionTemplate.cc
149 lines (117 loc) · 4.38 KB
/
ExpressionTemplate.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "ExpressionTemplate.h"
ExpressionTemplate::ExpressionTemplate(node* root, rational* numbers, rational expectedResult, const int size) {
this->size = size;
this->expectedResult = expectedResult;
/* Get space on the heap */
nodes = new valuatedNode[2*size+1];
ops = new int[size];
/* Copy node structure to enriched node structure (valuatedNode)
i) The left and right child pointers have to be redirected correctly
ii) The operation nodes point to successive elements of the allocation array
iii) The leaves get the rational numbers in the required sequence.
(ii) & (iii) are performed with a recursive method, see setNumbersAndOperations() below.
*/
for (int i=0;i<=2*size;i++) {
nodes[i].isLeaf = (root+i)->isLeaf;
if (!nodes[i].isLeaf) {
nodes[i].left = nodes + ((root+i)->left - root );
nodes[i].right = nodes + ((root+i)->right - root );
}
}
int iNum = 0, iOps = 0;
this->setNumbersAndOperations( nodes, numbers, &iNum, &iOps );
}
// Determine the sequence of numbers to evaluate (once per execution plan)
void ExpressionTemplate::setNumbersAndOperations( valuatedNode* node, rational* numbers, int* iNum, int *iOps ) {
if (node->isLeaf) {
node->value = numbers[(*iNum)++];
}
else {
node->op = & ops[(*iOps)++];
this->setNumbersAndOperations(node->left,numbers,iNum,iOps);
this->setNumbersAndOperations(node->right,numbers,iNum,iOps);
}
}
ExpressionTemplate::~ExpressionTemplate() {
for (auto r = results.begin(); r != results.end(); ++r) {
delete[] *r;
}
delete[] nodes;
delete[] ops;
}
void ExpressionTemplate::evaluateAllocations() {
// Create all 4**size combinations of operations,
// using a bit field of length 2*size
// If size becomes > 31, think of another implementation of this part
long long int counter = 1 << 2*size;
while (counter) {
counter--;
long long int allocation = counter;
nodes[0].value.denom = 0; // Makes result unequal to everything
int iOp = size-1;
for (valuatedNode* current = nodes + 2*size;
current >= nodes;
current-- ) {
if (!current->isLeaf) {
// Pop next operation from bit field
ops[iOp--] = allocation & 0b11;
allocation >>= 2;
// Skip [ *, [ *, ...], <>[*,...] ] & the like by associativity
if (isDuplicateByAssociativity( current )) break;
// Compute next intermediate result
current->value = current->left->value;
OPERATION[*current->op](¤t->value,current->right->value);
// ignore div 0
if (current->value.denom == 0) break;
}
}
if (equals(&expectedResult,nodes[0].value)) {
int* result = new int[size];
for (int i=0;i<size;i++) result[i] = ops[i];
results.push_back( result );
}
}
}
inline bool ExpressionTemplate::isDuplicateByAssociativity( const valuatedNode* current ) {
return
! current->left->isLeaf &&
(*current->left->op & 0b10) == (*current->op & 0b10) &&
( current->right->isLeaf ||
(*current->right->op & 0b10) != (*current->op & 0b10)
);
}
void ExpressionTemplate::printResults() {
for (auto ops = results.begin(); ops != results.end(); ops++ ) {
printResult( nodes, 0, *ops );
}
}
// Print result as expression
void ExpressionTemplate::printResult( valuatedNode* current, valuatedNode* parent, int ops[]) {
if (current == nodes) {
for (int i=0; i<size; i++) {
this->ops[i] = ops[i];
}
}
if (current->isLeaf) {
printRational( current->value );
}
else {
if (current != nodes && doBrackets(*current->op, *parent->op) ) std::cout << '(';
printResult( current->left, current, ops);
std::cout << glyph( OPERATION[*current->op] );
printResult( current->right, current, ops);
if (current != nodes && doBrackets(*current->op, *parent->op)) std::cout << ')';
}
if (current == nodes) std::cout << '\n';
}
// Omit brackets in cases like a * ( b * c ), a * ( b / c ) and so on
inline bool ExpressionTemplate::doBrackets( int op, int parentOp ) {
int pattern = ( parentOp << 2 ) | op;
if ( ( pattern == 0b0000 ) || // PLUS -> PLUS
( pattern == 0b0001 ) || // PLUS -> MINUS
( pattern == 0b1010 ) || // TIMES -> TIMES
( pattern == 0b1011 ) ) // TIMES -> BY
return false;
else
return true;
}