ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
goto_contractor.h
Go to the documentation of this file.
1#ifndef ESBMC_GOTO_CONTRACTOR_H
2#define ESBMC_GOTO_CONTRACTOR_H
3
4#include <iostream>
14#include <util/irep/std_types.h>
15#include <ibex.h>
16#include <ibex/ibex_Interval.h>
17#include <ibex/ibex_Expr.h>
18#include <ibex/ibex_Ctc.h>
19#include <irep2/irep2.h>
23#include <limits>
24#include <chrono>
25
27 goto_functionst &goto_functions,
29 const optionst &options);
30
31class vart
32{
33private:
34 ibex::Interval interval;
35 std::string var_name;
36 expr2tc symbol;
37 size_t index;
38 bool interval_changed;
39
40public:
41 size_t getIndex() const;
42 vart();
43 vart(const string &varName, const expr2tc &symbol, const size_t &index);
44 const ibex::Interval &getInterval() const;
45 void setInterval(const ibex::Interval &interval);
46 bool isIntervalChanged() const;
47 void setIntervalChanged(bool intervalChanged);
48 const expr2tc &getSymbol() const;
49 void dump() const;
50};
51
53{
54 ibex::Ctc *outer;
55 ibex::Ctc *inner;
56 unsigned int location;
57
58public:
60 {
61 outer = nullptr;
62 location = 0;
63 inner = nullptr;
64 }
65 Contractor(ibex::Ctc *c, unsigned int loc)
66 {
67 outer = c;
68 location = loc;
69 inner = get_complement_contractor(c);
70 }
71 Contractor(ibex::Ctc *c)
72 {
73 outer = c;
74 location = 0;
75 inner = nullptr;
76 }
78 {
79 // clean up
80 for (auto it = vector_ctc.rbegin(); it != vector_ctc.rend(); ++it)
81 delete (*it);
82 for (auto it = vector_nc.rbegin(); it != vector_nc.rend(); ++it)
83 delete (*it);
84 for (auto it = vector_f.rbegin(); it != vector_f.rend(); ++it)
85 delete (*it);
86 }
87
88 void set_outer(ibex::Ctc *outer)
89 {
90 Contractor::outer = outer;
91 }
92 void set_inner(ibex::Ctc *inner)
93 {
94 Contractor::inner = inner;
95 }
96 void set_location(unsigned int location)
97 {
98 Contractor::location = location;
99 }
100 ibex::Ctc *get_outer() const
101 {
102 return outer;
103 }
104 ibex::Ctc *get_inner() const
105 {
106 return inner;
107 }
108 unsigned int get_location() const
109 {
110 return location;
111 }
112
113private:
114 // Cleanup
115 std::vector<ibex::Function *> vector_f;
116 std::vector<ibex::NumConstraint *> vector_nc;
117 std::vector<ibex::Ctc *> vector_ctc;
118
119 ibex::Ctc *get_complement_contractor(ibex::Ctc *c)
120 {
121 if (auto ctc_compo = dynamic_cast<ibex::CtcCompo *>(c))
122 {
123 ibex::Array<ibex::Ctc> list_of_contractors;
124 for (auto &it : ctc_compo->list)
125 list_of_contractors.add(*get_complement_contractor(&it));
126 auto ctc_union = new ibex::CtcUnion(list_of_contractors);
127 vector_ctc.push_back(ctc_union);
128 return c;
129 }
130 else if (auto ctc_union = dynamic_cast<ibex::CtcUnion *>(c))
131 {
132 ibex::Array<ibex::Ctc> list_of_contractors;
133 for (auto &it : ctc_union->list)
134 list_of_contractors.add(*get_complement_contractor(&it));
135 auto ctc_compo = new ibex::CtcCompo(list_of_contractors);
136 vector_ctc.push_back(ctc_compo);
137 return ctc_compo;
138 }
139 else if (auto fwdbwd = dynamic_cast<ibex::CtcFwdBwd *>(c))
140 {
141 ibex::NumConstraint *ctr;
142 ibex::CtcFwdBwd *contractor;
143 switch (fwdbwd->ctr.op)
144 {
145 case ibex::GEQ:
146 ctr = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::LT);
147 vector_nc.push_back(ctr);
148 contractor = new ibex::CtcFwdBwd(*ctr);
149 vector_ctc.push_back(contractor);
150 return contractor;
151 case ibex::GT:
152 ctr = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::LEQ);
153 vector_nc.push_back(ctr);
154 contractor = new ibex::CtcFwdBwd(*ctr);
155 vector_ctc.push_back(contractor);
156 return contractor;
157 case ibex::LEQ:
158 ctr = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::GT);
159 vector_nc.push_back(ctr);
160 contractor = new ibex::CtcFwdBwd(*ctr);
161 vector_ctc.push_back(contractor);
162 return contractor;
163 case ibex::LT:
164 ctr = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::GEQ);
165 vector_nc.push_back(ctr);
166 contractor = new ibex::CtcFwdBwd(*ctr);
167 vector_ctc.push_back(contractor);
168 return contractor;
169 case ibex::EQ:
170 ctr = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::GT);
171 auto ctr2 = new ibex::NumConstraint(fwdbwd->ctr.f, ibex::LT);
172 auto *side1 = new ibex::CtcFwdBwd(*ctr);
173 auto *side2 = new ibex::CtcFwdBwd(*ctr2);
174 auto ctc_union = new ibex::CtcUnion(*side1, *side2);
175 // for clean up
176 vector_nc.push_back(ctr);
177 vector_nc.push_back(ctr2);
178 vector_ctc.push_back(side1);
179 vector_ctc.push_back(side2);
180 vector_ctc.push_back(ctc_union);
181
182 return ctc_union;
183 }
184 }
185 else
186 {
187 log_debug("contractor", "Contractors: Unsupported Ctc type");
188 }
189 return nullptr;
190 }
191};
192
194{
195private:
196 Contractor *c;
197 std::list<Contractor *> contractors;
198
199public:
201 {
202 c = nullptr;
203 }
205 {
206 if (c != nullptr)
207 {
208 if (c->get_outer() != nullptr)
209 delete (c->get_outer());
210 if (c->get_inner() != nullptr)
211 delete (c->get_inner());
212 delete (c);
213 }
214 for (auto cont : contractors)
215 delete (cont);
216 }
218 {
219 c = new Contractor();
220
221 auto size = contractors.size();
222 ibex::Array<ibex::Ctc> outer[size];
223 ibex::Array<ibex::Ctc> inner[size];
224 for (auto const &ctc : contractors)
225 if (ctc->get_location() < loc)
226 {
227 outer->add(*(ctc->get_outer()));
228 inner->add(*(ctc->get_inner()));
229 }
230
231 c->set_outer(new ibex::CtcCompo(*outer));
232 c->set_inner(new ibex::CtcUnion(*inner));
233 c->set_location(0);
234 return c;
235 }
236
238 {
239 Contractor *c = new Contractor();
240
241 auto size = contractors.size();
242 ibex::Array<ibex::Ctc> outer[size];
243 ibex::Array<ibex::Ctc> inner[size];
244 for (auto const &ctc : contractors)
245 {
246 outer->add(*(ctc->get_outer()));
247 inner->add(*(ctc->get_inner()));
248 }
249 c->set_outer(new ibex::CtcCompo(*outer));
250 c->set_inner(new ibex::CtcUnion(*inner));
251 c->set_location(0);
252 return c;
253 }
254
255 void dump()
256 {
257 std::ostringstream oss;
258
259 for (auto const &c : contractors)
260 {
261 oss << "outer :" << to_oss(c->get_outer()).str() << "\n";
262 oss << "inner :" << to_oss(c->get_inner()).str() << "\n";
263 oss << "location :" << c->get_location() << "\n";
264 }
265 log_debug("contractor", "{}", oss.str());
266 }
267 std::ostringstream list_to_oss(ibex::Array<ibex::Ctc> *list, bool is_compo)
268 {
269 std::ostringstream oss;
270 auto it = list->begin();
271 oss << "( " << to_oss(&*it).str();
272 it++;
273 while (it != list->end())
274 {
275 oss << (is_compo ? " && " : " || ") << to_oss(&*it).str();
276 it++;
277 }
278 oss << " )";
279 return oss;
280 }
281 std::ostringstream to_oss(ibex::Ctc *c)
282 {
283 std::ostringstream oss;
284 if (auto ctc_compo = dynamic_cast<ibex::CtcCompo *>(c))
285 oss = list_to_oss(&ctc_compo->list, true);
286 else if (auto ctc_union = dynamic_cast<ibex::CtcUnion *>(c))
287 oss = list_to_oss(&ctc_union->list, false);
288 else if (auto fwdbwd = dynamic_cast<ibex::CtcFwdBwd *>(c))
289 oss << fwdbwd->ctr;
290
291 return oss;
292 }
293
294 void add_contractor(ibex::Ctc *ctc, unsigned int loc)
295 {
296 if (ctc != nullptr)
297 {
298 Contractor *c = new Contractor(ctc, loc);
299 contractors.insert(contractors.end(), c);
300 }
301 }
302 bool is_empty()
303 {
304 return contractors.empty();
305 }
306};
307
315{
316public:
317 static constexpr int MAX_VAR = 20;
318 static constexpr int NOT_FOUND = -1;
319 static constexpr int IGNORE = -2;
320
321 std::map<std::string, vart> var_map;
322
323 CspMap() = default;
324
325 size_t add_var(const std::string &name, const expr2tc &symbol)
326 {
327 auto find = var_map.find(name);
328 if (find == var_map.end())
329 {
330 vart var(name, symbol, n);
331 var_map.insert(std::make_pair(name, var));
332 n++;
333 return n - 1;
334 }
335 return find->second.getIndex();
336 }
337
338 void update_lb_interval(double lb, const std::string &name)
339 {
340 auto find = var_map.find(name);
341 if (find == var_map.end())
342 return;
343 ibex::Interval X(lb, find->second.getInterval().ub());
344 find->second.setInterval(X);
345 }
346 void update_ub_interval(double ub, const std::string &name)
347 {
348 auto find = var_map.find(name);
349 if (find == var_map.end())
350 return;
351 ibex::Interval X(find->second.getInterval().lb(), ub);
352 find->second.setInterval(X);
353 }
354 int find(const std::string &name)
355 {
356 auto find = var_map.find(name);
357 if (find == var_map.end())
358 return NOT_FOUND;
359 return find->second.getIndex();
360 }
361 size_t size() const
362 {
363 return n;
364 }
365
366 ibex::IntervalVector create_interval_vector()
367 {
368 if (this->is_empty_vector)
369 return ibex::IntervalVector::empty(var_map.size());
370
371 ibex::IntervalVector X(var_map.size());
372 for (auto const &var : var_map)
373 X[var.second.getIndex()] = var.second.getInterval();
374 return X;
375 }
376
377 void update_intervals(ibex::IntervalVector vector)
378 {
379 // check if interval box is empty set or if the interval is degenerated
380 // in the case of a single interval
381 if (vector.is_empty())
382 {
383 is_empty_vector = true;
384 return;
385 }
386
387 for (auto &var : var_map)
388 {
389 if (var.second.getInterval() != vector[var.second.getIndex()])
390 {
391 var.second.setInterval(vector[var.second.getIndex()]);
392 var.second.setIntervalChanged(true);
393 }
394 }
395 }
396
397private:
398 size_t n = 0;
399 bool is_empty_vector = false;
400
401public:
402 bool is_empty_set() const
403 {
404 return is_empty_vector;
405 }
406 void dump()
407 {
408 std::ostringstream oss;
409 oss << "This map has : " << this->n;
410 if (is_empty_vector)
411 {
412 oss << "empty vector";
413 log_status("{}", oss.str());
414 return;
415 }
416 log_status("{}", oss.str());
417
418 for (const auto &var : var_map)
419 {
420 var.second.dump();
421 }
422 }
423};
424//-----------------------------------------------------------------------------------------------------------------
427{
428private:
429 CspMap *map;
430 ibex::Variable *vars = nullptr;
431
432 // Cleanup
433 std::vector<ibex::Function *> vector_f;
434 std::vector<ibex::NumConstraint *> vector_nc;
435 std::vector<ibex::Ctc *> vector_ctc;
436
437 static bool is_constraint_operator(const expr2tc &);
438 static bool is_unsupported_operator_in_constraint(const expr2tc &);
439 ibex::Ctc *create_contractor_from_expr2t(const expr2tc &);
447 ibex::NumConstraint *create_constraint_from_expr2t(const expr2tc &);
454 // not
455 ibex::Ctc *create_contractor_from_expr2t_not(const expr2tc &);
456 ibex::NumConstraint *create_constraint_from_expr2t_not(const expr2tc &);
457
458 ibex::Function *create_function_from_expr2t(const expr2tc &);
459 int create_variable_from_expr2t(const expr2tc &);
460 void parse_error(const expr2tc &);
461 bool is_constraint_operator_not(const expr2tc &expr);
462 bool is_unsupported_operator_in_constraint_not(const expr2tc &expr);
463
464public:
465 expr_to_ibex_parser(CspMap *map, ibex::Variable *vars)
466 {
467 this->map = map;
468 this->vars = vars;
469 }
472 {
473 return create_contractor_from_expr2t(expr);
474 }
476 {
477 // clean up
478 for (auto it = vector_ctc.rbegin(); it != vector_ctc.rend(); ++it)
479 delete (*it);
480 for (auto it = vector_nc.rbegin(); it != vector_nc.rend(); ++it)
481 delete (*it);
482 for (auto it = vector_f.rbegin(); it != vector_f.rend(); ++it)
483 delete (*it);
484 }
485};
486//-----------------------------------------------------------------------------------------------------------------
488{
489public:
491 const namespacet &namespacet,
492 const optionst &optionst);
493
505 goto_functionst &_goto_functions,
506 const namespacet &ns,
507 const optionst &options)
508 : goto_functions_algorithm(true), goto_functions(_goto_functions)
509 {
510 if (options.get_bool_option("goto-contractor-condition"))
511 {
512 vars = new ibex::Variable(CspMap::MAX_VAR);
513 goto_contractor_condition(ns, options);
514 }
515 else
516 {
517 initialize_main_function_loops();
518 if (!function_loops.empty())
519 {
520 vars = new ibex::Variable(CspMap::MAX_VAR);
521 parser = expr_to_ibex_parser(&map, vars);
522 log_debug(
523 "contractor", "1/4 - Parsing asserts to create CSP Constraints.");
524 get_contractors(_goto_functions);
525 if (contractors.is_empty())
526 {
527 log_debug(
528 "contractor",
529 "Contractors: expression not supported, No Contractors were "
530 "created.");
531 return;
532 }
533 contractors.dump();
534 log_debug(
535 "contractor",
536 "2/4 - Parsing assumes to set values for variables intervals.");
537 get_intervals(_goto_functions, ns);
538
539 log_debug("contractor", "3/4 - Applying contractor.");
540 apply_contractor();
541
542 log_debug("contractor", "4/4 - Inserting assumes.");
543 insert_assume(_goto_functions);
544 }
545 }
546 }
547
548protected:
550
551private:
552 ibex::IntervalVector domains;
554 ibex::Variable *vars;
556 CspMap map;
560 Contractors contractors;
561
562 unsigned number_of_functions = 0;
563
564 typedef std::list<loopst> function_loopst;
565 function_loopst function_loops;
566
575 void get_contractors(goto_functionst goto_functions);
576
584 void get_intervals(goto_functionst functionst, const namespacet &namespacet);
585
591 void apply_contractor();
592
598 ibex::CmpOp get_complement(ibex::CmpOp);
611 void insert_assume(goto_functionst goto_functions);
612
613 void parse_intervals(const expr2tc &orig_expr);
614
615 bool initialize_main_function_loops();
616
617 void insert_assume_at(
618 goto_functiont goto_function,
619 goto_programt::targett instruction);
620};
621//-----------------------------------------------------------------------------------------------------------------
623{
624 /* Declared first so it is set before, and restored after, every other member
625 * touches ibex. */
626 host_rounding_mode ibex_rounding{FE_UPWARD};
627
628public:
630
632 {
633 vars = new ibex::Variable(CspMap::MAX_VAR);
634 map = CspMap();
635 parser = expr_to_ibex_parser(&map, vars);
636 }
638 {
639 delete (vars);
640 }
641
642 bool parse_guard(expr2tc &guard)
643 {
644 auto t_0 = std::chrono::steady_clock::now();
645 ibex::Ctc *c = parser.parse(guard);
646 parse_time =
647 std::chrono::duration<double>(std::chrono::steady_clock::now() - t_0)
648 .count();
649
650 if (c == nullptr)
651 return false;
652 else if (map.var_map.size() == 0)
653 return false;
654
655 contractor = Contractor(c);
656 return true;
657 }
658
659 // void maps_to_domains(int_mapt, real_mapt);
660
661 void apply_contractor();
662
664
665 void dump(bool is_timed);
666
667 [[maybe_unused]] void modularize_intervals();
668
670 const std::optional<BigInt> &lower,
671 const std::optional<BigInt> &upper,
672 const std::string &name)
673 {
674 if (lower)
675 map.update_lb_interval(lower->to_int64(), name);
676 if (upper)
677 map.update_ub_interval(upper->to_int64(), name);
678 }
679
681 const std::optional<double> &lower,
682 const std::optional<double> &upper,
683 const std::string &name)
684 {
685 if (lower)
686 map.update_lb_interval(*lower, name);
687 if (upper)
688 map.update_ub_interval(*upper, name);
689 }
690
691private:
692 ibex::IntervalVector domains;
694 ibex::Variable *vars;
696 CspMap map;
697 CspMap map_outer;
701 Contractor contractor{};
702
703 void _dump()
704 {
705 std::ostringstream oss;
706 auto c = contractor;
707 oss << "constraint :" << to_oss(c.get_outer()).str();
708 log_debug("contractor", "{}", oss.str());
709 }
710 std::ostringstream list_to_oss(ibex::Array<ibex::Ctc> *list, bool is_compo)
711 {
712 std::ostringstream oss;
713 auto it = list->begin();
714 oss << "( " << to_oss(&*it).str();
715 it++;
716 while (it != list->end())
717 {
718 oss << (is_compo ? " && " : " || ") << to_oss(&*it).str();
719 it++;
720 }
721 oss << " )";
722 return oss;
723 }
724 std::ostringstream to_oss(ibex::Ctc *c)
725 {
726 std::ostringstream oss;
727 if (auto ctc_compo = dynamic_cast<ibex::CtcCompo *>(c))
728 oss = list_to_oss(&ctc_compo->list, true);
729 else if (auto ctc_union = dynamic_cast<ibex::CtcUnion *>(c))
730 oss = list_to_oss(&ctc_union->list, false);
731 else if (auto fwdbwd = dynamic_cast<ibex::CtcFwdBwd *>(c))
732 oss << fwdbwd->ctr;
733
734 return oss;
735 }
736};
737#endif // ESBMC_GOTO_CONTRACTOR_H
Definition goto_contractor.h:53
~Contractor()
Definition goto_contractor.h:77
Contractor(ibex::Ctc *c)
Definition goto_contractor.h:71
ibex::Ctc * get_inner() const
Definition goto_contractor.h:104
ibex::Ctc * get_outer() const
Definition goto_contractor.h:100
Contractor()
Definition goto_contractor.h:59
Contractor(ibex::Ctc *c, unsigned int loc)
Definition goto_contractor.h:65
void set_outer(ibex::Ctc *outer)
Definition goto_contractor.h:88
void set_inner(ibex::Ctc *inner)
Definition goto_contractor.h:92
void set_location(unsigned int location)
Definition goto_contractor.h:96
unsigned int get_location() const
Definition goto_contractor.h:108
Definition goto_contractor.h:194
void dump()
Definition goto_contractor.h:255
std::ostringstream to_oss(ibex::Ctc *c)
Definition goto_contractor.h:281
Contractor * get_contractors_up_to_loc(unsigned int loc)
Definition goto_contractor.h:217
void add_contractor(ibex::Ctc *ctc, unsigned int loc)
Definition goto_contractor.h:294
std::ostringstream list_to_oss(ibex::Array< ibex::Ctc > *list, bool is_compo)
Definition goto_contractor.h:267
~Contractors()
Definition goto_contractor.h:204
bool is_empty()
Definition goto_contractor.h:302
Contractors()
Definition goto_contractor.h:200
Contractor * get_contractors()
Definition goto_contractor.h:237
This class is for mapping the variables with their names and intervals.
Definition goto_contractor.h:315
int find(const std::string &name)
Definition goto_contractor.h:354
void update_ub_interval(double ub, const std::string &name)
Definition goto_contractor.h:346
void update_lb_interval(double lb, const std::string &name)
Definition goto_contractor.h:338
ibex::IntervalVector create_interval_vector()
Definition goto_contractor.h:366
void update_intervals(ibex::IntervalVector vector)
Definition goto_contractor.h:377
static constexpr int MAX_VAR
Definition goto_contractor.h:317
CspMap()=default
static constexpr int NOT_FOUND
Definition goto_contractor.h:318
std::map< std::string, vart > var_map
Definition goto_contractor.h:321
bool is_empty_set() const
Definition goto_contractor.h:402
static constexpr int IGNORE
Definition goto_contractor.h:319
size_t size() const
Definition goto_contractor.h:361
size_t add_var(const std::string &name, const expr2tc &symbol)
Definition goto_contractor.h:325
void dump()
Definition goto_contractor.h:406
This class will parse ESBMC expressions to ibex expressions:
Definition goto_contractor.h:427
~expr_to_ibex_parser()
Definition goto_contractor.h:475
ibex::Ctc * parse(irep_container< expr2t > expr)
Definition goto_contractor.h:471
expr_to_ibex_parser()=default
expr_to_ibex_parser(CspMap *map, ibex::Variable *vars)
Definition goto_contractor.h:465
void goto_contractor_condition(const namespacet &namespacet, const optionst &optionst)
Definition goto_contractor.cpp:305
goto_contractort(goto_functionst &_goto_functions, const namespacet &ns, const optionst &options)
This constructor will run the goto-contractor procedure.
Definition goto_contractor.h:504
goto_functionst & goto_functions
Definition goto_contractor.h:549
goto_functions_algorithm(bool sideffect)
Definition goto_functions_algorithm.h:13
Definition goto_functions.h:56
Definition goto_functions.h:23
instructionst::iterator targett
Definition goto_program.h:590
Definition host_rounding_mode.h:13
void interval_to_domain(const std::optional< BigInt > &lower, const std::optional< BigInt > &upper, const std::string &name)
Definition goto_contractor.h:669
bool parse_guard(expr2tc &guard)
Definition goto_contractor.h:642
~interval_analysis_ibex_contractor()
Definition goto_contractor.h:637
void dump(bool is_timed)
Definition goto_contractor.cpp:1061
void apply_contractor()
Definition goto_contractor.cpp:966
void modularize_intervals()
Definition goto_contractor.cpp:1086
double cpy_time
Definition goto_contractor.h:629
double parse_time
Definition goto_contractor.h:629
void interval_to_domain(const std::optional< double > &lower, const std::optional< double > &upper, const std::string &name)
Definition goto_contractor.h:680
double apply_time
Definition goto_contractor.h:629
interval_analysis_ibex_contractor()
Definition goto_contractor.h:631
expr2tc result_of_outer()
Definition goto_contractor.cpp:992
double mod_time
Definition goto_contractor.h:629
Reference counted container for irep2 nodes.
Definition irep2.h:144
Definition namespace.h:10
Definition options.h:11
bool get_bool_option(const std::string &option) const
Definition options.cpp:29
Definition goto_contractor.h:32
bool isIntervalChanged() const
Definition goto_contractor.cpp:468
size_t getIndex() const
Definition goto_contractor.cpp:450
const ibex::Interval & getInterval() const
Definition goto_contractor.cpp:445
void setIntervalChanged(bool intervalChanged)
Definition goto_contractor.cpp:473
void dump() const
Definition goto_contractor.cpp:487
vart()
Definition goto_contractor.cpp:483
void setInterval(const ibex::Interval &interval)
Definition goto_contractor.cpp:463
const expr2tc & getSymbol() const
Definition goto_contractor.cpp:478
void goto_contractor(goto_functionst &goto_functions, const namespacet &namespacet, const optionst &options)
Definition goto_contractor.cpp:5
Interval Analysis.
Classes and definitions for non-stringy internal representation.
irep_container< expr2t > expr2tc
Definition irep2.h:431
#define log_debug(mod, fmt,...)
Definition message.h:104
#define log_status(fmt,...)
Definition message.h:101
Definition __init__.py:1
static std::string lower(std::string s)
Definition st_fb_translator.cpp:95
#define true
Definition stdbool.h:11