1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
#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;
}
|