1
2 #include "Compare.hh"
3 #include "Cleanup.hh"
4 #include "algorithms/unwrap.hh"
5 #include "properties/Derivative.hh"
6 #include "properties/Accent.hh"
7 #include "properties/DiracBar.hh"
8 #include "properties/Spinor.hh"
9 #include "properties/DifferentialForm.hh"
10 #include "properties/GammaMatrix.hh"
11 #include "properties/DependsBase.hh"
12 //#include "algorithms/prodcollectnum.hh"
13
14 // #define DEBUG 1
15
16 using namespace cadabra;
17
unwrap(const Kernel & k,Ex & tr,Ex & w)18 unwrap::unwrap(const Kernel& k, Ex& tr, Ex& w)
19 : Algorithm(k, tr)
20 {
21 if(w.begin()!=w.end()) {
22 if(*w.begin()->name!="\\comma")
23 wrappers.push_back(w);
24 else {
25 auto sib=w.begin(w.begin());
26 while(sib!=w.end(w.begin())) {
27 wrappers.push_back(Ex(sib));
28 ++sib;
29 }
30 }
31 }
32 }
33
can_apply(iterator it)34 bool unwrap::can_apply(iterator it)
35 {
36 const Derivative *der=kernel.properties.get<Derivative>(it);
37 const Accent *acc=kernel.properties.get<Accent>(it);
38 if(der || acc) {
39 Ex_comparator comp(kernel.properties);
40 if(wrappers.size()>0) {
41 bool found=false;
42 for(auto&w : wrappers) {
43 #ifdef DEBUG
44 std::cerr << "comparing " << w << " to " << Ex(it) << std::endl;
45 #endif
46 if(comp.equal_subtree(w.begin(), it)==Ex_comparator::match_t::subtree_match) {
47 #ifdef DEBUG
48 std::cerr << "yes" << std::endl;
49 #endif
50 found=true;
51 break;
52 }
53 }
54 if(!found) return false;
55 }
56 return true;
57 }
58
59 if(*it->name=="\\wedge") return true;
60
61 return false;
62 }
63
apply_on_wedge(iterator & it)64 Algorithm::result_t unwrap::apply_on_wedge(iterator& it)
65 {
66 result_t res=result_t::l_no_action;
67
68 auto prodwrap = tr.wrap(it, str_node("\\prod"));
69
70 sibling_iterator sib=tr.begin(it);
71 while(sib!=tr.end(it)) {
72 if(*sib->name=="\\prod") {
73 sibling_iterator fac=tr.begin(sib);
74 while(fac!=tr.end(sib)) {
75 const DifferentialFormBase *diff = kernel.properties.get<DifferentialFormBase>(fac);
76 sibling_iterator nxt=fac;
77 ++nxt;
78 if(diff==0 || diff->degree(kernel.properties, fac).begin()->is_zero() ) {
79 // Figure out the sign. First move to front of existing
80 // simple product. Then move through all other factors
81 // in the wedge product.
82 Ex_comparator comp(kernel.properties);
83 int sign=comp.can_move_to_front(tr, sib, fac);
84 if(sign!=0) {
85 sibling_iterator prevwedfac=sib;
86 if(prevwedfac!=tr.begin(it)) {
87 do {
88 --prevwedfac;
89 auto stc=comp.equal_subtree(prevwedfac, fac);
90 sign*=comp.can_swap(prevwedfac, fac, stc);
91 } while(prevwedfac!=tr.begin(it));
92 }
93 if(sign!=0) {
94 tr.move_before(it, fac);
95 multiply(prodwrap->multiplier, sign);
96 }
97 }
98 }
99 fac=nxt;
100 }
101 }
102 sibling_iterator nxt=sib;
103 ++nxt;
104 iterator tmp=sib;
105 cleanup_dispatch(kernel, tr, tmp);
106 sib=nxt;
107 }
108 cleanup_dispatch(kernel, tr, prodwrap);
109
110 return res;
111 }
112
113 // \del{a*f*A*b*C*d*e} -> a*f*\del{A*b*C}*d*e
114 //
115 // locate first dependent factor
116 // locate first following independent factor
117 // ...
118 //
119 // Should also work for brackets, like
120 //
121 // \poisson( A )( B ) -> 0
122 //
123 // if either A or B has vanishing poisson bracket, and
124 //
125 // \poisson( N1 D1 )( N2 D2 ) -> N1 N2 \poisson( D1 )( D2 ).
126 //
127 // So all "derivatives"
128
apply(iterator & it)129 Algorithm::result_t unwrap::apply(iterator& it)
130 {
131 #ifdef DEBUG
132 std::cerr << "Applying unwrap at " << Ex(it) << std::endl;
133 #endif
134
135 if(*it->name=="\\wedge")
136 return apply_on_wedge(it);
137
138 result_t res = result_t::l_no_action;
139
140 bool is_accent=kernel.properties.get<Accent>(it);
141 bool is_diracbar=kernel.properties.get<DiracBar>(it);
142
143 // Wrap the 'derivative' in a product node so we can take
144 // child nodes out and stuff them inside the product.
145
146 iterator old_it=it;
147 it=tr.wrap(it, str_node("\\prod"));
148
149 bool all_arguments_moved_out=true;
150 sibling_iterator acton=tr.begin(old_it);
151 while(acton!=tr.end(old_it)) {
152 // Only look at child nodes which are not indices.
153 if(acton->is_index()==false) {
154 sibling_iterator derarg=acton;
155 ++acton; // don't use this anymore this loop
156
157 if(*derarg->name=="\\sum") {
158 all_arguments_moved_out=false;
159 continue; // FIXME: Don't know how to handle this yet.
160 }
161
162 #ifdef DEBUG
163 std::cerr << "doing " << *derarg->name << std::endl;
164 #endif
165
166 // If the argument of the derivative is not a product, make
167 // into one, so we can handle everything using the same code.
168 if(*derarg->name!="\\prod")
169 derarg=tr.wrap(derarg, str_node("\\prod"));
170
171 // Iterate over all arguments of the product sitting inside
172 // the derivative (but see the comment above).
173 sibling_iterator factor=tr.begin(derarg);
174 while(factor!=tr.end(derarg)) {
175 // std::cerr << "checking " << Ex(factor) << std::endl;
176
177 sibling_iterator nxt=factor;
178 ++nxt;
179 bool move_out=true;
180
181 // An object pattern like 'A??' should always be assumed to have
182 // dependence, because we don't yet know what it will match.
183 if(move_out) {
184 if(factor->is_name_wildcard() || factor->is_object_wildcard())
185 move_out=false;
186 }
187
188 if(move_out) {
189 if(is_diracbar)
190 if(kernel.properties.get<Spinor>(factor) || kernel.properties.get<GammaMatrix>(factor))
191 move_out=false;
192 }
193
194 // Then figure out whether there is implicit dependence on the operator.
195 // or on the coordinate.
196 if(move_out) {
197 const DependsBase *dep=kernel.properties.get<DependsBase>(factor);
198 if(dep!=0) {
199 #ifdef DEBUG
200 std::cerr << *factor->name << " acted on by " << *old_it->name << "; depends" << std::endl;
201 #endif
202 auto derivative=kernel.properties.get<Derivative>(old_it);
203 Ex deps=dep->dependencies(kernel, factor /* it */);
204 sibling_iterator depobjs=deps.begin(deps.begin());
205 while(depobjs!=deps.end(deps.begin())) {
206 #ifdef DEBUG
207 std::cerr << "?" << *old_it->name << " == " << *depobjs->name << std::endl;
208 #endif
209 // FIXME: need to compare more than the name
210 if(old_it->name == depobjs->name) {
211 move_out=false;
212 break;
213 }
214 else if(derivative && derivative->with_respect_to.size()>0 && derivative->with_respect_to.begin()->name==depobjs->name) {
215 move_out=false;
216 break;
217 }
218 else {
219 // compare all indices
220 #ifdef DEBUG
221 std::cerr << "comparing indices" << std::endl;
222 #endif
223 sibling_iterator indit=tr.begin(old_it);
224 while(indit!=tr.end(old_it)) {
225 if(indit->is_index()) {
226 #ifdef DEBUG
227 std::cerr << "compare " << *indit->name << " to " << *depobjs->name << std::endl;
228 #endif
229 if(subtree_compare(&kernel.properties, indit, depobjs, 0, false, 0, false)==0) {
230 #ifdef DEBUG
231 std::cerr << "not moving out" << std::endl;
232 #endif
233 move_out=false;
234 break;
235 }
236 }
237 ++indit;
238 }
239 if(!move_out) break;
240 }
241 ++depobjs;
242 }
243 }
244 }
245
246 // Finally, there may also be explicit dependence.
247 if(move_out) {
248 // FIXME: This certainly does not handle Y(a,b) correctly
249 sibling_iterator chldit=tr.begin(factor);
250 while(chldit!=tr.end(factor)) {
251 if(chldit->is_index()==false) {
252 sibling_iterator indit=tr.begin(old_it);
253 while(indit!=tr.end(old_it)) {
254 if(subtree_exact_equal(&kernel.properties, chldit, indit, 0)) {
255 move_out=false;
256 break;
257 }
258 ++indit;
259 }
260 if(!move_out) break;
261 }
262 ++chldit;
263 }
264 }
265
266 // If no dependence found, move this child out of the derivative.
267 if(move_out) {
268 // FIXME: Does does not look at the commutativity
269 // property of the index/indices wrt. which the
270 // derivative is taken.
271 int sign=1;
272 if(factor!=tr.begin(derarg)) {
273 Ex_comparator compare(kernel.properties);
274 sign=compare.can_move_to_front(tr, derarg, factor); //, Ex_comparator::match_t::no_match_less);
275 }
276 if(sign!=0) {
277 // If the sign *is* zero, it means that we are trying to move a factor
278 // through another one, but do not know how to do that. In that case,
279 // you cannot move the factor out.
280 res=result_t::l_applied;
281 tr.move_before(old_it, factor);
282 multiply(it->multiplier, sign);
283 }
284 }
285
286 factor=nxt;
287 }
288
289 // std::cerr << "after step " << Ex(it) << std::endl;
290
291 // All factors in this argument have been handled now, let's see what's left.
292 unsigned int derarg_num_chldr=tr.number_of_children(derarg);
293 if(derarg_num_chldr==0) {
294 // Empty accents should simply be ignored, but empty derivatives vanish.
295 if(!is_accent) {
296 zero(it->multiplier);
297 break; // we can stop now, the entire expression is zero.
298 }
299 }
300 else {
301 all_arguments_moved_out=false;
302 if(derarg_num_chldr==1) {
303 derarg=tr.flatten_and_erase(derarg);
304 }
305 }
306 }
307 else ++acton;
308 }
309
310
311 // All non-index arguments have now been handled.
312 if(all_arguments_moved_out && is_accent) {
313 zero(it->multiplier);
314 }
315 else if(*it->multiplier!=0) {
316 if(tr.number_of_children(it)==1) { // nothing was moved out
317 tr.flatten(it);
318 it=tr.erase(it);
319 }
320 else {
321 // Moving factors around has potentially led to a top-level product
322 // which contains children with non-unit multiplier.
323 cleanup_dispatch(kernel, tr, it);
324
325 // If the derivative acts on another derivative, we need
326 // to un-nest the argument of the outer (and this situation
327 // can only happen if there is only one non-index child node)
328 iterator itarg=tr.begin(it);
329 while(itarg->is_index())
330 ++itarg;
331
332 cleanup_dispatch(kernel, tr, itarg);
333 }
334 }
335 cleanup_dispatch(kernel, tr, it);
336
337 // std::cerr << "unwrap done " << it << std::endl;
338
339 return res;
340 }
341