Skip to content

Commit d1c24de

Browse files
committed
Use cyclicity of the trace
Analyzing an expression is easiest if all n! orderings of a given product produce the same output when passed to sort_product(). Unfortunately, this is very hard to achieve in a CAS for non-commuting objects. Consider matrices A and C with a scalar B. CAB and BCA are equal but the first is "sorted" because B comes after A and the second is "sorted" because B comes before C. An opportunity for making this better occurs when the expression is inside a trace. Then, B can be pulled out by untrace() and the rest can be sorted with cyclicity. Signed-off-by: Connor Behan <[email protected]>
1 parent fe4c302 commit d1c24de

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

core/algorithms/sort_product.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include "Cleanup.hh"
33
#include "algorithms/sort_product.hh"
4+
#include "properties/Trace.hh"
45

56
using namespace cadabra;
67

@@ -88,6 +89,61 @@ Algorithm::result_t sort_product::apply(iterator& st)
8889
}
8990
}
9091

92+
if(ret==result_t::l_no_action) {
93+
bool found=false;
94+
bool ascend=true;
95+
iterator parn=st;
96+
// It is fine to cycle when we have a sum of a sum inside a trace
97+
while(ascend && !tr.is_head(parn)) {
98+
parn=tr.parent(parn);
99+
const Trace *trace=kernel.properties.get<Trace>(parn);
100+
if(trace) {
101+
ascend=false;
102+
found=true;
103+
}
104+
else if(*parn->name=="\\indexbracket") {
105+
ascend=false;
106+
if(number_of_indices(parn)==2) {
107+
index_iterator first=begin_index(parn);
108+
index_iterator last=first;
109+
++last;
110+
if(*first->name==*last->name) found=true;
111+
}
112+
}
113+
else if(*parn->name!="\\sum") {
114+
ascend=false;
115+
}
116+
}
117+
if(found) {
118+
one=tr.begin(st);
119+
two=one;
120+
++two;
121+
while(two!=tr.end(st)) {
122+
compare.clear();
123+
auto es=compare.equal_subtree(one, two);
124+
if(compare.should_swap(one, es)) one=two;
125+
++two;
126+
}
127+
// We have found the element that should go at the front of the trace
128+
Ex::sibling_iterator front=one;
129+
while(tr.begin(st)!=front) {
130+
one=tr.begin(st);
131+
two=one;
132+
++two;
133+
while(two!=tr.end(st)) {
134+
compare.clear();
135+
auto es=compare.equal_subtree(one, two);
136+
int sign=compare.can_swap_components(one, two, es);
137+
if(sign==-1) flip_sign(st->multiplier);
138+
tr.swap(one);
139+
++two;
140+
++two;
141+
}
142+
}
143+
ret=result_t::l_applied;
144+
}
145+
}
146+
91147
if(cleanup)
92148
cleanup_dispatch(kernel, tr, st);
93149

tests/implicit.cdb

100644100755
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,29 @@ def test11():
144144

145145
test11()
146146

147+
def test12():
148+
__cdbkernel__=create_scope()
149+
{a,b}::Indices(vector);
150+
Tr{#}::Trace(indices=vector);
151+
A::ImplicitIndex(A_{a b});
152+
B::ImplicitIndex(B_{a b});
153+
{A_{a b}, B_{a b}}::AntiCommuting;
154+
ex:=Tr( B A );
155+
sort_product(_);
156+
tst:= Tr( -A B ) - @(ex);
157+
assert(tst==0)
158+
print("Test 12 passed")
159+
160+
test12()
161+
162+
def test13():
163+
__cdbkernel__=create_scope()
164+
{A,B,C}::ImplicitIndex;
165+
ex:=(B A C)_{a a};
166+
sort_product(_);
167+
tst:= (A C B)_{a a} - @(ex);
168+
assert(tst==0)
169+
print("Test 13 passed")
170+
171+
test13()
172+

0 commit comments

Comments
 (0)