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
|
#include "algorithms/take_match.hh"
#include "algorithms/substitute.hh"
#include "Cleanup.hh"
using namespace cadabra;
take_match::take_match(const Kernel& k, Ex& e, Ex& rules_)
: Algorithm(k, e), rules(rules_)
{
// Create a proper substitution rule out of the pattern (otherwise
// substitute will not swallow it).
auto wrap = rules.wrap(rules.begin(), str_node("\\arrow"));
rules.append_child(wrap, str_node("dummy"));
}
bool take_match::can_apply(iterator it)
{
// Apply only on terms in a top-level sum (NO LONGER: or elements of a top-level list),
// or on terms inside an integral.
// The second condition can be relaxed in the future to cover other
// operators which distribute over sums; for now let's be conservative.
// Note that any changes here need corresponding changes in replace_match.
if(*it->name=="\\sum") {
if(tr.is_head(it) ||
*tr.parent(it)->name=="\\int" ||
*tr.parent(it)->name=="\\equals") {
to_keep.clear();
to_erase.clear();
substitute subs(kernel, tr, rules);
sibling_iterator sib=tr.begin(it);
while(sib!=tr.end(it)) {
if(subs.can_apply(sib)==false)
to_erase.push_back(sib);
else
to_keep.push_back(tr.path_from_iterator(sib, tr.begin()));
++sib;
}
// If there is no match whatsoever we cannot apply here.
if(to_keep.size()==0) return false;
return true;
}
}
return false;
}
Algorithm::result_t take_match::apply(iterator& it)
{
// Push a copy of the expression onto the history stack. The
// 'to_keep' is a reference to the paths vector on the associated
// stack.
auto itpath = tr.path_from_iterator(it, tr.begin());
tr.push_history(to_keep);
// Now erase what we do not want anymore, the cleanup
for(auto& s: to_erase)
tr.erase(s);
cleanup_dispatch(kernel, tr, it);
return result_t::l_applied;
}
|