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 147 148 149
|
#include "algorithms/drop_weight.hh"
#include "Cleanup.hh"
#include "Props.hh"
#include "properties/Weight.hh"
#include "properties/WeightInherit.hh"
using namespace cadabra;
drop_keep_weight::drop_keep_weight(const Kernel& k, Ex& tr, Ex& a)
: Algorithm(k, tr), arg(a)
{
if(arg.begin()==arg.end())
throw ArgumentException("drop_keep_weight: need 'weight=rational' argument.");
if(Ex::number_of_children(arg.begin())!=2)
throw ArgumentException("drop_keep_weight: need 'weight=rational' argument.");
if(*(arg.begin()->name)!="\\equals")
throw ArgumentException("drop_keep_weight: need 'weight=rational' argument.");
}
// This algorithm acts on nodes which have Weight or inherit Weight.
// It only acts when the parent does _not_ have or inherit weight.
// This makes sure that we act on sums and products which are not
// themselves terms or factors in a sum or product.
bool drop_keep_weight::can_apply(iterator st)
{
//std::cerr << "can act? at " << st << std::endl;
sibling_iterator argit=arg.begin(arg.begin());
label=*argit->name;
++argit;
weight=*argit->multiplier;
// std::cerr << "dk: " << label << " = " << weight << std::endl;
const WeightInherit *gmnpar=0;
const Weight *wghpar=0;
gmn=kernel.properties.get<WeightInherit>(st, label);
wgh=kernel.properties.get<Weight>(st, label);
if(tr.is_head(st)==false) {
gmnpar=kernel.properties.get<WeightInherit>(tr.parent(st), label);
wghpar=kernel.properties.get<Weight>(tr.parent(st), label);
}
// std::cerr << *st->name << ": " << gmn << ", " << wgh << ", " << gmnpar << " " << std::endl;
if(gmn!=0 || wgh!=0) {
bool ret = (gmnpar==0 && wghpar==0);
// std::cerr << "can_apply " << ret << std::endl;
return ret;
}
// std::cerr << "cannot apply" << std::endl;
return false;
}
Algorithm::result_t drop_keep_weight::do_apply(iterator& it, bool keepthem)
{
Algorithm::result_t res=result_t::l_no_action;
if(gmn) {
if(gmn->combination_type==WeightInherit::multiplicative) {
if((keepthem==true && weight!=gmn->value(kernel, it, label)) ||
(keepthem==false && weight==gmn->value(kernel, it, label))) {
zero(it->multiplier);
}
}
else {
sibling_iterator sib=tr.begin(it);
while(sib!=tr.end(it)) {
if(*sib->name=="\\ldots") {
++sib;
continue;
}
const WeightBase *gnb=kernel.properties.get<WeightBase>(sib, label);
if(gnb) {
// std::cerr << "WeightBase for child " << Ex(sib) << std::endl;
multiplier_t val;
bool no_val=false;
try {
val=gnb->value(kernel, sib, label);
// std::cerr << *sib->name << " has weight " << val << std::endl;
}
catch(WeightInherit::WeightException& we) {
// std::cerr << *sib->name << " has undeterminable weight " << std::endl;
// If we cannot determine the weight of this term because this is a sum of
// terms with different weights: keep when in @drop, drop when in @keep.
no_val=true;
}
if( (no_val==false && ( (keepthem==true && weight!=val) || (keepthem==false && weight==val) ) )
|| (no_val==true && keepthem==true) ) {
sib=tr.erase(sib);
}
else ++sib;
}
else {
// std::cerr << "NO WeightBase for child " << Ex(sib) << std::endl;
if( (keepthem==true && weight!=0) || (keepthem==false && weight==0) ) {
sib=tr.erase(sib);
}
else ++sib;
}
}
if(tr.number_of_children(it)==0)
zero(it->multiplier);
else if(tr.number_of_children(it)==1) {
tr.flatten(it);
it=tr.erase(it);
}
res=result_t::l_applied;
}
}
else {
assert(wgh);
if((keepthem==true && weight!=wgh->value(kernel, it, label)) ||
(keepthem==false && weight==wgh->value(kernel, it, label))) {
res = result_t::l_applied;
zero(it->multiplier);
}
}
cleanup_dispatch(kernel, tr, it);
return res;
}
drop_weight::drop_weight(const Kernel& k, Ex& e, Ex& a)
: drop_keep_weight(k, e, a)
{
}
Algorithm::result_t drop_weight::apply(iterator& it)
{
return do_apply(it, false);
}
keep_weight::keep_weight(const Kernel& k, Ex& e, Ex& a)
: drop_keep_weight(k, e, a)
{
}
Algorithm::result_t keep_weight::apply(iterator& it)
{
return do_apply(it, true);
}
|