55
66using namespace cadabra ;
77
8- combine::combine (const Kernel& k, Ex& e)
9- : Algorithm(k, e)
8+ combine::combine (const Kernel& k, Ex& e, Ex& t )
9+ : Algorithm(k, e), trace_op(t)
1010 {
1111 }
1212
@@ -36,7 +36,7 @@ Algorithm::result_t combine::apply(iterator& it)
3636
3737 while (ind_dummy.begin ()!=ind_dummy.end ()) {
3838 bool found=false ;
39- index_map_t ::iterator start=ind_dummy.begin ();
39+ index_map_t ::iterator start=ind_dummy.begin (), backup ;
4040 while (!found && start!=ind_dummy.end ()) {
4141 iterator parent=tr.parent (start->second );
4242 sibling_iterator ch=tr.begin (parent), last_part;
@@ -46,11 +46,17 @@ Algorithm::result_t combine::apply(iterator& it)
4646 ++ch;
4747 }
4848 if (last_part==start->second ) {
49- // We are on a rightmost contracted index
50- found=true ;
49+ ++last_part;
50+ if (last_part==tr.end (parent)) {
51+ // Dummy index with nothing to the right is preferred
52+ found=true ;
53+ }
54+ else backup=start;
5155 }
52- else ++start;
56+ if (!found) ++start;
5357 }
58+ // As a backup, we use a dummy index with only non-dummies to the right
59+ if (!found) start=backup;
5460 bool paired=true ;
5561 while (paired && start!=ind_dummy.end ()) {
5662 iterator parent=tr.parent (start->second );
@@ -95,6 +101,7 @@ Algorithm::result_t combine::apply(iterator& it)
95101 }
96102 }
97103
104+ std::string trace_start=" " ;
98105 std::vector<Ex::iterator>::iterator dums1=dummies.begin (), dums2;
99106 dums2=dums1;
100107 ++dums2;
@@ -133,6 +140,38 @@ Algorithm::result_t combine::apply(iterator& it)
133140 iterator brackprod=tr.append_child (outerbrack, str_node (" \\ prod" ));
134141 iterator parn1=tr.parent (*dums1);
135142 iterator parn2=tr.parent (*dums2);
143+
144+ // count how many sign changes stand between the two objects
145+ int sign=1 ;
146+ unsigned int hits=0 ;
147+ Ex_comparator compare (kernel.properties );
148+ sib=tr.begin (it);
149+ while (hits<2 ) {
150+ if (hits==1 && sib!=parn2) {
151+ // pass arguments manually as can_swap() does not check them
152+ bool isbrack=*(sib->name )==" \\ indexbracket" ;
153+ if (isbrack && isbrack2) {
154+ auto es=compare.equal_subtree (tr.begin (parn2), tr.begin (sib));
155+ sign*=compare.can_swap_components (tr.begin (parn2), tr.begin (sib), es);
156+ }
157+ else if (isbrack && !isbrack2) {
158+ auto es=compare.equal_subtree (parn2, tr.begin (sib));
159+ sign*=compare.can_swap_components (parn2, tr.begin (sib), es);
160+ }
161+ else if (!isbrack && isbrack2) {
162+ auto es=compare.equal_subtree (tr.begin (parn2), sib);
163+ sign*=compare.can_swap_components (tr.begin (parn2), sib, es);
164+ }
165+ else {
166+ auto es=compare.equal_subtree (parn2, sib);
167+ sign*=compare.can_swap_components (parn2, sib, es);
168+ }
169+ }
170+ if (sib==parn1 || sib==parn2) ++hits;
171+ ++sib;
172+ }
173+ if (sign==-1 ) flip_sign (brackprod->multiplier );
174+
136175 // remove the dummy index from these two objects, and move
137176 // other (dummy or not) indices to the outer indexbracket.
138177 sibling_iterator ind1=tr.begin (tr.parent (*dums1));
@@ -197,7 +236,22 @@ Algorithm::result_t combine::apply(iterator& it)
197236 if (consecutive) {
198237 ++dums1;
199238 ++dums2;
239+ if (dums2!=dummies.end () && trace_op.size ()>0 ) {
240+ if (*(*dums2)->name ==trace_start) {
241+ iterator parn=tr.parent (*dums2);
242+ iterator trace=tr.insert (parn, str_node (trace_op.begin ()->name ));
243+ sibling_iterator nxt=tr.begin (parn);
244+ ++nxt;
245+ ++dums1;
246+ ++dums2;
247+ tr.reparent (trace, tr.begin (parn), nxt);
248+ multiply (trace->multiplier , *parn->multiplier );
249+ tr.erase (parn);
250+ trace_start=" " ;
251+ }
252+ }
200253 }
254+ else trace_start=*(*dums1)->name ;
201255 ++dums1;
202256 ++dums2;
203257 }
0 commit comments