#include "Algorithm.hh" #include "DisplayTerminal.hh" #include "Symbols.hh" #include "properties/Accent.hh" using namespace cadabra; DisplayTerminal::DisplayTerminal(const Kernel& k, const Ex& e, bool uuc) : DisplayBase(k, e), use_unicode(uuc) { symmap = { {"\\cos", "cos"}, {"\\sin", "sin"}, {"\\tan", "tan"}, {"\\cosh", "cosh"}, {"\\sinh", "sinh"}, {"\\tanh", "tanh"}, {"\\int", "∫" }, {"\\sum", "∑" } }; } // Logic: each node should check whether it needs to have brackets printed around // all of itself. The function below will determine that by inspecting the parent // node. Nodes should NOT print brackets for children. bool DisplayTerminal::needs_brackets(Ex::iterator it) { // FIXME: may need looking at properties // FIXME: write as individual parent/current tests if(tree.is_head(it)) return false; // Ex::iterator parent_it = tree.parent(it); Ex::iterator child_it = it; int child_num = tree.index(it); std::string parent=*tree.parent(it)->name; std::string child =*it->name; if(parent=="\\partial" && child=="\\sum") return true; if(parent=="\\frac" && ( child=="\\sum" || child=="\\prod" || (*child_it->multiplier!=1 && child_num>0) )) return true; if(parent=="\\pow" && ( !it->is_integer() || child=="\\prod" || child=="\\sum" || child=="\\pow") ) return true; // negative and fractional exponents need brackets. if(parent=="\\pow" && (*it->multiplier < 0 || !it->is_integer()) ) return true; // if(parent=="\\pow" && child_num>0 && *child_it->multiplier!=1 ) return true; if(parent=="\\prod" && child=="\\sum") return true; // if(it->fl.parent_rel==str_node::p_none && (child=="\\sum" || child=="\\prod") ) return true; return false; } //void DisplayTerminal::dispatch(std::ostream& str, Ex::iterator it) // { // // // print multiplier and object name // if(*it->multiplier!=1) // print_multiplier(str, it); // // if(*it->name=="1") { // if(*it->multiplier==1 || (*it->multiplier==-1)) // this would print nothing altogether. // str << "1"; // return; // } // // bool needs_extra_brackets=false; // const Accent *ac=kernel.properties.get(it); // if(!ac) { // accents should never get additional curly brackets, {\bar}{g} does not print. // Ex::sibling_iterator sib=tree.begin(it); // while(sib!=tree.end(it)) { // if(sib->is_index()) // needs_extra_brackets=true; // ++sib; // } // } // // if(needs_extra_brackets) str << "{"; // to prevent double sup/sub script errors // auto rn = symmap.find(*it->name); // if(rn!=symmap.end()) // str << rn->second; // else // str << *it->name; // if(needs_extra_brackets) str << "}"; // // print_children(str, it); // } void DisplayTerminal::print_children(std::ostream& str, Ex::iterator it, int skip) { str_node::bracket_t previous_bracket_ =str_node::b_invalid; str_node::parent_rel_t previous_parent_rel_=str_node::p_invalid; int number_of_nonindex_children=0; int number_of_index_children=0; Ex::sibling_iterator ch=tree.begin(it); while(ch!=tree.end(it)) { if(ch->is_index()==false) { ++number_of_nonindex_children; if(*ch->name=="\\prod") ++number_of_nonindex_children; } else ++number_of_index_children; ++ch; } ch=tree.begin(it); ch+=skip; unsigned int chnum=0; while(ch!=tree.end(it)) { str_node::bracket_t current_bracket_ =(*ch).fl.bracket; str_node::parent_rel_t current_parent_rel_=(*ch).fl.parent_rel; const Accent *is_accent=kernel.properties.get(it); if(current_bracket_==str_node::b_none) { if(previous_bracket_==str_node::b_none && current_parent_rel_==previous_parent_rel_ && current_parent_rel_==str_node::p_none) str << ", "; } if(current_bracket_!=str_node::b_none || previous_bracket_!=current_bracket_ || previous_parent_rel_!=current_parent_rel_) { print_parent_rel(str, current_parent_rel_, ch==tree.begin(it)); if(is_accent==0) print_opening_bracket(str, (number_of_nonindex_children>1 /* &&number_of_index_children>0 */ && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << "{"; } // print this child depending on its name or meaning dispatch(str, ch); ++ch; if(ch==tree.end(it) || current_bracket_!=str_node::b_none || current_bracket_!=(*ch).fl.bracket || current_parent_rel_!=(*ch).fl.parent_rel) { if(is_accent==0) print_closing_bracket(str, (number_of_nonindex_children>1 /* &&number_of_index_children>0 */ && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << "}"; } else str << " "; previous_bracket_=current_bracket_; previous_parent_rel_=current_parent_rel_; ++chnum; } } void DisplayTerminal::print_multiplier(std::ostream& str, Ex::iterator it, int mult) { mpz_class denom=it->multiplier->get_den(); if(denom!=1) { if(mult*it->multiplier->get_num()<0) { str << " - "; mult *= -1; } str << " " << mult * it->multiplier->get_num() << "/" << it->multiplier->get_den() << " "; } else if(mult * (*it->multiplier)==-1) { str << "-"; } else { str << mult * (*it->multiplier); } /* bool turned_one=false; mpz_class denom=it->multiplier->get_den(); if(*it->multiplier<0) { if(*tree.parent(it)->name=="\\sum") { // sum takes care of minus sign if(*it->multiplier!=-1) { if(denom!=1) { str << "\\frac{" << -(it->multiplier->get_num()) << "}{" << it->multiplier->get_den() << "}"; } else { str << -(*it->multiplier); } } else turned_one=true; } else { if(denom!=1) { str << "(\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "})"; } else if(*it->multiplier==-1) { str << "-"; turned_one=true; } else { str << "(" << *it->multiplier << ")"; } } } else { if(denom!=1) { str << "\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "}"; } else str << *it->multiplier; } if(!turned_one && !(*it->name=="1")) str << "*"; */ } void DisplayTerminal::print_opening_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: if(pr==str_node::p_none) str << "("; else str << "{"; break; case str_node::b_pointy: str << "<"; break; case str_node::b_curly: str << "{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(bracket_level); } void DisplayTerminal::print_closing_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: if(pr==str_node::p_none) str << ")"; else str << "}"; break; case str_node::b_pointy: str << ">"; break; case str_node::b_curly: str << "}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(bracket_level); } void DisplayTerminal::print_parent_rel(std::ostream& str, str_node::parent_rel_t pr, bool) { switch(pr) { case str_node::p_super: str << "^"; break; case str_node::p_sub: str << "_"; break; case str_node::p_property: str << "$"; break; case str_node::p_exponent: str << "**"; break; case str_node::p_none: break; case str_node::p_components: break; case str_node::p_invalid: break; } } void DisplayTerminal::dispatch(std::ostream& str, Ex::iterator it) { if(*it->name=="\\prod") print_productlike(str, it, " "); else if(*it->name=="\\sum") print_sumlike(str, it); else if(*it->name=="\\frac") print_fraclike(str, it); else if(*it->name=="\\comma") print_commalike(str, it); else if(*it->name=="\\commutator") print_commutator(str, it, true); else if(*it->name=="\\anticommutator") print_commutator(str, it, false); else if(*it->name=="\\arrow") print_arrowlike(str, it); else if(*it->name=="\\inner") print_dot(str, it); else if(*it->name=="\\pow") print_powlike(str, it); else if(*it->name=="\\wedge") print_productlike(str, it, " ^ "); else if(*it->name=="\\conditional") print_conditional(str, it); else if(*it->name=="\\greater" || *it->name=="\\less") print_relation(str, it); else if(*it->name=="\\int") print_intlike(str, it); else if(*it->name=="\\sum") print_intlike(str, it); else if(*it->name=="\\equals") print_equalitylike(str, it); else if(*it->name=="\\components") print_components(str, it); else if(*it->name=="\\ldots") print_dots(str, it); else print_other(str, it); } void DisplayTerminal::print_commalike(std::ostream& str, Ex::iterator it) { Ex::sibling_iterator sib=tree.begin(it); bool first=true; str << "{"; while(sib!=tree.end(it)) { if(first) first=false; else str << ", "; dispatch(str, sib); ++sib; } str << "}"; } void DisplayTerminal::print_arrowlike(std::ostream& str, Ex::iterator it) { Ex::sibling_iterator sib=tree.begin(it); dispatch(str, sib); if(use_unicode) str << " → "; else str << " -> "; ++sib; dispatch(str, sib); } void DisplayTerminal::print_dot(std::ostream& str, Ex::iterator it) { Ex::sibling_iterator sib=tree.begin(it); dispatch(str, sib); if(use_unicode) str << "·"; else str << "."; ++sib; dispatch(str, sib); } void DisplayTerminal::print_fraclike(std::ostream& str, Ex::iterator it) { Ex::sibling_iterator num=tree.begin(it), den=num; ++den; if(*it->multiplier!=1) print_multiplier(str, it); // if(needs_brackets(num)) // str << "("; if(num->is_rational()==false || (*it->multiplier)==1) dispatch(str, num); // if(needs_brackets(num)) // str << ")"; str << "/"; // if(needs_brackets(den)) // str << "("; dispatch(str, den); // if(needs_brackets(den)) // str << ")"; } void DisplayTerminal::print_productlike(std::ostream& str, Ex::iterator it, const std::string& inbetween) { if(needs_brackets(it)) str << "("; if(*it->multiplier!=1) { print_multiplier(str, it); // Ex::sibling_iterator st=tree.begin(it); } // To print \prod{\sum{a}{b}}{\sum{c}{d}} correctly: // If there is any sum as child, and if the sum children do not // all have the same bracket type (different from b_none or b_no), // then print brackets. str_node::bracket_t previous_bracket_=str_node::b_invalid; // bool beginning_of_group=true; Ex::sibling_iterator ch=tree.begin(it); while(ch!=tree.end(it)) { str_node::bracket_t current_bracket_=(*ch).fl.bracket; if(previous_bracket_!=current_bracket_) { if(current_bracket_!=str_node::b_none) { print_opening_bracket(str, current_bracket_, str_node::p_none); // beginning_of_group=true; } } dispatch(str, ch); ++ch; if(ch==tree.end(it)) { if(current_bracket_!=str_node::b_none) print_closing_bracket(str, current_bracket_, str_node::p_none); } if(ch!=tree.end(it)) { str << inbetween; } previous_bracket_=current_bracket_; } if(needs_brackets(it)) str << ")"; } void DisplayTerminal::print_sumlike(std::ostream& str, Ex::iterator it) { assert(*it->multiplier==1); if(needs_brackets(it)) str << "("; Ex::sibling_iterator ch=tree.begin(it); while(ch!=tree.end(it)) { if(*ch->multiplier>=0 && ch!=tree.begin(it)) str << " + "; dispatch(str, ch); ++ch; } if(needs_brackets(it)) str << ")"; str << std::flush; } void DisplayTerminal::print_powlike(std::ostream& str, Ex::iterator it) { if(needs_brackets(it)) str << "("; Ex::sibling_iterator sib=tree.begin(it); if(*it->multiplier!=1) print_multiplier(str, it); dispatch(str, sib); // if(needs_brackets(sib)) // str << ")"; str << "**"; ++sib; // if(needs_brackets(sib)) // str << "("; dispatch(str, sib); if(needs_brackets(it)) str << ")"; } void DisplayTerminal::print_conditional(std::ostream& str, Ex::iterator it) { auto sib=tree.begin(it); dispatch(str, sib); str << " with "; ++sib; dispatch(str, sib); } void DisplayTerminal::print_relation(std::ostream& str, Ex::iterator it) { auto sib=tree.begin(it); dispatch(str, sib); if(*it->name=="\\greater") str << " > "; if(*it->name=="\\less") str << " < "; ++sib; dispatch(str, sib); } void DisplayTerminal::print_intlike(std::ostream& str, Ex::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); if(!use_unicode || getenv("CADABRA_NO_UNICODE")!=0) str << *it->name << "{"; else str << symmap[*it->name] << "("; Ex::sibling_iterator sib=tree.begin(it); dispatch(str, sib); ++sib; if(tree.is_valid(sib)) { str << "}{"; dispatch(str, sib); } str << "}"; } void DisplayTerminal::print_equalitylike(std::ostream& str, Ex::iterator it) { Ex::sibling_iterator sib=tree.begin(it); dispatch(str, sib); str << " = "; ++sib; if(sib==tree.end(it)) throw ConsistencyException("Found equals node with only one child node."); dispatch(str, sib); } void DisplayTerminal::print_commutator(std::ostream& str, Ex::iterator it, bool comm) { if(comm) str << "["; else str << "{"; auto sib=tree.begin(it); bool first=true; while(sib!=tree.end(it)) { if(!first) str << ", "; else first=false; dispatch(str, sib); ++sib; } if(comm) str << "]"; else str << "}"; } void DisplayTerminal::print_components(std::ostream& str, Ex::iterator it) { if( ! (use_unicode && getenv("CADABRA_NO_UNICODE")==0) ) { print_other(str, it); return; } str << R"(□)"; auto sib=tree.begin(it); auto end=tree.end(it); --end; if(sib!=end) { bool needs_close=false; str_node::parent_rel_t prel=str_node::parent_rel_t::p_none; while(sib!=end) { if(sib->fl.parent_rel!=prel) { if(needs_close) str << "}"; needs_close=true; prel=sib->fl.parent_rel; if(prel==str_node::p_sub) str << "_{"; if(prel==str_node::p_super) str << "^{"; } dispatch(str, sib); ++sib; } if(needs_close) str << "}"; } str << "\n"; sib=tree.begin(end); while(sib!=tree.end(end)) { str << " "; dispatch(str, sib); str << "\n"; ++sib; } } bool DisplayTerminal::children_have_brackets(Ex::iterator ch) const { Ex::sibling_iterator chlds=tree.begin(ch); str_node::bracket_t childbr=chlds->fl.bracket; if(childbr==str_node::b_none || childbr==str_node::b_no) return false; else return true; } void DisplayTerminal::print_dots(std::ostream& str, Ex::iterator ) { str << " ... "; } void DisplayTerminal::print_other(std::ostream& str, Ex::iterator it) { if(needs_brackets(it)) str << "("; // print multiplier and object name if(*it->multiplier!=1) print_multiplier(str, it); if(*it->name=="1") { if(*it->multiplier==1 || (*it->multiplier==-1)) // this would print nothing altogether. str << "1"; if(needs_brackets(it)) str << ")"; return; } bool needs_extra_brackets=false; // const Accent *ac=kernel.properties.get(it); // if(!ac) { // accents should never get additional curly brackets, {\bar}{g} does not print. // Ex::sibling_iterator sib=tree.begin(it); // while(sib!=tree.end(it)) { // if(sib->is_index()) // needs_extra_brackets=true; // ++sib; // } // } if(needs_extra_brackets) str << "{"; // to prevent double sup/sub script errors std::string sbit=*it->name; if(use_unicode && getenv("CADABRA_NO_UNICODE")==0) { auto rn1 = symmap.find(sbit); if(rn1!=symmap.end()) sbit = rn1->second; auto rn = cadabra::symbols::greekmap.find(sbit); if(rn!=cadabra::symbols::greekmap.end()) sbit = rn->second; } str << sbit; if(needs_extra_brackets) str << "}"; print_children(str, it); if(needs_brackets(it)) str << ")"; }