YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
binexparser.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7#include <yarp/os/Log.h>
8#include <cstdio>
9#include <cstring>
10#include <iostream>
11#include <fstream>
12#include <string>
13#include <algorithm>
14#include <cmath>
15#include <cinttypes>
16#include <climits>
17#include <cstddef>
18
19
20#define EXPNOT '~'
21#define EXPAND '&'
22#define EXPOR '|'
23#define IMPLY ':'
24
25#define PRECISION(max_value) sizeof(max_value) * 8
26
27
28using namespace yarp::manager;
29
30
32
34
35bool BinaryExpParser::parse(std::string _exp)
36{
37 expression = _exp;
38 std::string strexp = expression;
39 if (!checkExpression(strexp)) {
40 return false;
41 }
42
43 binTree.clear();
44 operands.clear();
45 BinaryNodePtr root = nullptr;
46 parseExpression(strexp, root);
47 if(root == nullptr)
48 {
50 std::string msg = "BinaryExpParser: failed to parse the expression";
51 logger->addError(msg);
52 return false;
53 }
54 if(invalidOperands.size())
55 {
57 std::string msg = "Invalid operands";
58 for (const auto& invalidOperand : invalidOperands) {
59 msg += " '" + invalidOperand + "'";
60 }
61 logger->addError(msg);
62 return false;
63 }
64
65 // creating a truth table for inputs and outputs
66 createTruthTable(operands.size());
67 int n = truthTable.size();
68 for(int x = 0; x < (1 << (n-1)); ++x)
69 {
70 auto itr = operands.begin();
71 for (int y = 0; y < (n - 1); ++y) {
72 (*itr++).second = (truthTable[y][x] != 0);
73 }
74 truthTable[n-1][x] = evalTree(root, operands);
75 }
76 //printTruthTable(leftOpr);
77 return true;
78}
79
80bool BinaryExpParser::exportDotGraph(const char* szFileName)
81{
82 std::ofstream dot;
83 dot.open(szFileName);
84 if (!dot.is_open()) {
85 return false;
86 }
87
88 dot<<"digraph G {\n";
89 for(GraphIterator itr=binTree.begin(); itr!=binTree.end(); itr++)
90 {
91 switch((*itr)->getType()) {
92 case OPERATOR: {
93 auto node = (BinaryNodePtr)(*itr);
94 dot<<"\""<<node->getLabel()<<"\"";
95 dot<<" [label=\""<< node->getName()<<"\"";
96 dot<<" shape=circle, fillcolor=lightslategrey, style=filled];\n";
97 for(int i=0; i<node->sucCount(); i++)
98 {
99 Link l = node->getLinkAt(i);
100 auto to = (BinaryNodePtr)l.to();
101 dot<<"\""<<node->getLabel()<<"\" -> ";
102 dot<<"\""<<to->getLabel()<<"\"";
103 dot<<" [label=\"\"];\n";
104 }
105 break;
106 }
107 case OPERAND: {
108 auto node = (BinaryNodePtr)(*itr);
109 dot<<"\""<<node->getLabel()<<"\"";
110 dot<<" [label=\""<< node->getName()<<"\"";
111 dot<<" shape=square];\n";
112 break;
113 }
114 default:
115 break;
116 };
117 }
118 dot << "}\n";
119 dot.close();
120 return true;
121}
122
123
124bool BinaryExpParser::evalTree(BinaryNodePtr node, std::map<std::string, bool>& opnd)
125{
126 bool result = false;
127 if(node->isLeaf())
128 {
129 node->setValue(opnd[node->getName()]);
130 result = node->getValue();
131 }
132 else
133 {
134 if(strcmp(node->getName(), "~") == 0)
135 {
136 auto left = (BinaryNodePtr)node->getLinkAt(0).to();
137 result = !evalTree(left, opnd);
138 node->setValue(result);
139 }
140 else if(strcmp(node->getName(), "&") == 0)
141 {
142 auto left = (BinaryNodePtr)node->getLinkAt(0).to();
143 auto right = (BinaryNodePtr)node->getLinkAt(1).to();
144 result = evalTree(left, opnd) && evalTree(right, opnd);
145 node->setValue(result);
146 }
147 else if(strcmp(node->getName(), "|") == 0)
148 {
149 auto left = (BinaryNodePtr)node->getLinkAt(0).to();
150 auto right = (BinaryNodePtr)node->getLinkAt(1).to();
151 result = evalTree(left, opnd) || evalTree(right, opnd);
152 node->setValue(result);
153 }
154 }
155 return result;
156}
157
158bool isParentheses (char c)
159{
160 return ((c=='(') || (c==')'));
161}
162
163bool BinaryExpParser::checkExpression(std::string& strexp)
164{
166
167 if(std::count(strexp.begin(), strexp.end(), '(') !=
168 std::count(strexp.begin(), strexp.end(), ')'))
169 {
170 logger->addError("Incorrect expression format! (parentheses do not match)");
171 return false;
172 }
173 if(std::count(strexp.begin(), strexp.end(), IMPLY) != 1 )
174 {
175 logger->addError("Incorrect expression format! (no implication ':' found)");
176 return false;
177 }
178
179 // erassing all the sapces
180 strexp.erase(std::remove_if(strexp.begin(), strexp.end(), ::isspace), strexp.end());
181 if(!strexp.size())
182 {
183 logger->addError("Empty expression!");
184 return false;
185 }
186
187 // making a copy of strexp and checking more
188 std::string dummy = strexp;
189 // removing all pranteses
190 dummy.erase(std::remove_if(dummy.begin(), dummy.end(), isParentheses), dummy.end());
191 leftOpr = dummy.substr(0, dummy.find(IMPLY));
192 if(!leftOpr.size())
193 {
194 logger->addError("Missing operand before ':'");
195 return false;
196 }
197 if(dummy.find(IMPLY) == (dummy.size()-1))
198 {
199 logger->addError("Missing operands after ':'");
200 return false;
201 }
202
203 dummy.erase(0, dummy.find(IMPLY)+1);
204 if(dummy.find(leftOpr) != std::string::npos)
205 {
206 std::string msg;
207 msg = "recursive assignment of operand '" + leftOpr + "'";
208 logger->addError(msg.c_str());
209 return false;
210 }
211
212 // checking '~'
213 size_t n = dummy.find(EXPNOT);
214 while(n != std::string::npos)
215 {
216 OSTRINGSTREAM msg;
217 bool bError = ((n+1) == dummy.length()); // empty operand after ~
218 if((n+1) < dummy.length())
219 {
220 bError |= (dummy[n+1] == EXPAND); // operator & after ~
221 bError |= (dummy[n+1] == EXPOR); // operand | after ~
222 }
223 if (n != 0) {
224 bError |= (dummy[n - 1] != EXPAND) && (dummy[n - 1] != EXPOR); // an operand before ~
225 }
226 if(bError)
227 {
228 msg<<"Incorrect expression format of '~' at "<<(int)n;
229 logger->addError(msg.str().c_str());
230 return false;
231 }
232 n = dummy.find(EXPNOT, n+1);
233 }
234
235 // checking '| &'
236 n = dummy.find_first_of("&|");
237 while(n != std::string::npos)
238 {
239 OSTRINGSTREAM msg;
240 bool bError = ((n+1) == dummy.length()); // empty operand after & or |
241 if((n+1) < dummy.length())
242 {
243 bError |= (dummy[n+1] == EXPAND); // operator & after & or |
244 bError |= (dummy[n+1] == EXPOR); // operand | after & or |
245 }
246 bError |= (n == 0); // empty operand before & or |
247 if(n != 0)
248 {
249 bError |= (dummy[n-1] == EXPAND); // operator & before & or |
250 bError |= (dummy[n-1] == EXPOR); // operand | before & or |
251 bError |= (dummy[n-1] == EXPOR); // operand ~ before & or |
252 }
253 if(bError)
254 {
255 msg<<"Incorrect expression format of '&' or '|' at "<<(int)n;
256 logger->addError(msg.str().c_str());
257 return false;
258 }
259 n = dummy.find_first_of("&|", n+1);
260 }
261
262 // at the end
263 strexp.erase(0, strexp.find(IMPLY)+1);
264 return true;
265}
266
267void BinaryExpParser::parseExpression(std::string &strexp, BinaryNodePtr& node)
268{
269 std::string op;
270 BinaryNodePtr rightNode = nullptr;
271 parseNot(strexp, node);
272 while(!strexp.empty() &&
273 ((*strexp.begin() == EXPAND) ||
274 (*strexp.begin() == EXPOR)))
275 {
276 op = *strexp.begin();
277 strexp.erase(strexp.begin());
278 parseNot(strexp, rightNode);
279 BinaryNode tmpNode(op.c_str(), node, rightNode);
280 node = (BinaryNodePtr) binTree.addNode(&tmpNode);
281 }
282}
283
284
285void BinaryExpParser::parseNot(std::string &strexp, BinaryNodePtr& node) {
286 std::string op;
287 BinaryNodePtr rightNode;
288 if (*strexp.begin() != EXPNOT) {
289 parseFactor(strexp, node);
290 }
291 while(!strexp.empty() &&
292 (*strexp.begin() == EXPNOT))
293 {
294 op = *strexp.begin();
295 strexp.erase(strexp.begin());
296 parseFactor(strexp, rightNode);
297 BinaryNode tmpNode(op.c_str(), rightNode, nullptr);
298 node = (BinaryNodePtr) binTree.addNode(&tmpNode);
299 }
300}
301
302void BinaryExpParser::parseFactor(std::string &strexp, BinaryNodePtr& node) {
303 if(!strexp.empty() && (*strexp.begin() != '('))
304 {
305 std::string op = popNextOperand(strexp);
306 BinaryNode tmpNode(op.c_str());
307 node = (BinaryNodePtr) binTree.addNode(&tmpNode);
308 operands[op] = false;
309 if(validOperands.size())
310 {
311 if (std::find(validOperands.begin(),
312 validOperands.end(),
313 op)
314 == validOperands.end()) {
315 invalidOperands.push_back(op);
316 }
317 }
318 }
319 else
320 {
321 strexp.erase(strexp.begin()); //skip '('
322 parseExpression(strexp, node);
323 strexp.erase(strexp.begin()); //skip ')'
324 }
325}
326
327
328std::string BinaryExpParser::getNextOperand(std::string &strexp) {
329 std::string token;
330 std::string::iterator it;
331 for (it = strexp.begin(); it != strexp.end(); ++it) {
332 if ((*it != EXPAND) && (*it != EXPOR) && (*it != EXPNOT) && (*it != ')') && (*it != '(')) {
333 token.push_back(*it);
334 } else {
335 break;
336 }
337 }
338 return token;
339}
340
341std::string BinaryExpParser::popNextOperand(std::string &strexp) {
342 std::string token;
343 std::string::iterator it;
344 for (it = strexp.begin(); it != strexp.end(); ++it) {
345 if ((*it != EXPAND) && (*it != EXPOR) && (*it != EXPNOT) && (*it != ')') && (*it != '(')) {
346 token.push_back(*it);
347 } else {
348 strexp.erase(strexp.begin(), it);
349 break;
350 }
351 }
352 return token;
353}
354
355void BinaryExpParser::createTruthTable(const int n)
356{
357 yAssert((n-1) > 0);
358 yAssert((unsigned)(n-1) < PRECISION(INT_MAX));
359 yAssert(1 <= (INT_MAX >> (n-1)));
360
361 truthTable.clear();
362 // n input + one output
363 truthTable.resize(n+1);
364 for (int i = 0; i < n + 1; i++) {
365 truthTable[i].resize(1 << n);
366 }
367 int num_to_fill = 1 << (n - 1);
368 for(int col = 0; col < n; ++col, num_to_fill >>= 1)
369 {
370 for(int row = num_to_fill; row < (1 << n); row += (num_to_fill * 2))
371 {
372 std::fill_n(&truthTable[col][row], num_to_fill, 1);
373 }
374 }
375}
376
377void BinaryExpParser::printTruthTable(std::string lopr)
378{
379 int n = truthTable.size();
380
381 yAssert((n-1) > 0);
382 yAssert((unsigned)(n-1) < PRECISION(INT_MAX));
383 yAssert(1 <= (INT_MAX >> (n-1)));
384
385 std::map<std::string, bool>::iterator itr;
386 for (itr = operands.begin(); itr != operands.end(); itr++) {
387 std::cout << (*itr).first << "\t";
388 }
389 std::cout << lopr << '\n';
390 for (int i = 0; i < (int)operands.size() * 8 + 1; i++) {
391 std::cout << "-";
392 }
393 std::cout << '\n';
394
395 for(int x = 0; x < (1<<(n-1)); ++x)
396 {
397 for (int y = 0; y < n; ++y) {
398 std::cout << truthTable[y][x] << "\t";
399 }
400 std::cout << '\n';
401 }
402}
403
404
405bool LinkTrainer::train(const std::vector<std::vector<int> >& truthTable)
406{
407 // resetting weights
408 int n = truthTable.size();
409 errors.clear();
410 alphas.clear();
411 alphas.resize(n-1);
412 std::fill(alphas.begin(), alphas.end(), 0.0);
413 bias = 0.0;
414 double sumerr = 1.0;
415 for(int i=0; (i<maxIteration) && (sumerr !=0); i++)
416 {
417 sumerr = 0;
418 // number of training set : (1 << (n-1)
419 for(int x = 0; x < (1 << (n-1)); ++x)
420 {
421 // computing output of one set
422 double P = truthTable[n-1][x];
423 double out = bias;
424 for (int y = 0; y < n - 1; ++y) {
425 out = out + ((double)truthTable[y][x] * alphas[y]);
426 }
427 out = (out>0) ? 1 : 0;
428 double err = P - out;
429 sumerr += fabs(err);
430 //std::cout<<P<<"\t"<<out<<"\terr:"<<err<<'\n';
431 bias = bias + trainRate * err;
432 for (int y = 0; y < (n - 1); ++y) {
433 alphas[y] = alphas[y] + (trainRate * err * (double)truthTable[y][x]);
434 }
435 }
436 errors.push_back(sumerr);
437 }
438 return ((int)errors.size() < maxIteration);
439}
#define yAssert(x)
Definition Log.h:388
#define EXPNOT
bool isParentheses(char c)
#define PRECISION(max_value)
#define EXPAND
#define EXPOR
#define IMPLY
bool parse(std::string _exp)
bool exportDotGraph(const char *szFileName)
void setValue(bool val)
Definition binexparser.h:79
Singleton class ErrorLogger.
Definition utility.h:58
void addError(const char *szError)
Definition utility.cpp:126
static ErrorLogger * Instance()
Singleton class ErrorLogger.
Definition utility.cpp:98
Class GraphIterator.
Definition graph.h:66
GraphIterator begin()
Definition graph.cpp:165
Node * addNode(Node *node)
Definition graph.cpp:17
GraphIterator end()
Definition graph.cpp:172
bool train(const std::vector< std::vector< int > > &truthTable)
Link & getLinkAt(int index)
Definition node.h:95
bool isLeaf()
Definition node.h:87
BinaryNode * BinaryNodePtr
Definition binexparser.h:91
std::stringstream OSTRINGSTREAM
Definition utility.h:50