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