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