1 /*
2
3 Cadabra: a field-theory motivated computer algebra system.
4 Copyright (C) 2001-2014 Kasper Peeters <kasper.peeters@phi-sci.com>
5
6 This program is free software: you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "Storage.hh"
22 #include "Combinatorics.hh"
23 #include "Exceptions.hh"
24 #include <iomanip>
25 #include <sstream>
26 #include <locale>
27 #include <codecvt>
28 #include <pcrecpp.h>
29
30 #include <boost/functional/hash.hpp>
31
32 //#define DEBUG 1
33
34 namespace cadabra {
35
36 nset_t name_set;
37 rset_t rat_set;
38
to_long(multiplier_t mul)39 long to_long(multiplier_t mul)
40 {
41 return mul.get_num().get_si();
42 }
43
to_string(long num)44 std::string to_string(long num)
45 {
46 std::ostringstream str;
47 str << num;
48 return str.str();
49 }
50
51 // Expression constructor/destructor members.
52
Ex()53 Ex::Ex()
54 : tree<str_node>(), state_(result_t::l_no_action)
55 {
56 }
57
Ex(tree<str_node>::iterator it)58 Ex::Ex(tree<str_node>::iterator it)
59 : tree<str_node>(it), state_(result_t::l_no_action)
60 {
61 }
62
Ex(const str_node & x)63 Ex::Ex(const str_node& x)
64 : tree<str_node>(x), state_(result_t::l_no_action)
65 {
66 }
67
Ex(const Ex & other)68 Ex::Ex(const Ex& other)
69 : std::enable_shared_from_this<Ex>(other), tree<str_node>(other), state_(result_t::l_no_action)
70 {
71 // std::cout << "Ex copy constructor" << std::endl;
72 }
73
Ex(const std::string & str)74 Ex::Ex(const std::string& str)
75 : state_(result_t::l_no_action)
76 {
77 set_head(str_node(str));
78 }
79
Ex(int val)80 Ex::Ex(int val)
81 : state_(result_t::l_no_action)
82 {
83 set_head(str_node("1"));
84 multiply(begin()->multiplier, val);
85 }
86
state() const87 Ex::result_t Ex::state() const
88 {
89 return state_;
90 }
91
update_state(Ex::result_t newstate)92 void Ex::update_state(Ex::result_t newstate)
93 {
94 switch(newstate) {
95 case Ex::result_t::l_error:
96 state_=newstate;
97 break;
98 case Ex::result_t::l_applied:
99 if(state_!=Ex::result_t::l_error)
100 state_=newstate;
101 break;
102 default:
103 break;
104 }
105 }
106
reset_state()107 void Ex::reset_state()
108 {
109 state_=Ex::result_t::l_checkpointed;
110 }
111
changed_state()112 bool Ex::changed_state()
113 {
114 bool ret=false;
115 if(state_==result_t::l_checkpointed || state_==result_t::l_applied) ret=true;
116 state_=result_t::l_no_action;
117 return ret;
118 }
119
is_rational() const120 bool Ex::is_rational() const
121 {
122 if(begin()!=end())
123 if(begin()->is_rational())
124 return true;
125 return false;
126 }
127
to_rational() const128 multiplier_t Ex::to_rational() const
129 {
130 if(!is_rational())
131 throw InternalError("Called to_rational() on non-rational Ex");
132 return *(begin()->multiplier);
133 }
134
is_integer() const135 bool Ex::is_integer() const
136 {
137 if(begin()!=end())
138 if(begin()->is_integer())
139 return true;
140 return false;
141 }
142
to_integer() const143 long Ex::to_integer() const
144 {
145 if(!is_integer())
146 throw InternalError("Called to_integer() on non-integer Ex");
147 return to_long(*(begin()->multiplier));
148 }
149
print_python(std::ostream & str,Ex::iterator it)150 std::ostream& Ex::print_python(std::ostream& str, Ex::iterator it)
151 {
152 std::string name(*(*it).name);
153 std::string res;
154 if(*it->multiplier!=1)
155 str << *it->multiplier;
156
157 for(unsigned int i=0; i<name.size(); ++i) {
158 if(name[i]=='#') res+="\\#";
159 // else if(name[i]=='\\') res+="\\backslash{}";
160 else res+=name[i];
161 }
162 str << res;
163
164 Ex::sibling_iterator beg=it.begin();
165 Ex::sibling_iterator fin=it.end();
166 str_node::bracket_t current_bracket=str_node::b_invalid;
167 str_node::parent_rel_t current_parent_rel=str_node::p_invalid;
168
169 while(beg!=fin) {
170 if(beg==it.begin() || current_parent_rel!=(*beg).fl.parent_rel) {
171 switch((*beg).fl.parent_rel) {
172 case str_node::p_super:
173 str << "^";
174 break;
175 case str_node::p_sub:
176 str << "_";
177 break;
178 case str_node::p_property:
179 str << "$";
180 break;
181 case str_node::p_exponent:
182 str << "&";
183 break;
184 default:
185 break;
186 }
187 current_parent_rel=(*beg).fl.parent_rel;
188 }
189 if(beg==it.begin() || current_bracket!=(*beg).fl.bracket || current_parent_rel!=(*beg).fl.parent_rel) {
190 switch((*beg).fl.bracket) {
191 case str_node::b_round:
192 str << "(";
193 break;
194 case str_node::b_square:
195 str << "[";
196 break;
197 case str_node::b_curly:
198 str << "{";
199 break;
200 case str_node::b_pointy:
201 str << "<";
202 break;
203 case str_node::b_none: {
204 if((*beg).fl.parent_rel==str_node::p_none) str << "(";
205 else str << "{";
206 }
207 break;
208 default:
209 break;
210 }
211 current_bracket=(*beg).fl.bracket;
212 }
213
214 print_python(str, beg);
215
216 auto nxt=beg;
217 ++nxt;
218 if(nxt!=fin) {
219 if((*beg).fl.parent_rel!=str_node::p_none)
220 str << " ";
221 }
222 if(nxt==fin || (*nxt).fl.bracket!=(*beg).fl.bracket || (*beg).fl.parent_rel==str_node::p_none) {
223 current_bracket=str_node::b_invalid;
224 current_parent_rel=str_node::p_invalid;
225 switch((*beg).fl.bracket) {
226 case str_node::b_round:
227 str << ")";
228 break;
229 case str_node::b_square:
230 str << "]";
231 break;
232 case str_node::b_curly:
233 str << "}";
234 break;
235 case str_node::b_pointy:
236 str << ">";
237 break;
238 case str_node::b_none: {
239 if((*beg).fl.parent_rel==str_node::p_none) str << ")";
240 else str << "}";
241 }
242 break;
243 default:
244 break;
245 }
246 }
247 ++beg;
248 }
249
250 return str;
251 }
252
print_repr(std::ostream & str,Ex::iterator it) const253 std::ostream& Ex::print_repr(std::ostream& str, Ex::iterator it) const
254 {
255 str << *it->name;
256 sibling_iterator sib=it.begin();
257 while(sib!=it.end()) {
258 print_repr(str, sib);
259 ++sib;
260 }
261 return str;
262 }
263
print_recursive_treeform(std::ostream & str,Ex::iterator it)264 std::ostream& Ex::print_recursive_treeform(std::ostream& str, Ex::iterator it)
265 {
266 unsigned int num=1;
267 switch((*it).fl.parent_rel) {
268 case str_node::p_super:
269 str << "^";
270 break;
271 case str_node::p_sub:
272 str << "_";
273 break;
274 case str_node::p_property:
275 str << "$";
276 break;
277 case str_node::p_exponent:
278 str << "&";
279 break;
280 default:
281 break;
282 }
283 return print_recursive_treeform(str, it, num);
284 }
285
print_entire_tree(std::ostream & str) const286 std::ostream& Ex::print_entire_tree(std::ostream& str) const
287 {
288 sibling_iterator sib=begin();
289 unsigned int num=1;
290 while(sib!=end()) {
291 print_recursive_treeform(str, sib, num);
292 ++sib;
293 ++num;
294 }
295 return str;
296 }
297
print_recursive_treeform(std::ostream & str,Ex::iterator it,unsigned int & num)298 std::ostream& Ex::print_recursive_treeform(std::ostream& str, Ex::iterator it, unsigned int& num)
299 {
300 bool compact_tree=getenv("CDB_COMPACTTREE");
301
302 Ex::sibling_iterator beg=it.begin();
303 Ex::sibling_iterator fin=it.end();
304
305 if((*it).fl.bracket ==str_node::b_round) str << "(";
306 else if((*it).fl.bracket ==str_node::b_square) str << "[";
307 else if((*it).fl.bracket ==str_node::b_curly) str << "\\{";
308 else if((*it).fl.bracket ==str_node::b_pointy) str << "\\<";
309 else if((*it).fl.bracket ==str_node::b_none) str << "{";
310 // if((*it).fl.mark) str << "\033[1m";
311 str << *(*it).name;
312 // if((*it).fl.mark) str << "\033[0m";
313 if((*it).fl.bracket ==str_node::b_round) str << ")";
314 else if((*it).fl.bracket ==str_node::b_square) str << "]";
315 else if((*it).fl.bracket ==str_node::b_curly) str << "\\}";
316 else if((*it).fl.bracket ==str_node::b_pointy) str << "\\>";
317 else if((*it).fl.bracket ==str_node::b_none) str << "}";
318
319 if(*it->multiplier!=multiplier_t(1)) {
320 if(compact_tree)
321 str << "#" << *it->multiplier;
322 else
323 str << " " << *it->multiplier;
324 }
325 // str << " (" << calc_hash(it) << ")";
326 // str << " (" << depth(it) << ")";
327 // str << " (" << it->fl.bracket << " " << &(*it) << ")";
328 str << " (" << it->fl.bracket << " " << it.node << ")";
329 if(!compact_tree) str << std::endl;
330
331 while(beg!=fin) {
332 int offset=1;
333 if(num && !compact_tree) {
334 str << std::setw(3) << num << ":";
335 offset=1;
336 }
337 if(!compact_tree)
338 for(int i=offset; i<depth(beg); ++i)
339 str << " ";
340 switch((*beg).fl.parent_rel) {
341 case str_node::p_super:
342 str << "^";
343 break;
344 case str_node::p_sub:
345 str << "_";
346 break;
347 case str_node::p_property:
348 str << "$";
349 break;
350 case str_node::p_exponent:
351 str << "&";
352 break;
353 default:
354 break;
355 }
356 if(num) ++num;
357 print_recursive_treeform(str, beg, num);
358 ++beg;
359 }
360 return str;
361 }
362
363
364 // std::ostream& operator<<(std::ostream& str, const Ex& tr)
365 // {
366 // unsigned int number=1;
367 // Ex::iterator it=tr.begin();
368 // while(it!=tr.end()) {
369 // tr.print_recursive_infix(str, it, number, true);
370 // it.skip_children();
371 // ++it;
372 // if(it!=tr.end())
373 // str << std::endl;
374 // }
375 // return str;
376 // }
377
named_parent(Ex::iterator it,const std::string & nm) const378 Ex::iterator Ex::named_parent(Ex::iterator it, const std::string& nm) const
379 {
380 // std::cout << "!!" << *it->name << std::endl << std::flush;
381 assert(is_valid(it));
382 while(*it->name!=nm /* && it->is_command()==false */) {
383 it=parent(it);
384 assert(is_valid(it));
385 // std::cout << " !!" << *it->name << std::endl << std::flush;
386 }
387 // std::cout << " out" << std::endl;
388 return it;
389 }
390
erase_expression(Ex::iterator it)391 Ex::iterator Ex::erase_expression(Ex::iterator it)
392 {
393 it=named_parent(it, "\\history");
394 return erase(it);
395 }
396
397
calc_hash(iterator it) const398 hashval_t Ex::calc_hash(iterator it) const
399 {
400 // Hash values do not contain info about the multiplier field,
401 // nor do they know about the type of the links (FIXME: is the latter
402 // the correct thing to do?)
403 //
404 // If this algorithm is changed, factorise::calc_restricted_hash in
405 // core/algorithms/factor_in.cc should also be modified!
406
407 iterator end=it;
408 end.skip_children();
409 ++end;
410 it.skip_children(false);
411
412 hashval_t seed = 0;
413 while(it!=end) {
414 boost::hash_combine(seed, *it->name);
415 ++it;
416 }
417
418 return seed;
419 }
420
arg(iterator it,unsigned int num)421 Ex::sibling_iterator Ex::arg(iterator it, unsigned int num)
422 {
423 if(*it->name=="\\comma") {
424 assert(Ex::number_of_children(it)>num);
425 return Ex::child(it,num);
426 }
427 else return it;
428 }
429
arg_size(sibling_iterator sib)430 unsigned int Ex::arg_size(sibling_iterator sib)
431 {
432 if(*sib->name=="\\comma") return Ex::number_of_children(sib);
433 else return 1;
434 }
435
arg_to_num(sibling_iterator sib,unsigned int num) const436 multiplier_t Ex::arg_to_num(sibling_iterator sib, unsigned int num) const
437 {
438 sibling_iterator nod;
439 if(*sib->name=="\\comma") nod=child(sib,num);
440 else nod=sib;
441 return *nod->multiplier;
442 }
443
equation_number(Ex::iterator it) const444 unsigned int Ex::equation_number(Ex::iterator it) const
445 {
446 iterator historynode=named_parent(it, "\\history");
447 unsigned int num=0;
448 iterator sit=begin();
449 // long totravel=0;
450 while(sit!=end()) {
451 // ++totravel;
452 if(*sit->name=="\\history") {
453 ++num;
454 if(historynode==sit) {
455 // txtout << "had to travel " << totravel << std::endl;
456 return num;
457 }
458 }
459 sit.skip_children();
460 ++sit;
461 }
462 return 0;
463 }
464
equation_label(Ex::iterator it) const465 nset_t::iterator Ex::equation_label(Ex::iterator it) const
466 {
467 nset_t::iterator ret=name_set.end();
468
469 iterator sit=begin();
470 while(sit!=end()) {
471 if(*sit->name=="\\history") {
472 if(it==sit)
473 goto found;
474 iterator eit=begin(sit);
475 iterator endit=sit;
476 endit.skip_children();
477 ++endit;
478 while(eit!=endit) {
479 if(it==eit)
480 goto found;
481 ++eit;
482 }
483 sit.skip_children();
484 }
485 ++sit;
486 }
487 found:
488 if(sit!=end()) {
489 sibling_iterator lit=begin(sit);
490 while(lit!=end(sit)) {
491 if(*lit->name=="\\label") {
492 ret=begin(lit)->name;
493 break;
494 }
495 ++lit;
496 }
497 }
498 return ret;
499 }
500
501 // Always returns the \\history node of the equation (i.e. the top node).
equation_by_number(unsigned int i) const502 Ex::iterator Ex::equation_by_number(unsigned int i) const
503 {
504 iterator it=begin();
505 unsigned int num=1;
506 while(it!=end()) {
507 if(*it->name=="\\history") {
508 if(num==i) return it;
509 else ++num;
510 }
511 it.skip_children();
512 ++it;
513 }
514 return it;
515 // if(num==number_of_siblings(begin()))
516 // return end();
517 // return it;
518 }
519
equation_by_name(nset_t::iterator nit) const520 Ex::iterator Ex::equation_by_name(nset_t::iterator nit) const
521 {
522 unsigned int tmp;
523 return equation_by_name(nit, tmp);
524 }
525
equation_by_name(nset_t::iterator nit,unsigned int & tmp) const526 Ex::iterator Ex::equation_by_name(nset_t::iterator nit, unsigned int& tmp) const
527 {
528 unsigned int num=0;
529 iterator it=begin();
530 while(it!=end()) {
531 if(*it->name=="\\history") {
532 ++num;
533 sibling_iterator lit=begin(it);
534 while(lit!=end(it)) {
535 if(*lit->name=="\\label") {
536 if(begin(lit)->name==nit) {
537 tmp=num;
538 return it;
539 }
540 }
541 ++lit;
542 }
543 }
544 it.skip_children();
545 ++it;
546 }
547 return end();
548 }
549
is_hidden(iterator it) const550 bool Ex::is_hidden(iterator it) const
551 {
552 do {
553 if(*it->name=="\\ldots") return true;
554 if(is_head(it)) break;
555 it=parent(it);
556 }
557 while(true);
558 return false;
559 }
560
procedure_by_name(nset_t::iterator nit) const561 Ex::iterator Ex::procedure_by_name(nset_t::iterator nit) const
562 {
563 iterator it=begin();
564 while(it!=end()) {
565 if(*it->name=="\\procedure") {
566 sibling_iterator lit=begin(it);
567 while(lit!=end(it)) {
568 if(*lit->name=="\\label") {
569 if(begin(lit)->name==nit)
570 return it;
571 }
572 ++lit;
573 }
574 }
575 it.skip_children();
576 ++it;
577 }
578 return end();
579 }
580
replace_index(iterator pos,const iterator & from,bool keep_parent_rel)581 Ex::iterator Ex::replace_index(iterator pos, const iterator& from, bool keep_parent_rel)
582 {
583 // assert(pos->fl.parent_rel==str_node::p_sub || pos->fl.parent_rel==str_node::p_super);
584 str_node::bracket_t bt=pos->fl.bracket;
585 str_node::parent_rel_t pr=pos->fl.parent_rel;
586 iterator ret=replace(pos, from);
587 ret->fl.bracket=bt;
588 if(keep_parent_rel)
589 ret->fl.parent_rel=pr;
590 return ret;
591 }
592
move_index(iterator pos,const iterator & from)593 Ex::iterator Ex::move_index(iterator pos, const iterator& from)
594 {
595 // assert(pos->fl.parent_rel==str_node::p_sub || pos->fl.parent_rel==str_node::p_super);
596 str_node::bracket_t bt=pos->fl.bracket;
597 str_node::parent_rel_t pr=pos->fl.parent_rel;
598 move_ontop(pos, from);
599 from->fl.bracket=bt;
600 from->fl.parent_rel=pr;
601 return from;
602 }
603
list_wrap_single_element(iterator & it)604 void Ex::list_wrap_single_element(iterator& it)
605 {
606 if(*it->name!="\\comma") {
607 iterator commanode=insert(it, str_node("\\comma"));
608 sibling_iterator fr=it, to=it;
609 ++to;
610 reparent(commanode, fr, to);
611 it=commanode;
612 }
613 }
614
list_unwrap_single_element(iterator & it)615 void Ex::list_unwrap_single_element(iterator& it)
616 {
617 if(*it->name=="\\comma") {
618 if(number_of_children(it)==1) {
619 flatten(it);
620 it=erase(it);
621 }
622 }
623 }
624
flatten_and_erase(iterator pos)625 Ex::iterator Ex::flatten_and_erase(iterator pos)
626 {
627 // assert(number_of_children(pos)==1);
628
629 multiplier_t tmp=*pos->multiplier;
630 flatten(pos);
631 pos=erase(pos);
632 multiply(pos->multiplier, tmp);
633 return pos;
634 }
635
number_of_equations() const636 unsigned int Ex::number_of_equations() const
637 {
638 unsigned int last_eq=0;
639 iterator eq=begin();
640 while(eq!=end()) {
641 if(*eq->name=="\\history")
642 ++last_eq;
643 eq.skip_children();
644 ++eq;
645 }
646 return last_eq;
647 }
648
equation_by_number_or_name(iterator it,unsigned int last_used_equation,unsigned int & real_eqno) const649 Ex::iterator Ex::equation_by_number_or_name(iterator it, unsigned int last_used_equation,
650 unsigned int& real_eqno) const
651 {
652 iterator ret;
653 if(it->is_rational()) {
654 int eqno=static_cast<int>(it->multiplier->get_d());
655 real_eqno=eqno;
656 ret=equation_by_number(eqno);
657 }
658 else {
659 if(*it->name=="%") {
660 ret=equation_by_number(last_used_equation);
661 real_eqno=last_used_equation;
662 }
663 else {
664 ret=equation_by_name(it->name, real_eqno);
665 }
666 }
667 return ret;
668 }
669
equation_by_number_or_name(iterator it,unsigned int last_used_equation) const670 Ex::iterator Ex::equation_by_number_or_name(iterator it, unsigned int last_used_equation) const
671 {
672 unsigned int tmp;
673 return equation_by_number_or_name(it, last_used_equation, tmp);
674 }
675
equation_number_or_name(iterator it,unsigned int last_used_equation) const676 std::string Ex::equation_number_or_name(iterator it, unsigned int last_used_equation) const
677 {
678 std::stringstream ss;
679 if(it->is_rational()) {
680 int eqno=static_cast<int>(it->multiplier->get_d());
681 ss << eqno;
682 }
683 else {
684 if(*it->name=="%") ss << last_used_equation;
685 else ss << *it->name;
686 }
687 return ss.str();
688 }
689
operator ==(const Ex & other) const690 bool Ex::operator==(const Ex& other) const
691 {
692 return equal_subtree(begin(), other.begin());
693 }
694
push_history(const std::vector<Ex::path_t> & paths)695 void Ex::push_history(const std::vector<Ex::path_t>& paths)
696 {
697 history.push_back(*this);
698 terms.push_back(paths);
699 }
700
pop_history()701 std::vector<Ex::path_t> Ex::pop_history()
702 {
703 tree<str_node>::operator=(history.back());
704 history.pop_back();
705 auto ret(terms.back());
706 terms.pop_back();
707 return ret;
708 }
709
history_size() const710 int Ex::history_size() const
711 {
712 return history.size();
713 }
714
str_node(void)715 str_node::str_node(void)
716 {
717 multiplier=rat_set.insert(1).first;
718 // fl.modifier=m_none;
719 fl.bracket=b_none;
720 fl.parent_rel=p_none;
721 // fl.mark=0;
722 }
723
str_node(nset_t::iterator nm,bracket_t br,parent_rel_t pr)724 str_node::str_node(nset_t::iterator nm, bracket_t br, parent_rel_t pr)
725 {
726 multiplier=rat_set.insert(1).first;
727 name=nm;
728 // fl.modifier=m_none;
729 fl.bracket=br;
730 fl.parent_rel=pr;
731 // fl.mark=0;
732 }
733
str_node(const std::u32string & nm,bracket_t br,parent_rel_t pr)734 str_node::str_node(const std::u32string& nm, bracket_t br, parent_rel_t pr)
735 {
736 #ifdef _MSC_VER
737 std::wstring_convert<std::codecvt_utf8<int32_t>, int32_t> conv;
738 auto p = reinterpret_cast<const int32_t*>(nm.data());
739 std::string nm8 = conv.to_bytes(p, p + nm.size());
740 #else
741 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
742 std::string nm8=conv.to_bytes(nm);
743 #endif
744
745 #ifdef DEBUG
746 std::cerr << "str_node: " << nm8 << std::endl;
747 #endif
748 multiplier=rat_set.insert(1).first;
749 name=name_set.insert(nm8).first;
750 // fl.modifier=m_none;
751 fl.bracket=br;
752 fl.parent_rel=pr;
753 }
754
str_node(const std::string & nm,bracket_t br,parent_rel_t pr)755 str_node::str_node(const std::string& nm, bracket_t br, parent_rel_t pr)
756 {
757 multiplier=rat_set.insert(1).first;
758 name=name_set.insert(nm).first;
759 // fl.modifier=m_none;
760 fl.bracket=br;
761 fl.parent_rel=pr;
762 // fl.mark=0;
763 }
764
flip_parent_rel()765 void str_node::flip_parent_rel()
766 {
767 if(fl.parent_rel==p_super) fl.parent_rel=p_sub;
768 else if(fl.parent_rel==p_sub) fl.parent_rel=p_super;
769 else throw std::logic_error("flip_parent_rel called on non-index");
770 }
771
is_zero() const772 bool str_node::is_zero() const
773 {
774 if(*multiplier==0) return true;
775 return false;
776 }
777
is_identity() const778 bool str_node::is_identity() const
779 {
780 if(*name=="1" && *multiplier==1) return true;
781 return false;
782 }
783
is_rational() const784 bool str_node::is_rational() const
785 {
786 return (*name=="1");
787 }
788
is_integer() const789 bool str_node::is_integer() const
790 {
791 if(*name=="1") {
792 if(multiplier->get_den()==1)
793 return true;
794 }
795 return false;
796 }
797
is_unsimplified_rational() const798 bool str_node::is_unsimplified_rational() const
799 {
800 if((*name).size()==0) return false;
801 for(unsigned int i=0; i<(*name).size(); ++i) {
802 if(!isdigit((*name)[i]) && (*name)[i]!='/' && (*name)[i]!='-')
803 return false;
804 }
805 return true;
806 }
807
is_unsimplified_integer() const808 bool str_node::is_unsimplified_integer() const
809 {
810 if((*name).size()==0) return false;
811 for(unsigned int i=0; i<(*name).size(); ++i) {
812 if(!isdigit((*name)[i]) && (*name)[i]!='-')
813 return false;
814 }
815 return true;
816 }
817
is_index() const818 bool str_node::is_index() const
819 {
820 if(fl.parent_rel==p_sub || fl.parent_rel==p_super) return true;
821 return false;
822 }
823
824
825
is_quoted_string() const826 bool str_node::is_quoted_string() const
827 {
828 if((*name).size()<2) return false;
829 if((*name)[0]!='\"') return false;
830 if((*name)[(*name).size()-1]!='\"') return false;
831 return true;
832 }
833
is_command() const834 bool str_node::is_command() const
835 {
836 if((*name).size()>0)
837 if((*name)[0]=='@') {
838 if((*name).size()>1) {
839 if((*name)[1]!='@')
840 return true;
841 }
842 else return true;
843 }
844 return false;
845 }
846
is_inert_command() const847 bool str_node::is_inert_command() const
848 {
849 if((*name).size()>1)
850 if((*name)[0]=='@')
851 if((*name)[1]=='@')
852 return true;
853 return false;
854 }
855
is_name_wildcard() const856 bool str_node::is_name_wildcard() const
857 {
858 if((*name).size()>0)
859 if((*name)[name->size()-1]=='?') {
860 if(name->size()>1) {
861 if((*name)[name->size()-2]!='?')
862 return true;
863 }
864 else return true;
865 }
866 return false;
867 }
868
is_object_wildcard() const869 bool str_node::is_object_wildcard() const
870 {
871 if((*name).size()>1)
872 if((*name)[name->size()-1]=='?')
873 if((*name)[name->size()-2]=='?')
874 return true;
875 return false;
876 }
877
is_range_wildcard() const878 bool str_node::is_range_wildcard() const
879 {
880 if(name->size()>0) {
881 if((*name)[0]=='#')
882 return true;
883 }
884 return false;
885 }
886
is_siblings_wildcard() const887 bool str_node::is_siblings_wildcard() const
888 {
889 if(name->size()>0) {
890 if((*name)[name->size()-1]=='@')
891 return true;
892 }
893 return false;
894 }
895
is_autodeclare_wildcard() const896 bool str_node::is_autodeclare_wildcard() const
897 {
898 if(name->size()>0)
899 if((*name)[name->size()-1]=='#')
900 return true;
901 return false;
902 }
903
is_indexstar_wildcard() const904 bool str_node::is_indexstar_wildcard() const
905 {
906 if((*name).size()>1)
907 if((*name)[name->size()-1]=='?')
908 if((*name)[name->size()-2]=='*')
909 return true;
910 return false;
911 }
912
is_indexplus_wildcard() const913 bool str_node::is_indexplus_wildcard() const
914 {
915 if((*name).size()>1)
916 if((*name)[name->size()-1]=='?')
917 if((*name)[name->size()-2]=='+')
918 return true;
919 return false;
920 }
921
is_numbered_symbol() const922 bool str_node::is_numbered_symbol() const
923 {
924 int len=(*name).size();
925 if(len>1)
926 if(isdigit((*name)[len-1]))
927 return true;
928 return false;
929 }
930
name_only()931 nset_t::iterator str_node::name_only()
932 {
933 if(is_name_wildcard()) {
934 std::string tmp=(*name).substr(0, name->size()-1);
935 return name_set.insert(tmp).first;
936 }
937 else if(is_object_wildcard()) {
938 std::string tmp=(*name).substr(0, name->size()-2);
939 return name_set.insert(tmp).first;
940 }
941 else if(is_autodeclare_wildcard()) {
942 size_t pos=name->find('#');
943 std::string tmp=(*name).substr(0, pos);
944 return name_set.insert(tmp).first;
945 }
946 else if(is_numbered_symbol()) {
947 size_t pos=name->find_first_of("0123456789");
948 std::string tmp=(*name).substr(0, pos);
949 return name_set.insert(tmp).first;
950 }
951 return name;
952 }
953
operator ==(const str_node & other) const954 bool str_node::operator==(const str_node& other) const
955 {
956 if(*name==*other.name &&
957 fl.bracket==other.fl.bracket &&
958 fl.parent_rel==other.fl.parent_rel &&
959 multiplier==other.multiplier)
960 return true;
961 else return false;
962 }
963
compare_names_only(const str_node & one,const str_node & two)964 bool str_node::compare_names_only(const str_node& one, const str_node& two)
965 {
966 if(one.name==two.name) return true;
967 else return false;
968 }
969
compare_name_brack_par(const str_node & one,const str_node & two)970 bool str_node::compare_name_brack_par(const str_node& one, const str_node& two)
971 {
972 if(one.name==two.name &&
973 one.fl.bracket==two.fl.bracket &&
974 one.fl.parent_rel==two.fl.parent_rel) return true;
975 else return false;
976 }
977
compare_name_inverse_par(const str_node & one,const str_node & two)978 bool str_node::compare_name_inverse_par(const str_node& one, const str_node& two)
979 {
980 if(one.name==two.name &&
981 ( (one.fl.parent_rel==str_node::p_super && two.fl.parent_rel==str_node::p_sub) ||
982 (one.fl.parent_rel==str_node::p_sub && two.fl.parent_rel==str_node::p_super)))
983 return true;
984 return false;
985 }
986
operator ()(nset_t::iterator first,nset_t::iterator second) const987 bool nset_it_less::operator()(nset_t::iterator first, nset_t::iterator second) const
988 {
989 if(*first < *second)
990 return true;
991 return false;
992 }
993
994
multiply(rset_t::iterator & num,multiplier_t fac)995 void multiply(rset_t::iterator& num, multiplier_t fac)
996 {
997 fac*=*num;
998 fac.canonicalize();
999 num=rat_set.insert(fac).first;
1000 }
1001
add(rset_t::iterator & num,multiplier_t fac)1002 void add(rset_t::iterator& num, multiplier_t fac)
1003 {
1004 fac+=*num;
1005 fac.canonicalize();
1006 num=rat_set.insert(fac).first;
1007 }
1008
zero(rset_t::iterator & num)1009 void zero(rset_t::iterator& num)
1010 {
1011 num=rat_set.insert(0).first;
1012 }
1013
one(rset_t::iterator & num)1014 void one(rset_t::iterator& num)
1015 {
1016 num=rat_set.insert(1).first;
1017 }
1018
flip_sign(rset_t::iterator & num)1019 void flip_sign(rset_t::iterator& num)
1020 {
1021 multiplier_t fac=-(*num);
1022 fac.canonicalize();
1023 num=rat_set.insert(fac).first;
1024 }
1025
half(rset_t::iterator & num)1026 void half(rset_t::iterator& num)
1027 {
1028 multiplier_t fac=(*num)/2;
1029 fac.canonicalize();
1030 num=rat_set.insert(fac).first;
1031 }
1032
operator <(const cadabra::str_node & other) const1033 bool str_node::operator<(const cadabra::str_node& other) const
1034 {
1035 if(*name<*other.name) return true;
1036 else return false;
1037 }
1038
1039 }
1040
1041 // Keep operator overloading outside of the cadabra namespace.
1042
operator <<(std::ostream & str,const cadabra::Ex & ex)1043 std::ostream& operator<<(std::ostream& str, const cadabra::Ex& ex)
1044 {
1045 if(ex.begin()==ex.end()) return str;
1046 ex.print_recursive_treeform(str, ex.begin());
1047 // ex.print_python(str, ex.begin());
1048 return str;
1049 }
1050
operator <<(std::ostream & str,cadabra::Ex::iterator it)1051 std::ostream& operator<<(std::ostream& str, cadabra::Ex::iterator it)
1052 {
1053 cadabra::Ex::print_recursive_treeform(str, it);
1054 // ex.print_python(str, ex.begin());
1055 return str;
1056 }
1057
1058