1 
2 #include <typeinfo>
3 
4 #include "Compare.hh"
5 #include "Algorithm.hh" // FIXME: only needed because index_iterator is in there
6 #include <sstream>
7 #include <regex>
8 #include "properties/Indices.hh"
9 #include "properties/Coordinate.hh"
10 #include "properties/ImplicitIndex.hh"
11 #include "properties/SelfCommutingBehaviour.hh"
12 #include "properties/CommutingAsSum.hh"
13 #include "properties/CommutingAsProduct.hh"
14 #include "properties/CommutingBehaviour.hh"
15 #include "properties/DifferentialForm.hh"
16 #include "properties/DiracBar.hh"
17 #include "properties/Integer.hh"
18 #include "properties/SortOrder.hh"
19 
20 // In order to enable/disable debug output, also flip the swith in 'report' below.
21 // #define DEBUG(ln) ln
22 #define DEBUG(ln)
23 
24 namespace cadabra {
25 
26 	int Ex_comparator::offset=0;
27 
subtree_compare(const Properties * properties,Ex::iterator one,Ex::iterator two,int mod_prel,bool,int compare_multiplier,bool literal_wildcards)28 	int subtree_compare(const Properties *properties,
29 	                    Ex::iterator one, Ex::iterator two,
30 	                    int mod_prel, bool, int compare_multiplier, bool literal_wildcards)
31 		{
32 		//	std::cerr << "comparing " << Ex(one) << " with " << Ex(two) << " " << mod_prel << ", " << checksets << std::endl;
33 
34 		// The logic is to compare successive aspects of the two objects, returning a
35 		// no-match code if a difference is found at a particular level, or continuing
36 		// further down the line if there still is a match.
37 
38 		// Compare multipliers. Skip this step if one of the objects is a rational and the
39 		// other not, as in that case we are matching values to symbols.
40 		if( one->is_rational()==two->is_rational() ) {
41 			if(compare_multiplier==-2 && !two->is_name_wildcard() && !one->is_name_wildcard())
42 				if(one->multiplier != two->multiplier) {
43 					if(*one->multiplier < *two->multiplier) return 2;
44 					else return -2;
45 					}
46 			}
47 
48 		int  mult=2;
49 		// Handle object wildcards and comparison
50 		if(!literal_wildcards) {
51 			if(one->is_object_wildcard() || two->is_object_wildcard())
52 				return 0;
53 			}
54 
55 		// Handle mismatching node names.
56 		if(one->name!=two->name) {
57 			//		std::cerr << *one->name << " != " << *two->name << std::endl;
58 			if(literal_wildcards) {
59 				if(*one->name < *two->name) return mult;
60 				else return -mult;
61 				}
62 
63 			DEBUG( std::cerr << "auto? " << one->is_autodeclare_wildcard() << ", " << two->is_numbered_symbol() << std::endl; );
64 			if( (one->is_autodeclare_wildcard() && two->is_numbered_symbol()) ||
65 			      (two->is_autodeclare_wildcard() && one->is_numbered_symbol()) ) {
66 				if( one->name_only() != two->name_only() ) {
67 					if(*one->name < *two->name) return mult;
68 					else return -mult;
69 					}
70 				}
71 			else if( one->is_name_wildcard()==false && two->is_name_wildcard()==false ) {
72 				if(*one->name < *two->name) return mult;
73 				else return -mult;
74 				}
75 
76 			DEBUG( std::cerr << "match despite difference: " << *one->name << " and " << *two->name << std::endl; );
77 			}
78 
79 		// Compare parent relations.
80 		if(mod_prel<=-2) {
81 			str_node::parent_rel_t p1=one->fl.parent_rel;
82 			str_node::parent_rel_t p2=two->fl.parent_rel;
83 			if(p1!=p2) {
84 				return (p1<p2)?2:-2;
85 				}
86 			}
87 
88 		// Now turn to the child nodes. Before comparing them directly, first compare
89 		// the number of children, taking into account range wildcards.
90 		int numch1=Ex::number_of_children(one);
91 		int numch2=Ex::number_of_children(two);
92 
93 		// FIXME: handle range wildcards as in Props.cc
94 
95 		if(numch1!=numch2) {
96 			if(numch1<numch2) return 2;
97 			else return -2;
98 			}
99 
100 		// Compare actual children. We run through this twice: first
101 		// consider all non-index children, then all index children. This
102 		// is because we want products of tensors which differ only by
103 		// index position to be sorted by the names of the tensors first,
104 		// not first by their index positions. Otherwise canonicalise cannot
105 		// do its raising/lowering job.
106 
107 		bool do_indices=false;
108 		int remember_ret=0;
109 		if(mod_prel==0) mod_prel=-2;
110 		else if(mod_prel>0)  --mod_prel;
111 		if(compare_multiplier==0) compare_multiplier=-2;
112 		else if(compare_multiplier>0)  --compare_multiplier;
113 
114 		for(;;) {
115 			Ex::sibling_iterator sib1=one.begin(), sib2=two.begin();
116 
117 			while(sib1!=one.end()) {
118 				if(sib1->is_index() == do_indices) {
119 					int ret=subtree_compare(properties, sib1,sib2, mod_prel, true /* checksets */,
120 					                        compare_multiplier, literal_wildcards);
121 					// std::cerr << "result " << ret << std::endl;
122 					if(abs(ret)>1)
123 						return ret/abs(ret)*mult;
124 					if(ret!=0 && remember_ret==0)
125 						remember_ret=ret;
126 					}
127 				++sib1;
128 				++sib2;
129 				}
130 
131 			if(remember_ret!=0) break;
132 
133 			if(!do_indices) do_indices=true;
134 			else break;
135 			}
136 
137 		return remember_ret;
138 		}
139 
tree_less(const Properties * properties,const Ex & one,const Ex & two,int mod_prel,bool checksets,int compare_multiplier)140 	bool tree_less(const Properties* properties, const Ex& one, const Ex& two, int mod_prel, bool checksets, int compare_multiplier)
141 		{
142 		return subtree_less(properties, one.begin(), two.begin(), mod_prel, checksets, compare_multiplier);
143 		}
144 
tree_equal(const Properties * properties,const Ex & one,const Ex & two,int mod_prel,bool checksets,int compare_multiplier)145 	bool tree_equal(const Properties* properties, const Ex& one, const Ex& two, int mod_prel, bool checksets, int compare_multiplier)
146 		{
147 		return subtree_equal(properties, one.begin(), two.begin(), mod_prel, checksets, compare_multiplier);
148 		}
149 
tree_exact_less(const Properties * properties,const Ex & one,const Ex & two,int mod_prel,bool checksets,int compare_multiplier,bool literal_wildcards)150 	bool tree_exact_less(const Properties* properties, const Ex& one, const Ex& two, int mod_prel, bool checksets, int compare_multiplier, bool literal_wildcards)
151 		{
152 		return subtree_exact_less(properties, one.begin(), two.begin(), mod_prel, checksets, compare_multiplier, literal_wildcards);
153 		}
154 
tree_exact_equal(const Properties * properties,const Ex & one,const Ex & two,int mod_prel,bool checksets,int compare_multiplier,bool literal_wildcards)155 	bool tree_exact_equal(const Properties* properties, const Ex& one, const Ex& two, int mod_prel, bool checksets, int compare_multiplier, bool literal_wildcards)
156 		{
157 		return subtree_exact_equal(properties, one.begin(), two.begin(), mod_prel, checksets, compare_multiplier, literal_wildcards);
158 		}
159 
subtree_less(const Properties * properties,Ex::iterator one,Ex::iterator two,int mod_prel,bool checksets,int compare_multiplier)160 	bool subtree_less(const Properties* properties, Ex::iterator one, Ex::iterator two, int mod_prel, bool checksets, int compare_multiplier)
161 		{
162 		int cmp=subtree_compare(properties, one, two, mod_prel, checksets, compare_multiplier);
163 		if(cmp==2) return true;
164 		return false;
165 		}
166 
subtree_equal(const Properties * properties,Ex::iterator one,Ex::iterator two,int mod_prel,bool checksets,int compare_multiplier)167 	bool subtree_equal(const Properties* properties, Ex::iterator one, Ex::iterator two, int mod_prel, bool checksets, int compare_multiplier)
168 		{
169 		int cmp=subtree_compare(properties, one, two, mod_prel, checksets, compare_multiplier);
170 		if(abs(cmp)<=1) return true;
171 		return false;
172 		}
173 
subtree_exact_less(const Properties * properties,Ex::iterator one,Ex::iterator two,int mod_prel,bool checksets,int compare_multiplier,bool literal_wildcards)174 	bool subtree_exact_less(const Properties* properties, Ex::iterator one, Ex::iterator two, int mod_prel, bool checksets, int compare_multiplier, bool literal_wildcards)
175 		{
176 		int cmp=subtree_compare(properties, one, two, mod_prel, checksets, compare_multiplier, literal_wildcards);
177 		//std::cerr << "comparing " << Ex(one) << " with " << Ex(two) << " = " << cmp << std::endl;
178 		if(cmp>0) return true;
179 		return false;
180 		}
181 
subtree_exact_equal(const Properties * properties,Ex::iterator one,Ex::iterator two,int mod_prel,bool checksets,int compare_multiplier,bool literal_wildcards)182 	bool subtree_exact_equal(const Properties* properties, Ex::iterator one, Ex::iterator two, int mod_prel, bool checksets, int compare_multiplier, bool literal_wildcards)
183 		{
184 		int cmp=subtree_compare(properties, one, two, mod_prel, checksets, compare_multiplier, literal_wildcards);
185 		//	std::cout << *one->name << " == " << *two->name << " : " << cmp << std::endl;
186 		if(cmp==0) return true;
187 		return false;
188 		}
189 
tree_less_obj(const Properties * k)190 	tree_less_obj::tree_less_obj(const Properties* k)
191 		: properties(k)
192 		{
193 		}
194 
operator ()(const Ex & one,const Ex & two) const195 	bool tree_less_obj::operator()(const Ex& one, const Ex& two) const
196 		{
197 		return tree_less(properties, one, two);
198 		}
199 
tree_less_modprel_obj(const Properties * k)200 	tree_less_modprel_obj::tree_less_modprel_obj(const Properties* k)
201 		: properties(k)
202 		{
203 		}
204 
operator ()(const Ex & one,const Ex & two) const205 	bool tree_less_modprel_obj::operator()(const Ex& one, const Ex& two) const
206 		{
207 		return tree_less(properties, one, two, 0);
208 		}
209 
tree_equal_obj(const Properties * k)210 	tree_equal_obj::tree_equal_obj(const Properties* k)
211 		: properties(k)
212 		{
213 		}
214 
operator ()(const Ex & one,const Ex & two) const215 	bool tree_equal_obj::operator()(const Ex& one, const Ex& two) const
216 		{
217 		return tree_equal(properties, one, two);
218 		}
219 
tree_exact_less_obj(const Properties * p)220 	tree_exact_less_obj::tree_exact_less_obj(const Properties *p)
221 		: properties(p)
222 		{
223 		}
224 
operator ()(const Ex & one,const Ex & two) const225 	bool tree_exact_less_obj::operator()(const Ex& one, const Ex& two) const
226 		{
227 		return tree_exact_less(properties, one, two);
228 		}
229 
tree_exact_less_no_wildcards_obj()230 	tree_exact_less_no_wildcards_obj::tree_exact_less_no_wildcards_obj()
231 		{
232 		properties=0;
233 		}
234 
operator ()(const Ex & one,const Ex & two) const235 	bool tree_exact_less_no_wildcards_obj::operator()(const Ex& one, const Ex& two) const
236 		{
237 		return tree_exact_less(properties, one, two, -2, true, 0, true);
238 		}
239 
operator ()(const Ex & one,const Ex & two) const240 	bool tree_exact_less_no_wildcards_mod_prel_obj::operator()(const Ex& one, const Ex& two) const
241 		{
242 		return tree_exact_less(properties, one, two, 0, true, -2, true);
243 		}
244 
operator ()(const Ex & one,const Ex & two) const245 	bool tree_exact_equal_obj::operator()(const Ex& one, const Ex& two) const
246 		{
247 		return tree_exact_equal(properties, one, two);
248 		}
249 
tree_exact_less_mod_prel_obj(const Properties * p)250 	tree_exact_less_mod_prel_obj::tree_exact_less_mod_prel_obj(const Properties *p)
251 		: properties(p)
252 		{
253 		}
254 
operator ()(const Ex & one,const Ex & two) const255 	bool tree_exact_less_mod_prel_obj::operator()(const Ex& one, const Ex& two) const
256 		{
257 		return tree_exact_less(properties, one, two, 0, true, -2, true);
258 		}
259 
operator ()(const Ex & one,const Ex & two) const260 	bool tree_exact_equal_mod_prel_obj::operator()(const Ex& one, const Ex& two) const
261 		{
262 		return tree_exact_equal(properties, one, two, 0, true, -2, true);
263 		}
264 
operator ()(const Ex & one,const Ex & two) const265 	bool tree_exact_less_for_indexmap_obj::operator()(const Ex& one, const Ex& two) const
266 		{
267 		return tree_exact_less(0, one, two, -2 /* mod_prel, was 0 */, true, -2 /* compare_multiplier, was 0 */, true);
268 		}
269 
270 	//bool operator==(const Ex& first, const Ex& second)
271 	//	{
272 	//	return tree_exact_equal(properties, first, second, 0, true, -2, true);
273 	//	}
274 	//
275 
clear()276 	void Ex_comparator::clear()
277 		{
278 		replacement_map.clear();
279 		subtree_replacement_map.clear();
280 		index_value_map.clear();
281 		factor_locations.clear();
282 		factor_moving_signs.clear();
283 		}
284 
match_subtree(const Ex & tr,Ex::iterator i1,Ex::iterator i2,Ex::iterator conditions)285 	Ex_comparator::match_t Ex_comparator::match_subtree(const Ex& tr, Ex::iterator i1, Ex::iterator i2, Ex::iterator conditions)
286 		{
287 		auto ret = equal_subtree(i1, i2);
288 		if(ret==match_t::subtree_match || ret==match_t::node_match) {
289 			if(conditions==tr.end()) return ret;
290 			std::string error;
291 			if(satisfies_conditions(conditions, error))
292 				return ret;
293 			else
294 				return match_t::no_match_greater; // FIXME: is that the right thing to do?
295 			}
296 		else return ret;
297 		}
298 
equal_subtree(Ex::iterator i1,Ex::iterator i2,useprops_t use_props,bool ignore_parent_rel)299 	Ex_comparator::match_t Ex_comparator::equal_subtree(Ex::iterator i1, Ex::iterator i2,
300 	      useprops_t use_props, bool ignore_parent_rel)
301 		{
302 		DEBUG( std::cerr << "equal_subtree with use_props = " << use_props << std::endl; );
303 		++offset;
304 
305 		Ex::sibling_iterator i1end(i1);
306 		Ex::sibling_iterator i2end(i2);
307 		++i1end;
308 		++i2end;
309 
310 		// When measuring depth (to determine if we need to use
311 		// properties or not), things like \dot{\alpha} should give the
312 		// same depth for \dot and for \alpha, because \dot is an
313 		// Accent. We use a predicate function to take care of this.
314 		auto depth_predicate = [this,use_props](const Ex::iterator& i) {
315 			if(use_props!=useprops_t::not_at_top) return true;
316 			const Accent *accent = properties.get<Accent>(i);
317 			return (accent==0);
318 		};
319 
320 		bool first_call=true;
321 		match_t worst_mismatch=match_t::subtree_match;
322 		Ex::iterator rememberi1=i1;
323 
324 		while(i1!=i1end && i2!=i2end) {
325 			useprops_t up = use_props;
326 			auto dist = Ex::distance(rememberi1, i1, depth_predicate);
327 			if(use_props==useprops_t::not_at_top) {
328 				if(dist!=0) up=useprops_t::always;
329 				else        up=useprops_t::never;
330 				}
331 			bool    ip = ignore_parent_rel && (dist==0);
332 			match_t mm=compare(i1, i2, first_call, up, ip);
333 			//		DEBUG( std::cerr << "COMPARE " << *i1->name << ", " << *i2->name << " = " << static_cast<int>(mm) << std::endl; )
334 			first_call=false;
335 			switch(mm) {
336 				case match_t::no_match_indexpos_less:
337 				case match_t::no_match_indexpos_greater:
338 					worst_mismatch=mm;
339 					// FIXME: at the moment skipping children is the right thing to do
340 					// as we are assuming that the no_match_indexpos_... is the worst
341 					// thing that could have happened for this child subtree. See
342 					// also the FIXME below.
343 					i1.skip_children();
344 					i2.skip_children();
345 					break;
346 				case match_t::no_match_less:
347 				case match_t::no_match_greater:
348 					// As soon as we get a mismatch, return.
349 					return report(mm);
350 				case match_t::node_match: {
351 					size_t num1=Ex::number_of_children(i1);
352 					size_t num2=Ex::number_of_children(i2);
353 
354 					if(num1==1 && i1.begin()->is_range_wildcard()) {
355 						//				std::cerr << "comparing " << *i1->name << " with " << *i2->name << " " << num1 << " " << num2 << std::endl;
356 						return match_t::subtree_match;
357 						}
358 
359 					// TODO: this is where we should decide what to do with
360 					// nodes which have sibling wildcards. Make a
361 					// 'compare_siblings'. We also need a
362 					// siblings_replacement_map in which we can store a
363 					// sibling range for a given sibling wildcard symbol,
364 					// e.g. a... -> i j k.  This matching routine should walk
365 					// to the first non-range object in the pattern, and match
366 					// that. Once it is matched, it should store the resulting
367 					// map for any range object to the left. Then continue,
368 					// recursively, finding the second non-range object, and
369 					// again storing the range object map.  Once a no-match
370 					// comes back, pop the match objects from the stack and
371 					// try to find the non-range object to the right of the match
372 					// reported earlier.
373 
374 					// This slightly oversearches (we could keep track of how
375 					// many non-range objects are still to be matched in order
376 					// to restrict how far to the right a search should go), but in
377 					// practise this is probably not relevant (and can always be added).
378 
379 					if(num1 < num2)      return report(match_t::no_match_less);
380 					else if(num1 > num2) return report(match_t::no_match_greater);
381 					break;
382 					}
383 				case match_t::match_index_less:
384 				case match_t::match_index_greater:
385 					// If we have a match but different index names, remember this
386 					// mismatch, because it will determine our total result value.
387 					if(worst_mismatch==match_t::subtree_match)
388 						worst_mismatch=mm;
389 					// If indices by type but not name, we do not need to go
390 					// further down the tree. E.g. W_{\hat{\theta_1}} vs
391 					// W_{\hat{\theta_2}} compared at the index position.
392 					// The 'compare' has done a comparison of the entire
393 					// tree of the indices, no need to go down.
394 					i1.skip_children();
395 					i2.skip_children();
396 					break;
397 				case match_t::subtree_match:
398 					// If a match of the entire subtrees at i1 and i2 has been found,
399 					// we do not need to go down the child nodes of i1 and i2 anymore.
400 					i1.skip_children();
401 					i2.skip_children();
402 					break;
403 				}
404 			// Continue walking the tree downwards.
405 			DEBUG( std::cerr << "one down" << std::endl; );
406 			++i1;
407 			++i2;
408 			}
409 		DEBUG( std::cerr << "equal_subtree done" << std::endl; );
410 
411 		return report(worst_mismatch);
412 		}
413 
Ex_comparator(const Properties & k)414 	Ex_comparator::Ex_comparator(const Properties& k)
415 		: properties(k), value_matches_index(false)
416 		{
417 		}
418 
set_value_matches_index(bool v)419 	void Ex_comparator::set_value_matches_index(bool v)
420 		{
421 		value_matches_index=v;
422 		}
423 
tab() const424 	std::string Ex_comparator::tab() const
425 		{
426 		std::string ret;
427 		for(int i=0; i<offset; ++i)
428 			ret+="   ";
429 		return ret;
430 		}
431 
report(Ex_comparator::match_t r) const432 	Ex_comparator::match_t Ex_comparator::report(Ex_comparator::match_t r) const
433 		{
434 		return r;
435 
436 		std::cerr << tab() << "result = ";
437 		switch(r) {
438 			case match_t::node_match:
439 				std::cerr << "node_match";
440 				break;
441 			case match_t::subtree_match:
442 				std::cerr << "subtree_match";
443 				break;
444 			case match_t::match_index_less:
445 				std::cerr << "match_index_less";
446 				break;
447 			case match_t::match_index_greater:
448 				std::cerr << "match_index_greater";
449 				break;
450 			case match_t::no_match_indexpos_less:
451 				std::cerr << "no_match_indexpos_less";
452 				break;
453 			case match_t::no_match_indexpos_greater:
454 				std::cerr << "no_match_indexpos_greater";
455 				break;
456 			case match_t::no_match_less:
457 				std::cerr << "no_match_less";
458 				break;
459 			case match_t::no_match_greater:
460 				std::cerr << "no_match_greater";
461 				break;
462 			}
463 		std::cerr << std::endl;
464 		--offset;
465 		return r;
466 		}
467 
compare(const Ex::iterator & one,const Ex::iterator & two,bool nobrackets,useprops_t use_props,bool ignore_parent_rel)468 	Ex_comparator::match_t Ex_comparator::compare(const Ex::iterator& one,
469 	      const Ex::iterator& two,
470 	      bool nobrackets,
471 	      useprops_t use_props, bool ignore_parent_rel)
472 		{
473 		++offset;
474 
475 		// nobrackets also implies 'no multiplier', i.e. 'toplevel'.
476 		// 'one' is the substitute pattern, 'two' the expression under consideration.
477 
478 		DEBUG( std::cerr << tab() << "matching " << Ex(one) << tab() << "to " << Ex(two) << tab() << "using props = " << use_props << ", ignore_parent_rel = " << ignore_parent_rel << std::endl; );
479 
480 		if(nobrackets==false && one->fl.bracket != two->fl.bracket)
481 			return report( (one->fl.bracket < two->fl.bracket)?match_t::no_match_less:match_t::no_match_greater );
482 
483 		// Determine whether we are dealing with one of the pattern types.
484 		bool pattern=false;
485 		bool objectpattern=false;
486 		bool implicit_pattern=false; // anything in _{..} or ^{..} that is not an integer or coordinate
487 		bool is_index=false;
488 		bool is_sibling_pattern=false;
489 		bool is_coordinate=false;
490 		bool is_number=false;
491 
492 		if(one->fl.bracket==str_node::b_none && one->is_index() )
493 			is_index=true;
494 		if(one->is_name_wildcard())
495 			pattern=true;
496 		else if(one->is_object_wildcard())
497 			objectpattern=true;
498 		else if(one->is_siblings_wildcard())
499 			is_sibling_pattern=true;
500 		else if(is_index && one->is_integer()==false) {
501 			// Things in _{..} or ^{..} are either indices (implicit patterns) or coordinates.
502 			const Coordinate *cdn1=0;
503 			if(use_props==useprops_t::always) {
504 				DEBUG( std::cerr << tab() << "is " << *one->name << " a coordinate?" << std::endl; );
505 				cdn1=properties.get<Coordinate>(one, true);
506 				DEBUG( std::cerr << tab() << cdn1 << std::endl; );
507 				}
508 
509 			if(cdn1==0)
510 				implicit_pattern=true;
511 			else
512 				is_coordinate=true;
513 			}
514 		else if(one->is_integer())
515 			is_number=true;
516 
517 		// Various cases to be distinguished now:
518 		//   - match index pattern to object
519 		//   - match object pattern to object
520 		//   - match coordinate to index
521 		//   - everything else, which does not involve patterns/wildcards
522 
523 		if(pattern || implicit_pattern) {
524 
525 			// It is possible to match integers to implicit patterns (indices), provided
526 			// we know that the given index can take the found numerical value.
527 			// See basic.cdb/test26 for a simple example.
528 			// If we have a proper 'question mark' pattern, we always match to integers.
529 
530 			if(two->is_rational() && implicit_pattern) {
531 				// Determine whether 'one' can take the value 'two'.
532 				//std::cerr << "**** can one take value two " << use_props  << std::endl;
533 				const Integer *ip = 0;
534 				if(use_props==useprops_t::always) {
535 					DEBUG( std::cerr << tab() << "is " << *one->name << " an integer?" << std::endl; );
536 					ip = properties.get<Integer>(one, true); // 'true' to ignore parent rel.
537 					DEBUG( std::cerr << tab() << ip << std::endl; );
538 					}
539 
540 				if(ip==0) return report(match_t::no_match_less);
541 
542 				bool lower_bdy=true, upper_bdy=true;
543 				multiplier_t from, to;
544 				if(ip->from.begin()==ip->from.end()) lower_bdy=false;
545 				else {
546 					if(!ip->from.begin()->is_rational()) return report(match_t::no_match_less);
547 					from = *ip->from.begin()->multiplier;
548 					}
549 				if(ip->to.begin()==ip->to.end())     upper_bdy=false;
550 				else {
551 					if(!ip->to.begin()->is_rational()) return report(match_t::no_match_less);
552 					to   = *ip->to.begin()->multiplier;
553 					}
554 				if((lower_bdy && *two->multiplier < from) || (upper_bdy && *two->multiplier > to))
555 					return report(match_t::no_match_less);
556 
557 				// std::cerr << tab() << Ex(one) << tab() << "can take value " << *two->multiplier << std::endl;
558 				}
559 
560 			// We want to search the replacement map for replacement rules which we have
561 			// constructed earlier, and discard the current match if it conflicts those
562 			// rules. This is to make sure that e.g. a pattern k1_a k2_a does not match
563 			// an expression k1_c k2_d.
564 			//
565 			// In order to ensure that a replacement rule for a lower index is also
566 			// triggering a rule for an upper index, we simply store both rules (see
567 			// below) so that searching for rules can remain simple.
568 
569 			replacement_map_t::iterator loc=replacement_map.find(one);
570 
571 			bool tested_full=true;
572 
573 			// If this is a pattern with a non-zero number of children,
574 			// also search the pattern without the children (but not if
575 			// this node is an Accent, because then the child nodes are
576 			// very relevant).
577 			if(loc == replacement_map.end() && Ex::number_of_children(one)!=0) {
578 				DEBUG( std::cerr << tab() << "**** not found, trying without child nodes" << std::endl; );
579 				if(properties.get<Accent>(one)==0 ) {
580 					Ex tmp1(one);
581 					tmp1.erase_children(tmp1.begin());
582 					loc = replacement_map.find(tmp1);
583 					tested_full=false;
584 					}
585 				}
586 
587 			if(loc!=replacement_map.end()) {
588 				// We constructed a replacement rule for this node already at an earlier
589 				// stage. Need to make sure that that rule is consistent with what we
590 				// found now.
591 
592 				int cmp;
593 
594 				// If this is an index/pattern, try to match the whole index/pattern.
595 				if(tested_full)
596 					cmp=subtree_compare(&properties, (*loc).second.begin(), two, -2);
597 				else {
598 					Ex tmp2(two);
599 					tmp2.erase_children(tmp2.begin());
600 					cmp=subtree_compare(&properties, (*loc).second.begin(), tmp2.begin(), -2);
601 					}
602 				DEBUG(std::cerr << " pattern " << two
603 						<< " should be " << (*loc).second.begin()
604 						<< " because that's what " << one
605 						<< " was set to previously; result " << cmp << std::endl;  );
606 
607 				if(cmp==0)      return report(match_t::subtree_match);
608 				else if(cmp>0)  return report(match_t::no_match_less);
609 				else            return report(match_t::no_match_greater);
610 				}
611 			else {
612 				// This index/pattern was not encountered earlier. If this node is an index,
613 				// check that the index types in pattern and object agree (if known,
614 				// otherwise assume they match).
615 				// If two is a rational, we have already checked that one can take this value.
616 
617 				if(two->is_index() && !one->is_index() && !one->is_range_wildcard())
618 					return report(match_t::no_match_indexpos_greater);
619 
620 				if(one->is_index()) {
621 					DEBUG( std::cerr << tab() << "object one is index" << std::endl; );
622 
623 					const Indices *t1=0;
624 					const Indices *t2=0;
625 					if(use_props==useprops_t::always) {
626 						DEBUG( std::cerr << tab() << "is " << one << " an index?" << std::endl; );
627 						t1=properties.get<Indices>(one, false);
628 						DEBUG( std::cerr << tab() << "found for one: " << t1 << std::endl; );
629 						if(two->is_rational()==false) {
630 							DEBUG( std::cerr << tab() << "is " << two << " an index?" << std::endl; );
631 							t2=properties.get<Indices>(two, false);
632 							DEBUG( std::cerr << tab() << t2 << std::endl; );
633 							// It is still possible that t2 is a Coordinate and
634 							// t1 an Index which can take the value of the
635 							// coordinate. This happens when 'm' is an index
636 							// taking values {t,...}, you declare X^{m} to have
637 							// a property and then later ask if X^{t} has that
638 							// property. In that case X^{m} is object 1 and
639 							// X^{t} object 2, and we end up here (NOT in the
640 							// branch with both exchanged, which happens when
641 							// evaluate tries to determine if a rule for X^{t}
642 							// applies to an expression X^{m}).
643 							if(t1!=0 && t2!=t1) {
644 								auto ivals = std::find_if(t1->values.begin(), t1->values.end(),
645 								[&](const Ex& a) {
646 									if(subtree_compare(&properties, a.begin(), two, 0)==0) return true;
647 									else return false;
648 								});
649 								if(ivals!=t1->values.end())
650 									t2=t1;
651 								}
652 							}
653 							else {
654 								t2=t1; // We already know 'one' can take the value 'two', so in a sense t2 is in the same set as t1.
655 								DEBUG( std::cerr << tab() << two << " is rational" << std::endl; );
656 								}
657 						}
658 
659 					// Check parent rel if a) there is no Indices property for the indices, b) the index positions
660 					// are not free. Effectively this means that indices without property info get treated as
661 					// fixed-position indices.
662 
663 					// FIXME: this is not entirely correct. If the indexpos does not match, going deeper may
664 					// still reveal that the mismatch is even worse.
665 
666 					if(!ignore_parent_rel)
667 						if(t1==0 || t2==0 || (t1->position_type!=Indices::free && t2->position_type!=Indices::free))
668 							if(one->fl.parent_rel != two->fl.parent_rel) {
669 								DEBUG( std::cerr << tab() << "parent_rels not the same" << std::endl;);
670 								return report( (one->fl.parent_rel < two->fl.parent_rel)
671 								               ?match_t::no_match_indexpos_less:match_t::no_match_indexpos_greater );
672 								}
673 
674 					// If both indices have no Indices property, compare them by name and pretend they are
675 					// both in the same Indices set.
676 
677 					if(two->is_rational()==false && !(t1==0 && t2==0)) {
678 						if( (t1 || t2) && implicit_pattern ) {
679 							if(t1 && t2) {
680 								if((*t1).set_name != (*t2).set_name) {
681 									if((*t1).set_name < (*t2).set_name) return report(match_t::no_match_less);
682 									else                                return report(match_t::no_match_greater);
683 									}
684 								}
685 							else {
686 								// If we get here, 'one' or 'two' has an Indices property, and
687 								// the other one doesn't. So we do not know how to compare them,
688 								// except by name. Note that we should return something which is
689 								// symmetric if 'two' and 'one' had been exchanged!
690 								int dc = subtree_compare(&properties, one, two, 0);
691 								if(dc<0) return report(match_t::no_match_less);
692 								else     return report(match_t::no_match_greater);
693 								}
694 							}
695 						}
696 					}
697 
698 				// See the documentation of substitute::can_apply for details about
699 				// how the replacement_map is supposed to work. In general, if we want
700 				// that e.g a found _{z} also leads to a replacement rule for (z), or
701 				// if we want that a found _{z} also leads to a replacement for ^{z},
702 				// this needs to be added to the replacement map explicitly.
703 
704 					DEBUG( std::cerr << "adding " << one << " -> " << two << " to replacement map " << std::endl; );
705 				replacement_map[one]=two;
706 
707 				// if this is an index, also store the pattern with the parent_rel flipped
708 
709 				if(one->is_index()) {
710 					Ex cmptree1(one);
711 					Ex cmptree2(two);
712 					cmptree1.begin()->flip_parent_rel();
713 					if(two->is_index())
714 						cmptree2.begin()->flip_parent_rel();
715 					replacement_map[cmptree1]=cmptree2;
716 					}
717 
718 				// if this is a pattern and the pattern has a non-zero number of children,
719 				// also add the pattern without the children
720 				if(Ex::number_of_children(one)!=0) {
721 					Ex tmp1(one), tmp2(two);
722 					tmp1.erase_children(tmp1.begin());
723 					tmp2.erase_children(tmp2.begin());
724 					replacement_map[tmp1]=tmp2;
725 					}
726 				// and if this is a pattern also insert the one without the parent_rel
727 				if( /* one->is_name_wildcard()  &&  */ one->is_index()) {
728 					//std::cerr << "storing pattern without pattern rel " << replacement_map.size() << std::endl;
729 					Ex tmp1(one), tmp2(two);
730 					tmp1.begin()->fl.parent_rel=str_node::p_none;
731 					tmp2.begin()->fl.parent_rel=str_node::p_none;
732 					// We do not want this pattern to be present already.
733 					auto fnd=replacement_map.find(tmp1);
734 					if(fnd!=replacement_map.end()) {
735 						throw InternalError("Attempting to duplicate replacement rule.");
736 						}
737 					//				assert(replacement_map.find(tmp1)!=replacement_map.end());
738 					// std::cerr << "storing " << Ex(tmp1) << " -> " << Ex(tmp2) << std::endl;
739 					replacement_map[tmp1]=tmp2;
740 					}
741 
742 				DEBUG( std::cerr << "Replacement map is now:" << std::endl;
743 						 for(auto& rule: replacement_map)
744 							 std::cerr << "* " << rule.first << " -> " << rule.second << std::endl;
745 						 );
746 
747 				}
748 
749 			// Return a match of the appropriate type. If we are comparing indices and
750 			// they matched because they are from the same set but do not have the same
751 			// name, we still need to let the caller know about this.
752 			if(is_index) {
753 				int xc = subtree_compare(0, one, two, ignore_parent_rel?(-1):(-2));
754 				if(xc==0) return report(match_t::subtree_match);
755 				if(xc>0)  return report(match_t::match_index_less);
756 				return report(match_t::match_index_greater);
757 				}
758 			else return report(match_t::node_match);
759 			}
760 		else if(objectpattern) {
761 			// Even for object patterns, if we do not ignore the parent rel, we need to test them.
762 			if(!ignore_parent_rel)
763 				if( one->fl.parent_rel != two->fl.parent_rel )
764 					return report( (one->fl.parent_rel < two->fl.parent_rel)
765 										?match_t::no_match_indexpos_less:match_t::no_match_indexpos_greater );
766 
767 			subtree_replacement_map_t::iterator loc=subtree_replacement_map.find(one->name);
768 			if(loc!=subtree_replacement_map.end()) {
769 				return report(equal_subtree((*loc).second,two,use_props));
770 				}
771 			else subtree_replacement_map[one->name]=two;
772 
773 			return report(match_t::subtree_match);
774 			}
775 		else if(is_coordinate || is_number) {   // Check if the coordinate can come from an index.
776 			const Indices *t2=0;
777 			if(use_props==useprops_t::always) {
778 				DEBUG( std::cerr << tab() << "is " << *two->name << " an index?" << std::endl; );
779 				t2=properties.get<Indices>(two, true);
780 				DEBUG( std::cerr << tab() << t2 << std::endl; );
781 				}
782 
783 			if(value_matches_index && t2) {
784 				// std::cerr << "coordinate " << *one->name << " versus index " << *two->name << std::endl;
785 				// If the 'two' index type is fixed or independent, ensure
786 				// that the parent relation matches!
787 
788 				if(!ignore_parent_rel)
789 					if(t2->position_type==Indices::fixed || t2->position_type==Indices::independent) {
790 						if( one->fl.parent_rel != two->fl.parent_rel ) {
791 							DEBUG( std::cerr << tab() << "parent_rels not the same" << std::endl;);
792 							return report( (one->fl.parent_rel < two->fl.parent_rel)
793 							               ?match_t::no_match_indexpos_less:match_t::no_match_indexpos_greater );
794 							}
795 						}
796 
797 				// Look through values attribute of Indices object to see if the 'two' index
798 				// can take the 'one' value.
799 
800 				auto ivals = std::find_if(t2->values.begin(), t2->values.end(),
801 				[&](const Ex& a) {
802 					if(subtree_compare(&properties, a.begin(), one, 0)==0) return true;
803 					else return false;
804 					});
805 				if(ivals!=t2->values.end()) {
806 					// Verify that the 'two' index has not already been matched to a value
807 					// different from 'one'.
808 					Ex t1(two), t2(two), o1(one), o2(one);
809 					t2.begin()->flip_parent_rel();
810 					o2.begin()->flip_parent_rel();
811 					auto prev1 = index_value_map.find(t1);
812 					auto prev2 = index_value_map.find(t2);
813 					if(prev1!=index_value_map.end() && ! (prev1->second==o1) ) {
814 						//					std::cerr << "Previously 1 " << Ex(two) << " was " << Ex(prev1->second) << std::endl;
815 						return report(match_t::no_match_less);
816 						}
817 					if(prev2!=index_value_map.end() && ! (prev2->second==o2) ) {
818 						//					std::cerr << "Previously 2 " << Ex(two) << " was " << Ex(prev2->second) << std::endl;
819 						return report(match_t::no_match_less);
820 						}
821 
822 					index_value_map[two]=one;
823 					return report(match_t::node_match);
824 					}
825 				else {
826 					// The index 'one' is not known to be able to take value 'two'. So this is not
827 					// a match. Compare lexographically; this should be symmetric if one and two had
828 					// been exchanged.
829 					int dc = subtree_compare(&properties, one, two, 0);
830 					if(dc<0) return report(match_t::no_match_less);
831 					else     return report(match_t::no_match_greater);
832 					}
833 				}
834 			else {
835 				// What's left is the possibility that both indices are Coordinates, in which case they
836 				// need to match exactly.
837 				int cmp=subtree_compare(&properties, one, two, -2);
838 				if(cmp==0)      return report(match_t::subtree_match);
839 				else if(cmp>0)  return report(match_t::no_match_less);
840 				else            return report(match_t::no_match_greater);
841 				}
842 			}
843 		else {   // object is not dummy nor objectpattern nor coordinate
844 
845 			if(one->is_rational() && two->is_rational()) {
846 				if(one->multiplier!=two->multiplier) {
847 					if(*one->multiplier < *two->multiplier) return report(match_t::no_match_less);
848 					else                                    return report(match_t::no_match_greater);
849 					}
850 				else {
851 					// Equal numerical factors with different parent rel _never_ match, because
852 					// we cannot determine if index raising/lowering is allowed if we do not
853 					// know the bundle type.
854 					if(!ignore_parent_rel)
855 						if(one->fl.parent_rel != two->fl.parent_rel)
856 							return report( (one->fl.parent_rel < two->fl.parent_rel)
857 							               ?match_t::no_match_indexpos_less:match_t::no_match_indexpos_greater );
858 					}
859 				}
860 
861 			if(name_match_with_autodeclare(one, two)) {
862 				if(nobrackets || (one->multiplier == two->multiplier) ) {
863 					if(ignore_parent_rel || one->fl.parent_rel==two->fl.parent_rel) return report( match_t::node_match );
864 					report( (one->fl.parent_rel < two->fl.parent_rel)
865 					        ?match_t::no_match_indexpos_less:match_t::no_match_indexpos_greater );
866 					}
867 
868 				if(*one->multiplier < *two->multiplier) return report(match_t::no_match_less);
869 				else                                    return report(match_t::no_match_greater);
870 				}
871 			else if( ((one->is_autodeclare_wildcard() && two->is_numbered_symbol()) ||
872 						 (two->is_autodeclare_wildcard() && one->is_numbered_symbol()) ) && one->name_only()==two->name_only() ) {
873 				return report(match_t::node_match);
874 				}
875 			else {
876 				if( *one->name < *two->name ) return report(match_t::no_match_less);
877 				else                          return report(match_t::no_match_greater);
878 				}
879 			}
880 
881 		assert(1==0); // should never be reached
882 
883 		return report(match_t::no_match_less);
884 		}
885 
name_match_with_autodeclare(Ex::sibling_iterator one,Ex::sibling_iterator two) const886 	bool Ex_comparator::name_match_with_autodeclare(Ex::sibling_iterator one, Ex::sibling_iterator two) const
887 		{
888 		if(one->name==two->name) return true;
889 		if((one->is_autodeclare_wildcard() && two->is_numbered_symbol()) ||
890 			(two->is_autodeclare_wildcard() && one->is_numbered_symbol()) ) {
891 			if( one->name_only()==two->name_only() )
892 				return true;
893 			}
894 		return false;
895 		}
896 
match_subproduct(const Ex & tr,Ex::sibling_iterator lhs,Ex::sibling_iterator tofind,Ex::sibling_iterator st,Ex::iterator conditions)897 	Ex_comparator::match_t Ex_comparator::match_subproduct(const Ex& tr,
898 	      Ex::sibling_iterator lhs,
899 	      Ex::sibling_iterator tofind,
900 	      Ex::sibling_iterator st,
901 	      Ex::iterator conditions)
902 		{
903 		replacement_map_t         backup_replacements(replacement_map);
904 		subtree_replacement_map_t backup_subtree_replacements(subtree_replacement_map);
905 
906 		// 'Start' iterates over all factors, trying to find 'tofind'. It may happen that the
907 		// first match is such that the entire subproduct matches, but it may be that we have
908 		// to iterate 'start' over more factors (typically when non-commutative objects are
909 		// concerned).
910 
911 		Ex::sibling_iterator start=st.begin();
912 		while(start!=st.end()) {
913 
914 			// The factor 'tofind' can only be matched against a factor in the subproduct if we
915 			// have not already previously matched part of the lhs to this factor. We check that first.
916 
917 			if(std::find(factor_locations.begin(), factor_locations.end(), start)==factor_locations.end()) {
918 
919 				// Compare this factor with 'tofind'.
920 
921 				auto match = equal_subtree(tofind, start);
922 				if(match==match_t::subtree_match || match==match_t::match_index_less || match==match_t::match_index_greater) {
923 
924 					// The factor has been found. Verify that it can be moved
925 					// next to the previous factor, if applicable (nontrivial
926 					// if factors do not commute).
927 
928 					int sign=1;
929 					if(factor_locations.size()>0) {
930 						DEBUG(std::cerr << "--- can move?     ---" << std::endl; );
931 						// Determining the sign is non-trivial to do step-by step.
932 						// Consider an expression
933 						//   A B C D E
934 						// and a pattern
935 						//   D A B
936 						// (D, A, B anti-commuting). A can be moved to the right of D
937 						// picking up two signs, and B can moved to the right of A with
938 						// no sign.
939 						Ex_comparator comparator(properties);
940 						sign=comparator.can_move_adjacent(st, factor_locations, start);
941 						DEBUG(std::cerr << "--- done can move ---" << sign << std::endl; );
942 						}
943 					if(sign==0) { // object found, but we cannot move it in the right order
944 						replacement_map=backup_replacements;
945 						subtree_replacement_map=backup_subtree_replacements;
946 						}
947 					else {
948 						factor_locations.push_back(start);
949 						factor_moving_signs.push_back(sign);
950 
951 						Ex::sibling_iterator nxt=tofind;
952 						++nxt;
953 						if(nxt!=lhs.end()) {
954 							match_t res=match_subproduct(tr, lhs, nxt, st, conditions);
955 							if(res==match_t::subtree_match) return res;
956 							else {
957 								//						txtout << tofind.node << "found factor useless " << start.node << std::endl;
958 								factor_locations.pop_back();
959 								factor_moving_signs.pop_back();
960 								replacement_map=backup_replacements;
961 								subtree_replacement_map=backup_subtree_replacements;
962 								}
963 							}
964 						else {
965 							// Found all factors in sub-product, now check the conditions.
966 							std::string error;
967 							if(conditions==tr.end()) return match_t::subtree_match;
968 							if(satisfies_conditions(conditions, error)) {
969 								return match_t::subtree_match;
970 								}
971 							else {
972 								factor_locations.pop_back();
973 								factor_moving_signs.pop_back();
974 								replacement_map=backup_replacements;
975 								subtree_replacement_map=backup_subtree_replacements;
976 								}
977 							}
978 						}
979 					}
980 				else {
981 					//				txtout << tofind.node << "does not match" << std::endl;
982 					replacement_map=backup_replacements;
983 					subtree_replacement_map=backup_subtree_replacements;
984 					}
985 				}
986 			++start;
987 			}
988 		return match_t::no_match_less; // FIXME not entirely true
989 		}
990 
match_subsum(const Ex & tr,Ex::sibling_iterator lhs,Ex::sibling_iterator tofind,Ex::sibling_iterator st,Ex::iterator conditions)991 	Ex_comparator::match_t Ex_comparator::match_subsum(const Ex& tr,
992 	      Ex::sibling_iterator lhs,
993 	      Ex::sibling_iterator tofind,
994 	      Ex::sibling_iterator st,
995 	      Ex::iterator conditions)
996 		{
997 		replacement_map_t         backup_replacements(replacement_map);
998 		subtree_replacement_map_t backup_subtree_replacements(subtree_replacement_map);
999 
1000 		// 'Start' iterates over all terms, trying to find 'tofind'. It may happen that the
1001 		// first match is such that the entire sub-sum matches, but it may be that we have
1002 		// to iterate 'start' over more terms (typically when relative factors of terms
1003 		// do not match).
1004 
1005 		Ex::sibling_iterator start=st.begin();
1006 		while(start!=st.end()) {
1007 
1008 			// The term 'tofind' can only be matched against a term in the sub-sum if we
1009 			// have not already previously matched part of the lhs to this term. We check that first.
1010 
1011 			if(std::find(factor_locations.begin(), factor_locations.end(), start)==factor_locations.end()) {
1012 
1013 				// Compare this factor with 'tofind'.
1014 
1015 				auto match = equal_subtree(tofind, start);
1016 				if(match==match_t::subtree_match || match==match_t::match_index_less || match==match_t::match_index_greater) {
1017 
1018 					// The term has been found. If this is not the 1st term, verify
1019 					// that the ratio of its multiplier to the multiplier of the search term
1020 					// agrees with that ratio for the first term.
1021 
1022 					if(tr.index(tofind)==0) {
1023 						term_ratio = (*tofind->multiplier)/(*start->multiplier);
1024 						}
1025 					auto this_ratio = (*tofind->multiplier)/(*start->multiplier);
1026 					if(this_ratio!=term_ratio) {
1027 						replacement_map=backup_replacements;
1028 						subtree_replacement_map=backup_subtree_replacements;
1029 						}
1030 					else {
1031 						factor_locations.push_back(start);
1032 
1033 						Ex::sibling_iterator nxt=tofind;
1034 						++nxt;
1035 						if(nxt!=lhs.end()) {
1036 							match_t res=match_subsum(tr, lhs, nxt, st, conditions);
1037 							if(res==match_t::subtree_match) return res;
1038 							else {
1039 								factor_locations.pop_back();
1040 								replacement_map=backup_replacements;
1041 								subtree_replacement_map=backup_subtree_replacements;
1042 								}
1043 							}
1044 						else {
1045 							// Found all factors in sub-product, now check the conditions.
1046 							std::string error;
1047 							if(conditions==tr.end()) return match_t::subtree_match;
1048 							if(satisfies_conditions(conditions, error)) {
1049 								return match_t::subtree_match;
1050 								}
1051 							else {
1052 								factor_locations.pop_back();
1053 								replacement_map=backup_replacements;
1054 								subtree_replacement_map=backup_subtree_replacements;
1055 								}
1056 							}
1057 						}
1058 					}
1059 				else {
1060 					//				txtout << tofind.node << "does not match" << std::endl;
1061 					replacement_map=backup_replacements;
1062 					subtree_replacement_map=backup_subtree_replacements;
1063 					}
1064 				}
1065 			++start;
1066 			}
1067 		return match_t::no_match_less; // FIXME not entirely true
1068 		}
1069 
1070 	//Ex_comparator::match_t Ex_comparator::match_subsum(const Ex& tr,
1071 	//																		 Ex::sibling_iterator lhs,
1072 	//																		 Ex::sibling_iterator tofind,
1073 	//																		 Ex::sibling_iterator st,
1074 	//																		 Ex::iterator conditions)
1075 	//	{
1076 	//	// 'Start' iterates over all terms, trying to find 'tofind'.
1077 	//
1078 	//	Ex::sibling_iterator start=st.begin();
1079 	//	while(start!=st.end()) {
1080 	//
1081 	//		// The term 'tofind' can only be matched against a term in the
1082 	//		// subsum if we have not already previously matched part of the
1083 	//		// lhs to this factor. We check that first.
1084 	//
1085 	//		if(std::find(factor_locations.begin(), factor_locations.end(), start)==factor_locations.end()) {
1086 	//
1087 	//			// Compare this term with 'tofind'.
1088 	//
1089 	//			auto match = equal_subtree(tofind, start);
1090 	//			if(match==match_t::subtree_match || match==match_t::match_index_less || match==match_t::match_index_greater) {
1091 	//				factor_locations.push_back(start);
1092 	//
1093 	//				Ex::sibling_iterator nxt=tofind;
1094 	//				++nxt;
1095 	//				if(nxt!=lhs.end()) {
1096 	//					match_t res=match_subsum(tr, lhs, nxt, st, conditions);
1097 	//					return res;
1098 	//					}
1099 	//				else {
1100 	//					// Found all factors in sub-product.
1101 	//					auto sib=lhs.begin();
1102 	//					for(size_t i=0; i<factor_locations.size(); ++i) {
1103 	//						std::cerr << *factor_locations[i]->multiplier << " (vs " << *sib->multiplier << "), ";
1104 	//						++sib;
1105 	//						}
1106 	//					std::cerr << std::endl;
1107 	//
1108 	//					// Now check the conditions.
1109 	//					std::string error;
1110 	//					if(conditions==tr.end()) return match_t::subtree_match;
1111 	//					if(satisfies_conditions(conditions, error)) {
1112 	//						return match_t::subtree_match;
1113 	//						}
1114 	//					}
1115 	//				}
1116 	//			}
1117 	//		++start;
1118 	//		}
1119 	//	return match_t::no_match_less;
1120 	//	}
1121 
1122 
can_move_adjacent(Ex::iterator prod,Ex::sibling_iterator one,Ex::sibling_iterator two,bool fix_one)1123 	int Ex_comparator::can_move_adjacent(Ex::iterator prod,
1124 	                                     Ex::sibling_iterator one, Ex::sibling_iterator two, bool fix_one)
1125 		{
1126 		assert(Ex::parent(one)==Ex::parent(two));
1127 		assert(Ex::parent(one)==prod);
1128 
1129 		// Make sure that 'one' points to the object which occurs first in 'prod'.
1130 		bool onefirst=false;
1131 		Ex::sibling_iterator probe=one;
1132 		while(probe!=prod.end()) {
1133 			if(probe==two) {
1134 				onefirst=true;
1135 				break;
1136 				}
1137 			++probe;
1138 			}
1139 		int sign=1;
1140 		if(!onefirst) {
1141 			std::swap(one,two);
1142 			auto es=equal_subtree(one,two);
1143 			sign*=can_swap(one,two,es);
1144 			//		txtout << "swapping one and two: " << sign << std::endl;
1145 			}
1146 
1147 		if(sign!=0) {
1148 			// Loop over all pair flips which are necessary to move one to the left of two.
1149 			// Keep one fixed if fix_one is true.
1150 
1151 			if(fix_one) {
1152 				probe=two;
1153 				--probe;
1154 				while(probe!=one) {
1155 					auto es=equal_subtree(two,probe);
1156 					// std::cerr << "swapping " << Ex(two) << " and " << Ex(probe) << std::endl;
1157 					sign*=can_swap(two,probe,es);
1158 					if(sign==0) break;
1159 					--probe;
1160 					}
1161 				}
1162 			else {
1163 				probe=one;
1164 				++probe;
1165 				while(probe!=two) {
1166 					assert(probe!=prod.end());
1167 					auto es=equal_subtree(one,probe);
1168 					// std::cerr << "swapping " << Ex(one) << " and " << Ex(probe) << std::endl;
1169 					sign*=can_swap(one,probe,es);
1170 					if(sign==0) break;
1171 					++probe;
1172 					}
1173 				}
1174 			}
1175 		return sign;
1176 		}
1177 
can_move_to_front(Ex & tr,Ex::iterator prod,Ex::sibling_iterator one)1178 	int Ex_comparator::can_move_to_front(Ex& tr, Ex::iterator prod, Ex::sibling_iterator one)
1179 		{
1180 		// Insert a dummy, determine whether we can move
1181 		// next to the dummy, then erase the dummy again.
1182 		auto dummy = tr.prepend_child(prod, str_node("dummy"));
1183 		int sign=can_move_adjacent(prod, dummy, one, true);
1184 		tr.erase(dummy);
1185 		return sign;
1186 		}
1187 
can_swap_components(Ex::iterator one,Ex::iterator two,match_t subtree_comparison)1188 	int Ex_comparator::can_swap_components(Ex::iterator one, Ex::iterator two, match_t subtree_comparison)
1189 		{
1190 		int tmp;
1191 		auto impi=properties.get_with_pattern<ImplicitIndex>(one, tmp, "");
1192 		if(impi.first) {
1193 			if(impi.first->explicit_form.size()>0) {
1194 				one=impi.first->explicit_form.begin();
1195 				}
1196 			}
1197 		impi=properties.get_with_pattern<ImplicitIndex>(two, tmp, "");
1198 		if(impi.first) {
1199 			if(impi.first->explicit_form.size()>0) {
1200 				two=impi.first->explicit_form.begin();
1201 				}
1202 			}
1203 		return can_swap(one, two, subtree_comparison, true);
1204 		}
1205 
1206 	// Determine the sign required to move the last factor in 'factors' to
1207 	// the right of the first.  If moving left, do not count signs from
1208 	// moving past any of the other factors.  If moving right, do count
1209 	// those signs. In effect, the logic is that we count signs as if
1210 	// all other factors have already been moved to the right of the first.
1211 
can_move_adjacent(Ex::iterator prod,const std::vector<Ex::sibling_iterator> & factors,Ex::sibling_iterator i2)1212 	int Ex_comparator::can_move_adjacent(Ex::iterator prod, const std::vector<Ex::sibling_iterator>& factors, Ex::sibling_iterator i2)
1213 		{
1214 		if(factors.size()==0) return 1;
1215 
1216 		Ex::sibling_iterator i1=factors[0];
1217 
1218 		// Determine whether to move right or left.
1219 		bool move_right=true;
1220 		Ex::sibling_iterator probe=i1;
1221 		while(probe!=prod.end()) {
1222 			if(probe==i2) {
1223 				move_right=false;
1224 				break;
1225 				}
1226 			++probe;
1227 			}
1228 
1229 		// Move through all factors.
1230 		probe=i2;
1231 		int sign=1;
1232 		do {
1233 			if(move_right) ++probe;
1234 			else           --probe;
1235 			if(probe==i1)
1236 				break;
1237 
1238 			if(std::find(factors.begin(), factors.end(), probe)!=factors.end())
1239 				continue;
1240 			auto es=equal_subtree(i2, probe);
1241 			sign*=can_swap(i2, probe, es);
1242 
1243 			}
1244 		while(sign!=0);
1245 
1246 		if(move_right) {
1247 			// When moving right, all factors which we have already ordered
1248 			// sit to the right of the moving one, so we need to swap with them
1249 			// all.
1250 			auto f=factors.begin();
1251 			while(f!=factors.end()) {
1252 				auto es=equal_subtree(i2, *f);
1253 				sign*=can_swap(i2, *f, es);
1254 				++f;
1255 				}
1256 			}
1257 
1258 		return sign;
1259 		}
1260 
1261 
1262 	// Should obj and obj+1 be swapped, according to the SortOrder
1263 	// properties?
1264 	//
should_swap(Ex::iterator obj,match_t subtree_comparison)1265 	bool Ex_comparator::should_swap(Ex::iterator obj, match_t subtree_comparison)
1266 		{
1267 		Ex::sibling_iterator one=obj, two=obj;
1268 		++two;
1269 
1270 		// If the two objects are the same up to index names, we do not care
1271 		// whether it sits in a SortOrder list; just compare alpha.
1272 		if(subtree_comparison==match_t::match_index_less)    return false;
1273 		if(subtree_comparison==match_t::match_index_greater) return true;
1274 
1275 		// Find a SortOrder property which contains both one and two.
1276 		int num1, num2;
1277 		const SortOrder *so1=properties.get<SortOrder>(one,num1);
1278 		const SortOrder *so2=properties.get<SortOrder>(two,num2);
1279 
1280 		if(so1==0 || so2==0 || so1!=so2) {
1281 			// std::cerr << "No sort order between " << Ex(one) << " and " << Ex(two);
1282 			report(subtree_comparison);
1283 			// std::cerr <<  std::endl;
1284 			// No explicit sort order known; use alpha sort.
1285 			if(subtree_comparison==match_t::subtree_match)    return false;
1286 			if(subtree_comparison==match_t::no_match_less)    return false;
1287 			if(subtree_comparison==match_t::no_match_greater) return true;
1288 			return false;
1289 			}
1290 
1291 		assert(so1==so2);
1292 		return num1>num2;
1293 		}
1294 
1295 	// Various tests about whether two non-elementary objects can be swapped.
1296 	//
can_swap_prod_obj(Ex::iterator prod,Ex::iterator obj,bool ignore_implicit_indices)1297 	int Ex_comparator::can_swap_prod_obj(Ex::iterator prod, Ex::iterator obj,
1298 	                                     bool ignore_implicit_indices)
1299 		{
1300 		//	std::cout << "prod_obj " << *prod->name << " " << *obj->name << std::endl;
1301 		// Warning: no check is made that prod is actually a product!
1302 		int sign=1;
1303 		Ex::sibling_iterator sib=prod.begin();
1304 		while(sib!=prod.end()) {
1305 			const Indices *ind1=properties.get<Indices>(sib, true);
1306 			const Indices *ind2=properties.get<Indices>(obj, true);
1307 			if(! (ind1!=0 && ind2!=0) ) { // If both objects are actually real indices,
1308 				// then we do not include their commutativity property
1309 				// in the sign. This is because the routines that use
1310 				// can_swap_prod_obj all test for such index-index
1311 				// swaps separately.
1312 				auto es=equal_subtree(sib, obj);
1313 				//			std::cout << "  " << *sib->name << " " << *obj->name << " " << es << std::endl;
1314 				sign*=can_swap(sib, obj, es, ignore_implicit_indices);
1315 				if(sign==0) break;
1316 				}
1317 			++sib;
1318 			}
1319 		return sign;
1320 		}
1321 
can_swap_prod_prod(Ex::iterator prod1,Ex::iterator prod2,bool ignore_implicit_indices)1322 	int Ex_comparator::can_swap_prod_prod(Ex::iterator prod1, Ex::iterator prod2,
1323 	                                      bool ignore_implicit_indices)
1324 		{
1325 		//	std::cout << "prod_prod " << *prod1->name << " " << *prod2->name;
1326 		// Warning: no check is made that prod1,2 are actually products!
1327 		int sign=1;
1328 		Ex::sibling_iterator sib=prod2.begin();
1329 		while(sib!=prod2.end()) {
1330 			sign*=can_swap_prod_obj(prod1, sib, ignore_implicit_indices);
1331 			if(sign==0) break;
1332 			++sib;
1333 			}
1334 		//	std::cout << "  -> " << sign << std::endl;
1335 		return sign;
1336 		}
1337 
can_swap_sum_obj(Ex::iterator sum,Ex::iterator obj,bool ignore_implicit_indices)1338 	int Ex_comparator::can_swap_sum_obj(Ex::iterator sum, Ex::iterator obj,
1339 	                                    bool ignore_implicit_indices)
1340 		{
1341 		// Warning: no check is made that sum is actually a sum!
1342 		int sofar=2;
1343 		Ex::sibling_iterator sib=sum.begin();
1344 		while(sib!=sum.end()) {
1345 			auto es=equal_subtree(sib, obj);
1346 			int thissign=can_swap(sib, obj, es, ignore_implicit_indices);
1347 			if(sofar==2) sofar=thissign;
1348 			else if(thissign!=sofar) {
1349 				sofar=0;
1350 				break;
1351 				}
1352 			++sib;
1353 			}
1354 		return sofar;
1355 		}
1356 
can_swap_prod_sum(Ex::iterator prod,Ex::iterator sum,bool ignore_implicit_indices)1357 	int Ex_comparator::can_swap_prod_sum(Ex::iterator prod, Ex::iterator sum,
1358 	                                     bool ignore_implicit_indices)
1359 		{
1360 		// Warning: no check is made that sum is actually a sum or prod is a prod!
1361 		int sign=1;
1362 		Ex::sibling_iterator sib=prod.begin();
1363 		while(sib!=prod.end()) {
1364 			//		const Indices *ind=kernel.properties->get<Indices>(sib);
1365 			//		if(ind==0) {
1366 			sign*=can_swap_sum_obj(sum, sib, ignore_implicit_indices);
1367 			if(sign==0) break;
1368 			//			}
1369 			++sib;
1370 			}
1371 		return sign;
1372 		}
1373 
can_swap_sum_sum(Ex::iterator sum1,Ex::iterator sum2,bool ignore_implicit_indices)1374 	int Ex_comparator::can_swap_sum_sum(Ex::iterator sum1, Ex::iterator sum2,
1375 	                                    bool ignore_implicit_indices)
1376 		{
1377 		int sofar=2;
1378 		Ex::sibling_iterator sib=sum1.begin();
1379 		while(sib!=sum1.end()) {
1380 			int thissign=can_swap_sum_obj(sum2, sib, ignore_implicit_indices);
1381 			if(sofar==2) sofar=thissign;
1382 			else if(thissign!=sofar) {
1383 				sofar=0;
1384 				break;
1385 				}
1386 			++sib;
1387 			}
1388 		return sofar;
1389 		}
1390 
can_swap_ilist_ilist(Ex::iterator obj1,Ex::iterator obj2)1391 	int Ex_comparator::can_swap_ilist_ilist(Ex::iterator obj1, Ex::iterator obj2)
1392 		{
1393 		int sign=1;
1394 
1395 		index_iterator it1=index_iterator::begin(properties, obj1);
1396 		while(it1!=index_iterator::end(properties, obj1)) {
1397 			index_iterator it2=index_iterator::begin(properties, obj2);
1398 			while(it2!=index_iterator::end(properties, obj2)) {
1399 				// Only deal with real indices here, i.e. those carrying an Indices property.
1400 				const Indices *ind1=properties.get<Indices>(it1, true);
1401 				const Indices *ind2=properties.get<Indices>(it2, true);
1402 				if(ind1!=0 && ind2!=0) {
1403 					const CommutingBehaviour *com1 =properties.get<CommutingBehaviour>(it1, true);
1404 					const CommutingBehaviour *com2 =properties.get<CommutingBehaviour>(it2, true);
1405 
1406 					if(com1!=0  &&  com1 == com2)
1407 						sign *= com1->sign();
1408 
1409 					if(sign==0) break;
1410 					}
1411 				++it2;
1412 				}
1413 			if(sign==0) break;
1414 			++it1;
1415 			}
1416 
1417 		return sign;
1418 		}
1419 
can_swap_different_indexsets(Ex::iterator obj1,Ex::iterator obj2)1420 	bool Ex_comparator::can_swap_different_indexsets(Ex::iterator obj1, Ex::iterator obj2)
1421 		{
1422 		std::set<const Indices *> index_sets1;
1423 		// std::cerr << "Are " << obj1 << " and " << obj2 << " swappable?" << std::endl;
1424 
1425 		index_iterator it1=index_iterator::begin(properties, obj1);
1426 		while(it1!=index_iterator::end(properties, obj1)) {
1427 			auto ind = properties.get<Indices>(it1, true);
1428 			if(!ind) return false;
1429 			index_sets1.insert(ind);
1430 			++it1;
1431 			}
1432 		index_iterator it2=index_iterator::begin(properties, obj2);
1433 		while(it2!=index_iterator::end(properties, obj2)) {
1434 			auto ind = properties.get<Indices>(it2, true);
1435 			if(!ind) return false;
1436 			if(index_sets1.find(ind)!=index_sets1.end()) {
1437 				// std::cerr << "NO" << std::endl;
1438 				return false;
1439 				}
1440 			++it2;
1441 			}
1442 		// std::cerr << "YES" << std::endl;
1443 		return true;
1444 		}
1445 
can_swap(Ex::iterator one,Ex::iterator two,match_t,bool ignore_implicit_indices)1446 	int Ex_comparator::can_swap(Ex::iterator one, Ex::iterator two, match_t,
1447 	                            bool ignore_implicit_indices)
1448 		{
1449 		// std::cerr << "can_swap " << *one->name << " " << *two->name << " " << ignore_implicit_indices << std::endl;
1450 
1451 		// Explicitly declared commutation behaviour goes first.
1452 		const CommutingBehaviour *com = properties.get<CommutingBehaviour>(one, two, true);
1453 		if(com)
1454 			return com->sign();
1455 
1456 
1457 		// If both objects have implicit indices, we cannot swap the
1458 		// objects because that would re-order the index line. The sole
1459 		// exception is when these indices are explicitly stated to be in
1460 		// different sets.
1461 
1462 		const ImplicitIndex *ii1 = properties.get<ImplicitIndex>(one);
1463 		const ImplicitIndex *ii2 = properties.get<ImplicitIndex>(two);
1464 		if(!ignore_implicit_indices) {
1465 			if(ii1) {
1466 				if(ii1->explicit_form.size()==0) {
1467 					if(ii2) return 0; // nothing known about explicit form
1468 					}
1469 				else one=ii1->explicit_form.begin();
1470 				}
1471 			if(ii2) {
1472 				if(ii2->explicit_form.size()==0) {
1473 					if(ii1) return 0; // nothing known about explicit form
1474 					}
1475 				else two=ii2->explicit_form.begin();
1476 				}
1477 			// Check that indices in one and two are in mutually exclusive sets.
1478 			if(ii1 && ii2)
1479 				if(!can_swap_different_indexsets(one, two))
1480 					return false;
1481 			}
1482 
1483 		// Differential forms in a product cannot be moved through each
1484 		// other except when the degree of one of them is zero.  In a wedge
1485 		// product, we can move them and potentially pick up a sign.
1486 
1487 		const DifferentialFormBase *df1 = properties.get<DifferentialFormBase>(one);
1488 		const DifferentialFormBase *df2 = properties.get<DifferentialFormBase>(two);
1489 
1490 		if(df1 && df2) {
1491 			if(df1->degree(properties,one).begin()->is_zero() || df2->degree(properties,two).begin()->is_zero())
1492 				return 1;
1493 			else {
1494 				if(Ex::is_head(one) || *(Ex::parent(one)->name)=="\\wedge") {
1495 					if(df1->degree(properties, one).is_rational()==false ||
1496 					      df2->degree(properties, two).is_rational()==false)
1497 						return 0; // Cannot yet order forms with non-numerical degrees.
1498 					long d1 = to_long(df1->degree(properties, one).to_rational());
1499 					long d2 = to_long(df2->degree(properties, two).to_rational());
1500 					if( (d1*d2) % 2 == 1) return -1;
1501 					return 1;
1502 					}
1503 				}
1504 			}
1505 
1506 		// Do we need to use Self* properties?
1507 		const SelfCommutingBehaviour *sc1 =properties.get<SelfCommutingBehaviour>(one, true);
1508 		const SelfCommutingBehaviour *sc2 =properties.get<SelfCommutingBehaviour>(two, true);
1509 		if( (sc1!=0 && sc1==sc2) )
1510 			return sc1->sign();
1511 
1512 		// One or both of the objects are not in an explicit list. So now comes the generic
1513 		// part. The first step is to look at all explicit indices of the two objects and determine
1514 		// their commutativity.
1515 		// Note: this does not yet look at arguments (non-index children).
1516 
1517 		int tmpsign=can_swap_ilist_ilist(one, two);
1518 		if(tmpsign==0) return 0;
1519 
1520 		// The second step is to check for product-like and sum-like behaviour. The following
1521 		// take into account all commutativity properties of explict with implicit indices,
1522 		// as well as hard-specified commutativity of factors.
1523 
1524 		const CommutingAsProduct *comap1 = properties.get<CommutingAsProduct>(one);
1525 		const CommutingAsProduct *comap2 = properties.get<CommutingAsProduct>(two);
1526 		const CommutingAsSum     *comas1 = properties.get<CommutingAsSum>(one);
1527 		const CommutingAsSum     *comas2 = properties.get<CommutingAsSum>(two);
1528 
1529 		if(comap1 && comap2) return tmpsign*can_swap_prod_prod(one,two,ignore_implicit_indices);
1530 		if(comap1 && comas2) return tmpsign*can_swap_prod_sum(one,two,ignore_implicit_indices);
1531 		if(comap2 && comas1) return tmpsign*can_swap_prod_sum(two,one,ignore_implicit_indices);
1532 		if(comas1 && comas2) return tmpsign*can_swap_sum_sum(one,two,ignore_implicit_indices);
1533 		if(comap1)           return tmpsign*can_swap_prod_obj(one,two,ignore_implicit_indices);
1534 		if(comap2)           return tmpsign*can_swap_prod_obj(two,one,ignore_implicit_indices);
1535 		if(comas1)           return tmpsign*can_swap_sum_obj(one,two,ignore_implicit_indices);
1536 		if(comas2)           return tmpsign*can_swap_sum_obj(two,one,ignore_implicit_indices);
1537 
1538 		return 1; // default: commuting.
1539 		}
1540 
satisfies_conditions(Ex::iterator conditions,std::string & error)1541 	bool Ex_comparator::satisfies_conditions(Ex::iterator conditions, std::string& error)
1542 		{
1543 //		std::cerr << "satisfies_conditions" << std::endl;
1544 		for(unsigned int i=0; i<Ex::arg_size(conditions); ++i) {
1545 			Ex::iterator cond=Ex::arg(conditions, i);
1546 //			std::cerr << "condition " << cond << std::endl;
1547 			if(*cond->name=="\\unequals") {
1548 				Ex::sibling_iterator lhs=cond.begin();
1549 				Ex::sibling_iterator rhs=lhs;
1550 				++rhs;
1551 				// Lookup the replacement rules for the two given objects, and return true if
1552 				// those rules give a different result. But first check that there are rules
1553 				// to start with.
1554 				//			std::cerr << *lhs->name  << " !=? " << *rhs->name << std::endl;
1555 				if(replacement_map.find(Ex(lhs))==replacement_map.end() ||
1556 				      replacement_map.find(Ex(rhs))==replacement_map.end()) return true;
1557 				//			std::cerr << *lhs->name  << " !=?? " << *rhs->name << std::endl;
1558 				if(tree_exact_equal(&properties, replacement_map[Ex(lhs)], replacement_map[Ex(rhs)])) {
1559 					return false;
1560 					}
1561 				}
1562 			else if(*cond->name=="\\greater" || *cond->name=="\\less") {
1563 				Ex::sibling_iterator lhs=cond.begin();
1564 				Ex::sibling_iterator rhs=lhs;
1565 				++rhs;
1566 
1567 				multiplier_t mlhs;
1568 				if(lhs->is_rational()==false) {
1569 					auto fnd=replacement_map.find(Ex(lhs));
1570 //					std::cerr << "finding " << lhs << std::endl;
1571 					if(fnd!=replacement_map.end()) {
1572 						auto tn=fnd->second.begin();
1573 //						std::cerr << tn << std::endl;
1574 						if(tn->is_rational())
1575 							mlhs=*tn->multiplier;
1576 						else {
1577 							error="Replacement not numerical.";
1578 							return false;
1579 							}
1580 						}
1581 					else {
1582 						error="Can only compare objects which evaluate to numbers.";
1583 						return false;
1584 						}
1585 					}
1586 				else mlhs=*lhs->multiplier;
1587 
1588 				// FIXME: abstract into Storage
1589 				multiplier_t mrhs;
1590 				if(rhs->is_rational()==false) {
1591 					auto fnd=replacement_map.find(Ex(rhs));
1592 					if(fnd!=replacement_map.end()) {
1593 						auto tn=fnd->second.begin();
1594 						if(tn->is_rational())
1595 							mrhs=*tn->multiplier;
1596 						else {
1597 							error="Replacement not numerical.";
1598 							return false;
1599 							}
1600 						}
1601 					else {
1602 						error="Can only compare objects which evaluate to numbers.";
1603 						return false;
1604 						}
1605 					}
1606 				else mrhs=*rhs->multiplier;
1607 
1608 				if(*cond->name=="\\greater" && mlhs <= mrhs) return false;
1609 				if(*cond->name=="\\less"    && mlhs >= mrhs) return false;
1610 				}
1611 			else if(*cond->name=="\\indexpairs") {
1612 				int countpairs=0;
1613 				replacement_map_t::const_iterator it=replacement_map.begin(),it2;
1614 				while(it!=replacement_map.end()) {
1615 					it2=it;
1616 					++it2;
1617 					while(it2!=replacement_map.end()) {
1618 						if(tree_exact_equal(&properties, it->second, it2->second)) {
1619 							++countpairs;
1620 							break;
1621 							}
1622 						++it2;
1623 						}
1624 					++it;
1625 					}
1626 				//			txtout << countpairs << " pairs" << std::endl;
1627 				if(countpairs!=*(cond.begin()->multiplier))
1628 					return false;
1629 				}
1630 			else if(*cond->name=="\\regex") {
1631 				//			txtout << "regex matching..." << std::endl;
1632 				Ex::sibling_iterator lhs=cond.begin();
1633 				Ex::sibling_iterator rhs=lhs;
1634 				++rhs;
1635 				// If we have a match, all indices have replacement rules.
1636 				std::string pat=(*rhs->name).substr(1,(*rhs->name).size()-2);
1637 				//			txtout << "matching " << *comp.replacement_map[lhs->name]
1638 				//					 << " with pattern " << pat << std::endl;
1639 				std::regex reg(pat);
1640 				if (!std::regex_match(*(replacement_map[Ex(lhs)].begin()->name), reg))
1641 					return false;
1642 				}
1643 			// V2: FIXME: re-enable searching for properties
1644 			//		else if(*cond->name=="\\hasprop") {
1645 			//			Ex::sibling_iterator lhs=cond.begin();
1646 			//			Ex::sibling_iterator rhs=lhs;
1647 			//			++rhs;
1648 			//			Properties::registered_property_map_t::iterator pit=properties->store.find(*rhs->name);
1649 			//			if(pit==properties->store.end()) {
1650 			//				std::ostringstream str;
1651 			//				str << "Property \"" << *rhs->name << "\" not registered." << std::endl;
1652 			//				error=str.str();
1653 			//				return false;
1654 			//				}
1655 			//			const property_base *aprop=pit->second();
1656 			//
1657 			//			subtree_replacement_map_t::iterator subfind=subtree_replacement_map.find(lhs->name);
1658 			//			replacement_map_t::iterator         patfind=replacement_map.find(Ex(lhs));
1659 			//
1660 			//			if(subfind==subtree_replacement_map.end() && patfind==replacement_map.end()) {
1661 			//				std::ostringstream str;
1662 			//				str << "Pattern " << *lhs->name << " in \\hasprop did not occur in match." << std::endl;
1663 			//				delete aprop;
1664 			//				error=str.str();
1665 			//				return false;
1666 			//				}
1667 			//
1668 			//			bool ret=false;
1669 			//			if(subfind==subtree_replacement_map.end())
1670 			//				 ret=properties->has(aprop, (*patfind).second.begin());
1671 			//			else
1672 			//				 ret=properties->has(aprop, (*subfind).second);
1673 			//			delete aprop;
1674 			//			return ret;
1675 			//			}
1676 			else {
1677 				std::ostringstream str;
1678 				str << "substitute: condition involving " << *cond->name << " not understood." << std::endl;
1679 				error=str.str();
1680 				return false;
1681 				}
1682 			}
1683 		return true;
1684 		}
1685 
Ex_is_equivalent(const Properties & k)1686 	Ex_is_equivalent::Ex_is_equivalent(const Properties& k)
1687 		: properties(k)
1688 		{
1689 		}
1690 
operator ()(const Ex & one,const Ex & two)1691 	bool Ex_is_equivalent::operator()(const Ex& one, const Ex& two)
1692 		{
1693 		int ret=subtree_compare(&properties, one.begin(), two.begin());
1694 		if(ret==0) return true;
1695 		else       return false;
1696 		}
1697 
Ex_is_less(const Properties & k,int mp)1698 	Ex_is_less::Ex_is_less(const Properties& k, int mp)
1699 		: properties(k), mod_prel(mp)
1700 		{
1701 		}
1702 
operator ()(const Ex & one,const Ex & two)1703 	bool Ex_is_less::operator()(const Ex& one, const Ex& two)
1704 		{
1705 		int ret=subtree_compare(&properties, one.begin(), two.begin(), mod_prel);
1706 		if(ret < 0) return true;
1707 		else        return false;
1708 		}
1709 
1710 	}
1711 
operator <(const cadabra::Ex::iterator & i1,const cadabra::Ex::iterator & i2)1712 bool operator<(const cadabra::Ex::iterator& i1, const cadabra::Ex::iterator& i2)
1713 	{
1714 	return i1.node < i2.node;
1715 	}
1716 
operator <(const cadabra::Ex & e1,const cadabra::Ex & e2)1717 bool operator<(const cadabra::Ex& e1, const cadabra::Ex& e2)
1718 	{
1719 	return e1.begin().node < e2.begin().node;
1720 	}
1721 
operator <<(std::ostream & s,cadabra::Ex_comparator::useprops_t up)1722 std::ostream& operator<<(std::ostream& s, cadabra::Ex_comparator::useprops_t up)
1723 	{
1724 	switch(up) {
1725 		case cadabra::Ex_comparator::useprops_t::always:
1726 			s << "always";
1727 			break;
1728 		case cadabra::Ex_comparator::useprops_t::not_at_top:
1729 			s << "not_at_top";
1730 			break;
1731 		case cadabra::Ex_comparator::useprops_t::never:
1732 			s << "never";
1733 			break;
1734 		}
1735 	return s;
1736 	}
1737 
1738 
1739