#include "Cleanup.hh" #include "algorithms/young_project_product.hh" #include "algorithms/young_project_tensor.hh" #include "algorithms/distribute.hh" #include "algorithms/collect_terms.hh" #include "algorithms/canonicalise.hh" using namespace cadabra; young_project_product::young_project_product(const Kernel& k, Ex& tr) : Algorithm(k, tr) { } bool young_project_product::can_apply(iterator it) { if(*it->name=="\\prod") return true; return false; } Algorithm::result_t young_project_product::apply(iterator& it) { result_t res=result_t::l_no_action; Ex rep; iterator topsum = rep.set_head(str_node("\\sum")); sibling_iterator sib=tr.begin(it); bool first=true; while(sib!=tr.end(it)) { young_project_tensor ypt(kernel, tr, true); sibling_iterator nxt=sib; ++nxt; if(ypt.can_apply(sib)) { ypt.modulo_monoterm=true; iterator ii(sib); ypt.apply(ii); if(*ii->name!="\\sum") ii=tr.wrap(ii, str_node("\\sum")); res=result_t::l_applied; if(first) { // Add a new \prod node to rep for each term in the projected factor. first=false; sibling_iterator trm=tr.begin(ii); while(trm!=tr.end(ii)) { iterator prod=rep.append_child(topsum, str_node("\\prod")); prod->fl.bracket=str_node::b_round; prod->multiplier=it->multiplier; rep.append_child(prod, iterator(trm)); ++trm; } } else { // Distribute this projected factor over all existing terms in rep, sibling_iterator trm=rep.begin(topsum); while(trm!=rep.end(topsum)) { // iterator tmp=trm; sibling_iterator nxttrm=trm; ++nxttrm; // Copy this term out of the sum and append projected factor. Ex work(trm); iterator workit=work.begin(); iterator put=rep.append_child(work.begin(), str_node()); if(tr.number_of_children(ii)==1) rep.replace(put, tr.begin(ii)); else { rep.replace(put, ii); // Distribute the product. distribute dis(kernel, work); if(dis.can_apply(workit)) dis.apply(workit); } // txtout << "GOOD?" << std::endl; // work.print_recursive_treeform(txtout, work.begin()); // Canonicalise all new products. canonicalise can(kernel, work); // txtout << *workit->name << " " << *put->name << std::endl; can.apply_generic(workit, true, false, 0); if(*work.begin()->multiplier!=0) { // The upcoming move wants to see a sum, even if there is only one term if(*work.begin()->name!="\\sum") work.wrap(work.begin(), str_node("\\sum")); // Move back to the original tree. sibling_iterator cpyit=work.begin(work.begin()); while(cpyit!=work.end(work.begin())) { sibling_iterator cpyitnxt=cpyit; ++cpyitnxt; rep.move_before(trm, cpyit); cpyit=cpyitnxt; } } rep.erase(trm); trm=nxttrm; } collect_terms coll(kernel, rep); if(coll.can_apply(topsum)) coll.apply(topsum); // If collect terms removed the sum because there was only // one term (or zero) left, put it back in. if(*topsum->name!="\\sum") topsum=tr.wrap(topsum, str_node("\\sum")); } } else { if(first) { first=false; iterator prod=rep.append_child(topsum, str_node("\\prod")); prod->fl.bracket=str_node::b_round; prod->multiplier=it->multiplier; rep.append_child(prod, iterator(sib)); } else { // just multiply all terms with this factor sibling_iterator trm=rep.begin(topsum); while(trm!=rep.end(topsum)) { iterator put=rep.append_child(trm,str_node()); tr.replace(put, iterator(sib)); ++trm; } } } // rep.print_recursive_treeform(debugout, rep.begin()); sib=nxt; } if(res==result_t::l_applied) { it=tr.replace(it, rep.begin()); // FIXME: this canonicalise should really not be necessary // txtout << "WHOOAAH " << *it->name << std::endl; // tr.print_recursive_treeform(txtout, it); // canonicalise can(tr, tr.end()); // can.apply_recursive(it, false); cleanup_dispatch(kernel, tr, it); } return res; }