#include "PreClean.hh" #include "Cleanup.hh" namespace cadabra { void pre_clean_dispatch(const Kernel& kernel, Ex& ex, Ex::iterator& it) { if(*it->name!="1" && it->is_unsimplified_rational()) cleanup_rational(kernel, ex, it); if(*it->name=="\\frac") cleanup_frac(kernel, ex, it); else if(*it->name=="\\sub") cleanup_sub(kernel, ex, it); else if(*it->name=="\\sqrt") cleanup_sqrt(kernel, ex, it); else if((*it->name).substr(0,2)=="UP" || (*it->name).substr(0,2)=="DN") cleanup_updown(kernel, ex, it); cleanup_indexbracket(kernel, ex, it); } void pre_clean_dispatch_deep(const Kernel& k, Ex& tr) { return cleanup_dispatch_deep(k, tr, &pre_clean_dispatch); } void cleanup_updown(const Kernel&, Ex&, Ex::iterator& st) { std::string rn=*st->name; bool isup=true; if(rn.substr(0,2)=="DN") isup=false; rn=rn.substr(2); // tr.flatten(st); // st=tr.erase(st); if(isup) st->fl.parent_rel=str_node::p_super; else st->fl.parent_rel=str_node::p_sub; st->name=name_set.insert(rn).first; } void cleanup_rational(const Kernel&, Ex&, Ex::iterator& st) { multiplier_t num(*st->name); num.canonicalize(); st->name=name_set.insert("1").first; multiply(st->multiplier,num); } void cleanup_frac(const Kernel&, Ex& tr, Ex::iterator& st) { // Catch \frac{} nodes with one argument; those are supposed to be read as 1/(...). // The only exception is \frac{#}, which needs to stay as it is. if(tr.number_of_children(st)==1) { if(tr.begin(st)->is_range_wildcard()) return; tr.insert(tr.begin(st), str_node("1")); } // Turn this into a \prod node. Everything except the first child // should be wrapped in a \pow{..}{-1} node. auto sib=tr.begin(st); ++sib; while(sib!=tr.end(st)) { sib = tr.wrap(sib, str_node("\\pow")); multiply( tr.append_child(sib, str_node("1"))->multiplier, -1 ); ++sib; } st->name=name_set.insert("\\prod").first; // assert(tr.number_of_children(st)>1); // Ex::sibling_iterator it=tr.begin(st); // multiplier_t rat; // // bool allnumerical=true; // rat=*(it->multiplier); // if(it->is_rational()==false) // allnumerical=false; // // one(it->multiplier); // ++it; // while(it!=tr.end(st)) { // if(*it->multiplier==0) { // // CHECK: do these zeroes get handled correctly elsewhere? // return; // } // rat/=*it->multiplier; // one(it->multiplier); // if(it->is_rational()==false) allnumerical=false; // ++it; // } // if(allnumerical) { // can remove the \frac altogether // tr.erase_children(st); // st->name=name_set.insert("1").first; // } // else { // just remove the all-numerical child nodes // it=tr.begin(st); // ++it; // while(it!=tr.end(st)) { // if(it->is_rational()) // it=tr.erase(it); // else ++it; // } // if(tr.number_of_children(st)==1) { // tr.begin(st)->fl.bracket=st->fl.bracket; // tr.begin(st)->fl.parent_rel=st->fl.parent_rel; // multiply(tr.begin(st)->multiplier, *st->multiplier); // tr.flatten(st); // st=tr.erase(st); // } // } // multiply(st->multiplier, rat); } void cleanup_sqrt(const Kernel&, Ex& tr, Ex::iterator& st) { st->name=name_set.insert("\\pow").first; multiply(tr.append_child(st, str_node("1"))->multiplier, multiplier_t(1)/2); } void cleanup_sub(const Kernel&, Ex& tr, Ex::iterator& it) { assert(tr.number_of_children(it)>1); // To guarantee that we have really cleaned up that old stuff. it->name=name_set.insert("\\sum").first; Ex::sibling_iterator sit=tr.begin(it); // Make sure that all terms have the right sign, and zeroes are removed. if(*sit->multiplier==0) sit=tr.erase(sit); else ++sit; while(sit!=tr.end(it)) { if(*sit->multiplier==0) sit=tr.erase(sit); else { flip_sign(sit->multiplier); ++sit; } } // Single-term situation: remove the \sum. if(tr.number_of_children(it)==0) { zero(it->multiplier); it->name=name_set.insert("1").first; } else { if(tr.number_of_children(it)==1) { sit=tr.begin(it); sit->fl.parent_rel=it->fl.parent_rel; sit->fl.bracket=it->fl.bracket; multiply(sit->multiplier, *it->multiplier); tr.flatten(it); it=tr.erase(it); } } } void cleanup_indexbracket(const Kernel&, Ex& tr, Ex::iterator& it) { if((*it->name).size()==0) { auto sib=tr.begin(it); if(sib->fl.parent_rel!=str_node::p_super && sib->fl.parent_rel!=str_node::p_sub) { ++sib; while(sib!=tr.end(it)) { if(sib->fl.parent_rel==str_node::p_super || sib->fl.parent_rel==str_node::p_sub) { it->name=name_set.insert("\\indexbracket").first; return; } ++sib; } } } else if(*it->name=="\\prod" || *it->name=="\\sum") { auto sib=tr.begin(it); while(sib!=tr.end(it)) { if(sib->fl.parent_rel==str_node::p_super || sib->fl.parent_rel==str_node::p_sub) { auto ibrack=tr.insert(it,str_node("\\indexbracket")); Ex::sibling_iterator nxt=it; ++nxt; tr.reparent(ibrack,Ex::sibling_iterator(it),nxt); it=tr.begin(ibrack); auto sib=tr.begin(it); while(sib!=tr.end(it)) { if(sib->fl.parent_rel==str_node::p_super || sib->fl.parent_rel==str_node::p_sub) { tr.append_child(ibrack,*sib); sib=tr.erase(sib); } else ++sib; } it=ibrack; return; } ++sib; } } } std::string replace_all(std::string const& original, std::string const& from, std::string const& to ) { std::string results; std::string::const_iterator end = original.end(); std::string::const_iterator current = original.begin(); std::string::const_iterator next = std::search( current, end, from.begin(), from.end() ); while ( next != end ) { results.append( current, next ); results.append( to ); current = next + from.size(); next = std::search( current, end, from.begin(), from.end() ); } results.append( current, next ); return results; } }