/*************************************************************************** FemtoCad.cpp - an implementation of some of the Cadabra functionality ------------------- begin : Wed 14 July 2010 copyright : (C) 2010 by Chris Austin email : chris@chrisaustin.info ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include using namespace std; struct chpr { char cr; char rs; }; struct strpr { string dv; string rm; }; char fstnb(const string bufr, size_t& pos); char nxtc(const string bufr, size_t& pos); char nxtnb(const string bufr, size_t& pos); char aftrfctr(const string bufr, size_t& pos); char aftrtrm(const string bufr, size_t& pos); int rmvxtrblnk(string& bufr); int rplcmmp(string& bufr, size_t pos); int rmvxtrpls(string& bufr, size_t pos); void tdysgnblnk(string& bufr); void dstrib(string& bufr); chpr chdd(char a, char b); chpr chml(char a, char b); chpr chsb(char a, char b); string rlz(const string a); string strchdd(const string a, char b, long n); string strchml(const string a, char b, long n); string strchsb(const string a, char b, long n); strpr strlngdv(const string a, const string b); int strcm(const string a, const string b); string strdd(const string a, const string b); string strml(const string a, const string b); string strsb(const string a, const string b); string strdv(const string a, const string b); string strdr(const string a, const string b); string gcd(const string a, const string b); int isrt(const string a); strpr rt2nd(const string a); string rtrdc(const string a); string rtml(const string a, const string b); char nxt2(const string bufr, size_t& pos); char aftrfct2(const string bufr, size_t& pos); void clctnmfc(string& bufr); void fndrplc(string& bufr, const char* a, const char* b); void ndcprp(string& bufr); void ntgprp(string& bufr); void cfnprp(string& bufr); void cfndrlnrp(string& bufr, const string cfnt); void pdwthblnks(string& bufr); string prpfrct(const string bufr); string nxtndx(const string bufr, size_t& pos1, size_t& pos2, bool& nbrcs); string ntnbrcsnxtndx(const string bufr, size_t& pos1, size_t& pos2, bool& nbrcs); string ndxlst(const string bufr, size_t pos1, size_t pos2); string sdndlst(const string tmndlst, const string ndcs); string rpndlst(const string tmndlst, string& ndcp); string prpndcp(const string trmlst, const string ndcs); string ndendint(const string ndx); void sdndx(string& bufr, size_t pos1, size_t& pos2, const string ndcs); void rpndx(string& bufr, size_t pos1, size_t& pos2, const string ndlst, const string rplst); string mpnd2nd(const string alst, const string blst, const string ndx); void sdndbf(string& bufr, const string ndcs); void snglndbrcs(string& bufr); void sdndtmbtm(string& bufr, const string ndcs); bool tstsnglfctr(const string bufr); bool tstdblfctr(const string bufr); void sbsaftrfctr(const string bfcp, size_t& pos); string stwsouts(const string a, const string b); string prprplrhs(const string rhslst, const string lhslst, const string mchlst, const string rnllst, const string rplrnl); void sbsttt(const string cmnd, string& bufr, const string ndcs); int main(int argc, char* argv[]) // argc is total number of words in command line // argv[] is array of pointers to the command line words { char c, svd; int rdsvd = 0, hvcln = 0, ndcmnd, aftrdblcln, npr, shwc; string prop, ndcs, ntgr, cfnt, expr, cmnd; try { prop.clear(); ndcs.clear(); ntgr.clear(); cfnt.clear(); do { cmnd.clear(); ndcmnd = aftrdblcln = 0; shwc = 1; do { if ( rdsvd == 0 ) cin >> noskipws >> c; else { c = svd; rdsvd = 0; } if ( ( c < 0x20 ) || ( c > 0x7e ) ) c = ' '; if ( aftrdblcln == 1 ) { if ( c == '(' ) npr++; if ( c == ')' ) npr--; if ( ( c == '.' ) && ( npr == 0 ) ) ndcmnd = 1; } if ( hvcln == 1 ) { hvcln = 0; if ( c != ':' ) { svd = c; rdsvd = 1; ndcmnd = 1; c = ':'; shwc = 0; } else { aftrdblcln = 1; npr = 0; } } else if ( c == ':' ) hvcln = 1; if ( c == ';' ) ndcmnd = 1; if ( ( shwc == 1 ) && ( ( !cmnd.empty() ) || ( c != ' ' ) ) ) cmnd += c; } while ( ( !cin.eof() ) && ( ndcmnd != 1 ) ); if ( cin.eof() ) break; if ( c == '.' ) { if ( cmnd.find("::Indices") != string::npos ) { ndcprp(cmnd); ndcs += cmnd; } else if ( cmnd.find("::Integer(") != string::npos ) { ntgprp(cmnd); ntgr += cmnd; } else if ( cmnd.find("::Coefficients") != string::npos ) { cfnprp(cmnd); cfnt += cmnd; } else prop += cmnd; } else if ( cmnd[0] != '@' ) { expr = cmnd; cfndrlnrp(expr, cfnt); clctnmfc(expr); } else if ( cmnd.find("@all_contractions") != string::npos ) cout << "@all_contractions command" << endl; else if ( cmnd.find("@canonicalise") != string::npos ) cout << "@canonicalise command" << endl; else if ( cmnd.find("@collect_terms") != string::npos ) cout << "@collect_terms command" << endl; else if ( cmnd.find("@decompose") != string::npos ) cout << "@decompose command" << endl; else if ( cmnd.find("@distribute") != string::npos ) dstrib(expr); else if ( cmnd.find("@eliminate_kr") != string::npos ) cout << "@eliminate_kr command" << endl; else if ( cmnd.find("@length") != string::npos ) cout << "@length command" << endl; else if ( cmnd.find("@quit") != string::npos ) { cmnd.clear(); break; } else if ( cmnd.find("@rename_dummies") != string::npos ) sdndtmbtm(expr, ndcs); else if ( cmnd.find("@standardize") != string::npos ) sdndbf(expr, ndcs); else if ( cmnd.find("@substitute") != string::npos ) sbsttt(cmnd, expr, ndcs); else break; if ( cmnd[cmnd.length() - 1] == ';' ) cout << prpfrct(expr) << endl; } while ( 1 ); if ( !cmnd.empty() ) { cout << cmnd << endl; cout << "Command not recognized" << endl; } } catch (int e) { if ( e == 0 ) cout << "Empty parentheses" << endl; if ( e == 1 ) cout << "Unmatched ( or {" << endl; if ( e == 2 ) cout << "Missing ; or :" << endl; if ( e == 3 ) cout << "Unmatched )" << endl; if ( e == 4 ) cout << "Division by 0" << endl; if ( e == 5 ) cout << "Index error" << endl; if ( e == 6 ) cout << "Unsupported substitution rule" << endl; if ( e == 7 ) cout << "Insufficient available indices" << endl; } catch (bad_alloc&) { cout << "Error allocating memory." << endl; } catch (exception& e) { cout << "Standard exception: " << e.what() << endl; } return 0; } // set pos to first non-blank and return that char char fstnb(const string bufr, size_t& pos) { char c; if ( pos < bufr.length() ) c = bufr[pos]; else c = '\0'; while ( ( c != '\0' ) && ( c == ' ' ) ) { pos++; if ( pos < bufr.length() ) c = bufr[pos]; else c = '\0'; } return c; } // set pos to next char and return that char, but treat (...) as a single char char nxtc(const string bufr, size_t& pos) { char c; long n; if ( bufr.at(pos++) == '(' ) { if ( pos == bufr.length() ) throw 1; n = 1; do { c = bufr[pos++]; if ( c == '(' ) n++; if ( c == ')' ) n--; } while ( ( n > 0 ) && ( pos < bufr.length() ) ); if ( ( n > 0 ) && ( pos == bufr.length() ) ) throw 1; } if ( pos < bufr.length() ) c = bufr[pos]; else c = '\0'; return c; } // set pos to next non-blank, and return that char, but treat (...) as a single char char nxtnb(const string bufr, size_t& pos) { char c; c = nxtc(bufr, pos); return fstnb(bufr, pos); } // set pos to next ( or + or - or ) or ; or : and return that char char aftrfctr(const string bufr, size_t& pos) { char c; string tststr = "(+-);:"; do { pos++; if ( pos < bufr.length() ) c = bufr[pos]; else c = '\0'; } while ( ( c != '\0' ) && ( tststr.find(c) == string::npos ) ); if ( c == '\0' ) throw 2; return c; } // set pos to next + or - or ) or ; or : that is not in parentheses, and return that char char aftrtrm(const string bufr, size_t& pos) { char c; string tststr = "+-);:"; do c = nxtnb(bufr, pos); while( ( pos < bufr.length() ) && ( tststr.find(c) == string::npos ) ); if ( pos == bufr.length() ) throw 2; return c; } // replace consecutive blanks by a single blank and return 1 for change, 0 for no change int rmvxtrblnk(string& bufr) { char c; size_t pos1 = 0; int cnrmvbl = 0, chng = 0; while ( pos1 < bufr.length() ) { c = bufr[pos1]; if ( ( c == ' ' ) && ( cnrmvbl == 1 ) ) { bufr.erase(pos1, 1); chng = 1; continue; } if ( c == ' ' ) cnrmvbl = 1; else cnrmvbl = 0; pos1++; } return chng; } // replace - - by + and return 1 for change, 0 for no change int rplcmmp(string& bufr, size_t pos = 0) { char c; size_t pos0, pos1 = pos; int lstwsm = 0, chng = 0; while ( pos1 < bufr.length() ) { c = fstnb(bufr, pos1); if ( c == '\0' ) break; if ( ( c == '-' ) && ( lstwsm == 1 ) ) { bufr.replace(pos0, pos1 + 1 - pos0, "+"); pos1 = pos0 + 1; lstwsm = 0; chng = 1; continue; } if ( c == '-' ) { pos0 = pos1; lstwsm = 1; } else lstwsm = 0; pos1++; } return chng; } // remove unnecessary + signs and return 1 for change, 0 for no change int rmvxtrpls(string& bufr, size_t pos = 0) { char c; size_t pos0, pos1 = pos; int cnrmvpls = 1, rmv1stpls = 0, chng = 0; while ( pos1 < bufr.length() ) { c = fstnb(bufr, pos1); if ( cnrmvpls == 1) { if ( c == '\0' ) throw 2; if ( c == '+' ) { bufr.erase(pos1, 1); chng = 1; continue; } } cnrmvpls = 0; if ( pos1 == bufr.length() ) break; if ( ( c == '-' ) && ( rmv1stpls == 1 ) ) { bufr.erase(pos0, 1); chng = 1; pos1--; } rmv1stpls = 0; if ( c == '+' ) { pos0 = pos1; rmv1stpls = 1; } if ( ( c == '+' ) || ( c == '-' ) || ( c == '(' ) ) cnrmvpls = 1; pos1++; } return chng; } // tidy signs and blanks void tdysgnblnk(string& bufr) { int chng = 0; do { chng = rplcmmp(bufr); chng = rmvxtrpls(bufr); } while ( chng != 0 ); chng = rmvxtrblnk(bufr); } // disribute void dstrib(string& bufr) { char c; size_t pos1 = 0, pos2, pos3; string fctr; clctnmfc(bufr); while ( pos1 < bufr.length() ) // at start of bufr or immediately after a + { c = fstnb(bufr, pos1); if ( c == '\0' ) throw 2; if ( ( c == ';' ) || ( c == ':' ) ) break; if ( c != '(' ) { pos2 = pos1; // term either has no parentheses or has a left factor c = aftrfctr(bufr, pos2); if ( c == '(' ) { fctr.assign(bufr, pos1, pos2 - pos1); // term has a left factor if ( fctr[0] != ' ' ) fctr.insert(0, " "); if ( fctr[fctr.length() - 1] != ' ' ) fctr += ' '; bufr.erase(pos1, pos2 + 1 - pos1); // pos1 is now where ( was pos2 = pos1; c = fstnb(bufr, pos2); if ( ( c == '\0' ) || ( c == ';' ) || ( c == ':' ) ) throw 1; if ( c == ')' ) throw 0; if ( c == '-' ) pos2++; bufr.insert(pos2, fctr); do { c = fstnb(bufr, pos2); c = aftrtrm(bufr, pos2); if ( ( c == ';' ) || ( c == ':' ) ) throw 1; pos2++; if ( c == ')' ) break; if ( pos2 == bufr.length() ) throw 1; bufr.insert(pos2, fctr); } while ( c != ')' ); if ( pos2 == bufr.length() ) throw 2; // pos2 is now first after ) } else { // term has no parentheses if ( c == ')' ) throw 3; if ( ( c == ';' ) || ( c == ':' ) ) break; pos1 = pos2; if ( c == '-' ) bufr.insert(pos1, "+"); pos1++; if ( pos1 == bufr.length() ) throw 2; continue; } } else { // term has parentheses but no left factor pos2 = pos1; c = nxtc(bufr, pos2); bufr.erase(pos1, 1); pos2--; // pos2 is now first after ) } pos3 = pos2; // find out if there is a right factor c = fstnb(bufr, pos3); if ( c == '\0' ) throw 2; if ( c == ')' ) throw 3; if ( ( c != '+' ) && ( c != '-' ) && ( c != ';' ) && ( c != ':' ) ) { c = aftrtrm(bufr, pos3); // there is a right factor fctr.assign(bufr, pos2, pos3 - pos2); if ( fctr[0] != ' ' ) fctr.insert(0, " "); if ( fctr[fctr.length() - 1] != ' ' ) fctr += ' '; bufr.erase(pos2, pos3 - pos2); rplcmmp(bufr, pos1); rmvxtrpls(bufr, pos1); c = fstnb(bufr, pos1); do { c = aftrtrm(bufr, pos1); bufr.insert(pos1, fctr); pos1 += fctr.length(); pos1++; } while ( c != ')' ); } else pos1 = pos2; // there is no right factor pos1--; bufr.erase(pos1, 1); // erase the ) c = fstnb(bufr, pos1); if ( c == '\0' ) throw 2; if ( c == ')' ) throw 3; if ( ( c == ';' ) || ( c == ':' ) ) break; if ( c == '-' ) bufr.insert(pos1, "+"); // c must be + or - pos1++; if ( pos1 == bufr.length() ) throw 2; } clctnmfc(bufr); } // add two numeric characters chpr chdd(char a, char b) { int A = a - 0x30, B = b - 0x30; chpr P; A += B; P.cr = char(A / 10) + 0x30; P.rs = char(A % 10) + 0x30; return P; } // multiply two numeric characters chpr chml(char a, char b) { int A = a - 0x30, B = b - 0x30; chpr P; A *= B; P.cr = char(A / 10) + 0x30; P.rs = char(A % 10) + 0x30; return P; } // subtract a numeric character b from a numeric character a chpr chsb(char a, char b) { int A = a - 0x30, B = b - 0x30; chpr P; if ( A < B ) A += 10; P.cr = char(A / 10) + 0x30; A -= B; P.rs = char(A % 10) + 0x30; return P; } // remove leading '0' characters from a string string rlz(const string a) { string s = a; int n = 1; while ( ( s.length() > 0 ) && ( n > 0 ) ) { if ( s[0] == '0' ) s.erase(0, 1); else n = 0; } return s; } // add a numeric character to the nth from last digit of an unsigned string integer string strchdd(const string a, char b, long n) { char c = b; string s = rlz(a); long m = a.length() - 1 - n; chpr P; while ( ( m >= 0 ) && ( c > '0' ) ) { P = chdd(s[m], c); s.replace(m, 1, 1, P.rs); m--; c = P.cr; } while ( ( m < -1 ) && ( c > '0' ) ) { s.insert(0, 1, '0'); m++; } if ( ( m = -1 ) && ( c > '0' ) ) s.insert(0, 1, c); return rlz(s); } // multiply an unsigned string integer by a numeric character and append n 0's string strchml(const string a, char b, long n) { string s = ""; size_t m = 0; chpr P; while ( m < a.length() ) { P = chml(a[a.length() -1 - m], b); s = strchdd(s, P.rs, m++); s = strchdd(s, P.cr, m); } s.append(n, '0'); return rlz(s); } // subtract a numeric character from the nth from last digit of an unsigned string integer string strchsb(const string a, char b, long n) { char c = b; string s = rlz(a); long m = a.length() - 1 - n; chpr P; while ( ( m >= 0 ) && ( c > '0' ) ) { P = chsb(s[m], c); s.replace(m, 1, 1, P.rs); m--; c = P.cr; } return rlz(s); //the returned value is only correct when the correct result is non-negative } // long division of an unsigned string integer a by an unsigned string integer b != "" strpr strlngdv(const string a, const string b) { string dv = "", rm = rlz(a), B = rlz(b), mB; long n = rm.length() - B.length(), m; strpr P; if ( B == "" ) throw 4; if ( n > 0 ) B.append(n,'0'); if ( ( strcm(a, B) < 0 ) && ( n > 0 ) ) { B.erase(B.length() - 1, 1); n--; } while ( n >= 0 ) { m = 9; mB = strchml(B, '9', 0); while ( strcm(rm, mB) < 0 ) { mB = strsb(mB, B); m--; } rm = strsb(rm, mB); if ( ( dv != "" ) || ( m != 0 ) ) dv += ( char(m) + 0x30 ); if ( n > 0 ) B.erase(B.length() - 1, 1); n--; } P.dv = rlz(dv); P.rm = rlz(rm); return P; } // compare two unsigned string integers and return 1, 0, -1 for a > b, a = b, a < b int strcm(const string a, const string b) { string A = rlz(a), B = rlz(b); int r = 0; size_t n = 0; if ( A.length() > B.length() ) r = 1; if ( A.length() < B.length() ) r = -1; if ( A.length() == B.length() ) { while ( n < A.length() ) { if ( A[n] > B[n] ) { r = 1; break; } if ( A[n] < B[n] ) { r = -1; break; } n++; } } return r; } // add two unsigned string integers string strdd(const string a, const string b) { string s = rlz(a); size_t n = 0; while ( n < b.length() ) { s = strchdd(s, b[b.length() - 1 - n], n); n++; } return rlz(s); } // multiply two unsigned string integers string strml(const string a, const string b) { string s = ""; size_t n = 0; while ( n < b.length() ) { s = strdd(s, strchml(a, b[b.length() - 1 - n], n)); n++; } return rlz(s); } // subtract an unsigned string integer b from an unsigned string integer a string strsb(const string a, const string b) { string s = rlz(a); size_t n = 0; while ( n < b.length() ) { s = strchsb(s, b[b.length() - 1 - n], n); n++; } return rlz(s); //the returned value is only correct when the correct result is non-negative } // divide an unsigned string integer a by an unsigned string integer b != "" string strdv(const string a, const string b) { return strlngdv(a, b).dv; } // remainder on dividing an unsigned string integer a by an unsigned string integer b != "" string strdr(const string a, const string b) { return strlngdv(a, b).rm; } // calculate the gcd of two unsigned string integers != "" string gcd(const string a, const string b) { string A = rlz(a), B = rlz(b), c; if ( strcm(A, B) < 0 ) { c = A; A = B; B = c; } do { c = strdr(A, B); A = B; B = c; } while (c != ""); return rlz(A); } // return 1 if a string is an unsigned rational number, and 0 otherwise int isrt(const string a) { char c; size_t n = 0; int f = 1, p = 0; while ( n < a.length() ) { c = a[n++]; if ( ( ( c < '0' ) || ( c > '9' ) ) && ( c != '/' ) ) f = 0; if ( ( c == '/' ) && ( p == 1 ) ) f = 0; if ( c == '/' ) p = 1; } return f; } // extract the numerator and denominator of an unsigned rational to dv and rm of a string pair strpr rt2nd(const string a) { char c; size_t n = 0; string num = "", dnm = "1"; strpr P; while ( n < a.length() ) { c = a[n]; if ( c == '/' ) break; n++; } if ( n > 0 ) num.assign(a, 0, n); if ( n == ( a.length() - 1 ) ) throw 4; if ( n < ( a.length() - 1 ) ) dnm.assign(a, n + 1, a.length() - 1 - n); P.dv = rlz(num); P.rm = rlz(dnm); if ( P.rm == "" ) throw 4; return P; } // reduce an unsigned rational number to its lowest terms string rtrdc(const string a) { strpr P = rt2nd(a); string num = rlz(P.dv), dnm = rlz(P.rm), c; if ( dnm == "" ) throw 4; if ( num != "" ) { c = gcd(num, dnm); num = strdv(num, c); dnm = strdv(dnm, c); if ( dnm != "1" ) num = num + "/" + dnm; } return num; } // multiply two unsigned rational numbers string rtml(const string a, const string b) { strpr Pa = rt2nd(a), Pb = rt2nd(b); string anum = rlz(Pa.dv), adnm = rlz(Pa.rm), bnum = rlz(Pb.dv), bdnm = rlz(Pb.rm); return rtrdc(strml(anum, bnum) + "/" + strml(adnm, bdnm)); } // set pos to next char and return that char, but treat (...) and {...} as a single char char nxt2(const string bufr, size_t& pos) { char c = bufr.at(pos++); long n; if ( ( c == '(' ) || ( c == '{' ) ) { if ( pos == bufr.length() ) throw 1; n = 1; do { c = bufr[pos++]; if ( ( c == '(' ) || ( c == '{' ) ) n++; if ( ( c == ')' ) || ( c == '}' ) ) n--; } while ( ( n > 0 ) && ( pos < bufr.length() ) ); if ( ( n > 0 ) && ( pos == bufr.length() ) ) throw 1; } if ( pos < bufr.length() ) c = bufr[pos]; else c = '\0'; return c; } // set pos to first char after small factor and return that char char aftrfct2(const string bufr, size_t& pos) { char c; int f = 1; do { c = nxt2(bufr, pos); if ( ( bufr[pos - 1] == ')' ) || ( bufr[pos - 1] == '}' ) ) f = 0; if ( ( c == ' ' ) || ( c == '(' ) || ( c == '+' ) || ( c == '-' ) ) f = 0; if ( ( c == ';' ) || ( c == ':' ) || ( c == '\0' ) ) f = 0; } while ( f == 1 ); return c; } // collect numerical factors to the start of each term, and run pdwthblnks and tdysgnblnk void clctnmfc(string& bufr) { char c; size_t pos1 = 0, pos2, pos3; string nmcf, fctr; pdwthblnks(bufr); tdysgnblnk(bufr); if ( bufr[pos1] == '-' ) pos1++; while ( pos1 < bufr.length() ) // at start of bufr or immediately after a + or - { nmcf = "1"; pos2 = pos1; do { c = fstnb(bufr, pos2); if ( ( c == '+' ) || ( c == '-' ) ) break; if ( ( c == ';' ) || ( c == ':' ) || ( c == '\0' ) ) break; pos3 = pos2; c = aftrfct2(bufr, pos3); if ( ( bufr[pos3 - 1] != ')' ) && ( bufr[pos3 - 1] != '}' ) ) { fctr.assign(bufr, pos2, pos3 - pos2); if ( isrt(fctr) == 1 ) { nmcf = rtml(nmcf, fctr); bufr.erase(pos2, pos3 - pos2); pos3 = pos2; } } pos2 = pos3; if ( ( c == '+' ) || ( c == '-' ) ) break; if ( ( c == ';' ) || ( c == ':' ) || ( c == '\0' ) ) break; } while ( 1 ); if ( nmcf == "" ) { if ( pos1 > 0 ) pos1--; bufr.erase(pos1, pos2 - pos1); pos2 = pos1; } if ( ( nmcf != "1" ) && ( nmcf != "" ) ) { nmcf.insert(0, " "); nmcf += ' '; bufr.insert(pos1, nmcf); pos2 += nmcf.length(); } pos1 = pos2; if ( ( c == ';' ) || ( c == ':' ) || ( c == '\0' ) ) break; pos1++; } pdwthblnks(bufr); tdysgnblnk(bufr); } // find and replace all occurrences of a[] by b[] in bufr void fndrplc(string& bufr, const char* a, const char* b) { size_t pos = 0; string astr = a, bstr = b; do { pos = bufr.find(astr, pos); if ( pos == string::npos ) break; bufr.replace(pos, astr.length(), bstr); pos += bstr.length(); } while ( 1 ); } // prepare an Indices property command for appending to ndcs void ndcprp(string& bufr) { size_t pos; string prns; fndrplc(bufr, " ", ""); if ( bufr.find("::Indices(") == string::npos ) bufr.replace(bufr.find("::Indices"), 9, "::Indices()"); fndrplc(bufr, "::Indices", ""); fndrplc(bufr, "{", ","); fndrplc(bufr, "}", ","); pos = bufr.find("("); prns.assign(bufr, pos, bufr.length() - pos); bufr.erase(pos); prns.erase(prns.length() - 1); fndrplc(prns, ",", "."); bufr.insert(0, prns); } // prepare an Integer property command for appending to ntgr void ntgprp(string& bufr) { fndrplc(bufr, " ", ""); fndrplc(bufr, "::Integer", ""); fndrplc(bufr, "{", ","); fndrplc(bufr, "}", ","); bufr.erase(bufr.length() - 1); } // prepare a Coefficient property command for appending to cfnt void cfnprp(string& bufr) { fndrplc(bufr, " ", ""); fndrplc(bufr, "::Coefficients.", ""); fndrplc(bufr, "{#}", ""); fndrplc(bufr, "{", ""); fndrplc(bufr, "}", ","); } // replace underlines after Coefficients by 0x1f void cfndrlnrp(string& bufr, const string cfnt) { size_t cfps1 = 0, cfps2; string srchcf, rplccf; while ( cfps1 < cfnt.length() ) { cfps2 = cfnt.find(',', cfps1); if ( ( cfps2 != string::npos ) && ( cfps2 > cfps1 ) ) { srchcf.assign(cfnt, cfps1, cfps2 - cfps1); srchcf.insert(0, " "); rplccf = srchcf; srchcf += '_'; rplccf += 0x1f; fndrplc(bufr, srchcf.c_str(), rplccf.c_str()); } cfps1 = cfps2 + 1; } } // pad with blanks at start and before and after + - ( ) } and before ; : and after { and nms void pdwthblnks(string& bufr) { char c; size_t pos = 0; bool nm; bufr.insert(0, " "); fndrplc(bufr, "+", " + "); fndrplc(bufr, "-", " - "); fndrplc(bufr, "(", " ( "); fndrplc(bufr, ")", " ) "); fndrplc(bufr, "}", " } "); fndrplc(bufr, "{", "{ "); fndrplc(bufr, ";", " ;"); fndrplc(bufr, ":", " :"); while ( pos < bufr.length() ) { do { c = bufr[pos]; if ( c == ' ' ) pos++; } while ( ( c == ' ' ) && ( pos < bufr.length() ) ); if ( pos < bufr.length() ) { nm = false; if ( ( ( c >= '0' ) && ( c <= '9' ) ) || ( c == '/' ) ) nm = true; do { c = bufr[pos]; if ( nm && ( ( c < '0' ) || ( c > '9' ) ) && ( c != '/' ) && ( c != ' ' ) ) { bufr.insert(pos, " "); c = ' '; } pos++; } while ( ( c != ' ' ) && ( pos < bufr.length() ) ); } } } // return a copy of bufr prepared for cout string prpfrct(const string bufr) { string bfcp = bufr, cfndrln = ""; cfndrln += 0x1f; if ( bfcp[0] == ' ' ) bfcp.erase(0, 1); fndrplc(bfcp, "( ", "("); fndrplc(bfcp, " )", ")"); fndrplc(bfcp, "{ ", "{"); fndrplc(bfcp, " }", "}"); fndrplc(bfcp, " ;", ";"); fndrplc(bfcp, " :", ":"); fndrplc(bfcp, cfndrln.c_str(), "_"); if ( bfcp == ";" ) bfcp = "0;"; return bfcp; } // return next index, set pos1 to its start, pos2 to its first after, set nbrcs if in braces string nxtndx(const string bufr, size_t& pos1, size_t& pos2, bool& nbrcs) { char c; string ndx = "", ntvld = " (+-)},;:#"; ntvld += 0x1f; if ( !nbrcs ) { if ( pos1 < bufr.length() ) ndx = ntnbrcsnxtndx(bufr, pos1, pos2, nbrcs); else pos1 = string::npos; } else { if ( pos1 >= bufr.length() ) throw 5; do { c = bufr[pos1]; if ( c == ' ' ) pos1++; } while ( ( c == ' ' ) && ( pos1 < bufr.length() ) ); if ( pos1 >= bufr.length() ) throw 5; if ( c != '}' ) { if ( ntvld.find(c) != string::npos ) throw 5; pos2 = bufr.find(' ', pos1); ndx.assign(bufr, pos1, pos2 - pos1); } else { pos1++; nbrcs = false; if ( pos1 < bufr.length() ) ndx = ntnbrcsnxtndx(bufr, pos1, pos2, nbrcs); else pos1 = string::npos; } } return ndx; } // return as for nxtndx, but call only if not in braces at start string ntnbrcsnxtndx(const string bufr, size_t& pos1, size_t& pos2, bool& nbrcs) { char c; string ndx = "", ntvld = " (+-)},;:#"; ntvld += 0x1f; nbrcs = false; pos1 = bufr.find('_', pos1); if ( pos1 != string::npos ) { pos1++; if ( pos1 < bufr.length() ) { c = bufr[pos1]; if ( ntvld.find(c) != string::npos ) throw 5; if ( c == '{' ) { pos1++; if ( pos1 < bufr.length() ) { do { c = bufr[pos1]; if ( c == ' ' ) pos1++; } while ( ( c == ' ' ) && ( pos1 < bufr.length() ) ); if ( pos1 >= bufr.length() ) throw 5; if ( ntvld.find(c) != string::npos ) throw 5; pos2 = bufr.find(' ', pos1); ndx.assign(bufr, pos1, pos2 - pos1); nbrcs = true; } else throw 5; } else { pos2 = bufr.find(' ', pos1); ndx.assign(bufr, pos1, pos2 - pos1); } } else throw 5; } return ndx; } // form comma surrounded list of all distinct indices from pos1 to immediately before pos2 string ndxlst(const string bufr, size_t pos1, size_t pos2) { bool nbrcs = false; size_t ps1 = pos1, ps2; string ndx, ndlst = ","; // ndlst will have initial , and final , and ,'s between inds while ( ps1 < pos2 ) { ndx = nxtndx(bufr, ps1, ps2, nbrcs); if ( ( ps1 == string::npos ) || ( ps1 >= pos2 ) ) break; ndx.insert(0, ","); ndx += ','; if ( ndlst.find(ndx) == string::npos ) { ndx.erase(0, 1); ndlst += ndx; } ps1 = ps2; } return ndlst; } // return standardized list of indices from same lists in ndcs as the indices in tmndlst string sdndlst(const string tmndlst, const string ndcs) { string ndcp = ndcs; return rpndlst(tmndlst, ndcp); } // return replacemnt list for tmndlst using earliest inds in ndcp with initial , rathr than ; string rpndlst(const string tmndlst, string& ndcp) { size_t tmps1 = 0, tmps2, ndps1, ndps2; string nd2cp, ndx, ndhsh, rplst = ","; while ( tmps1 < ( tmndlst.length() - 1 ) ) // tmndlst has both initial , and final , { tmps2 = tmndlst.find(',', tmps1 + 1); ndx.assign(tmndlst, tmps1, tmps2 + 1 - tmps1); // ndx gets both initial , and final , tmps1 = tmps2; ndhsh = ndendint(ndx); // prepare ndhsh if ndx ends with an integer nd2cp = ndcp; fndrplc(nd2cp, ";", ","); // indices appended to rplst have inital , rpl by ; in ndcp ndps1 = string::npos; if ( ndhsh != "" ) ndps1 = nd2cp.find(ndhsh); if ( ndps1 == string::npos ) ndps1 = nd2cp.find(ndx); if ( ndps1 != string::npos ) { // typical ndcs might be (),a,b,(),A,B#,(),\mu,\nu, ndps2 = ndps1 = ndcp.rfind(')', ndps1); ndps1 = ndcp.find(',', ndps1); if ( ndps1 == string::npos ) throw 7; tmps2 = ndcp.rfind(')', ndps1); if ( ndps2 < tmps2 ) throw 7; ndps2 = nd2cp.find(',', ndps1 + 1); tmps2 = ndcp.find('#', ndps1); if ( tmps2 == string::npos ) tmps2 = ndps2 + 1; ndx.assign(nd2cp, ndps1, ndps2 + 1 - ndps1 ); if ( tmps2 < ndps2 ) { if ( ( tmps2 + 1 ) == ndps2 ) ndx.insert(ndps2 - ndps1, "0"); ndx.erase(tmps2 - ndps1, 1); ndhsh.assign(ndcp, tmps2 + 1, ndps2 - tmps2 - 1); ndhsh = strchdd(ndhsh, '1', 0); ndcp.replace(tmps2 + 1, ndps2 - tmps2 - 1, ndhsh); } else ndcp.replace(ndps1, 1, ";"); } ndx.erase(0, 1); rplst += ndx; } return rplst; } // return ndcp prepared from ndcs with , to ; or large enough int after # for inds in trmlst string prpndcp(const string trmlst, const string ndcs) { size_t tmps1 = 0, tmps2, ndps1, ndps2; string ndcp = ndcs, nd2cp, ndx, ndhsh1, ndhsh2; while ( tmps1 < ( trmlst.length() - 1 ) ) // trmlst has both initial , and final , { tmps2 = trmlst.find(',', tmps1 + 1); ndx.assign(trmlst, tmps1, tmps2 + 1 - tmps1); // ndx gets both initial , and final , tmps1 = tmps2; ndhsh1 = ndendint(ndx); // prepare ndhsh1 if ndx ends with an integer nd2cp = ndcp; fndrplc(nd2cp, ";", ","); // indices earlier in trmlst have inital , rpl by ; in ndcp ndps1 = string::npos; if ( ndhsh1 != "" ) ndps1 = nd2cp.find(ndhsh1); if ( ndps1 == string::npos ) ndps1 = nd2cp.find(ndx); if ( ndps1 != string::npos ) { ndps2 = ndcp.find(',', ndps1 + 1); tmps2 = ndcp.find('#', ndps1); if ( tmps2 == string::npos ) tmps2 = ndps2 + 1; if ( tmps2 < ndps2 ) { ndps1 = ndhsh1.length() - 1; ndhsh1.assign(ndx, ndps1, ndx.length() - ndps1 - 1); ndhsh2.assign(ndcp, tmps2 + 1, ndps2 - tmps2 - 1); if ( strcm(ndhsh1, ndhsh2) < 0 ) ndhsh1 = ndhsh2; ndhsh1 = strchdd(ndhsh1, '1', 0); ndcp.replace(tmps2 + 1, ndps2 - tmps2 - 1, ndhsh1); } else ndcp.replace(ndps1, 1, ";"); } } return ndcp; } // find out if ndx ends with an integer, and if yes, return ndhsh as ndx with int -> # string ndendint(const string ndx) { char c; size_t pos = ndx.length() - 2; // ndx has both initial , and final , string ndhsh = ""; do { c = ndx[pos]; if ( ( c >= '0' ) && ( c <= '9' ) ) pos--; } while ( ( c >= '0' ) && ( c <= '9' ) ); if ( ( pos < ( ndx.length() - 2 ) ) && ( pos > 0 ) ) { pos++; do { c = ndx[pos]; if ( c == '0' ) pos++; } while ( c == '0' ); if ( pos == ( ndx.length() - 1 ) ) pos--; ndhsh.assign(ndx, 0, pos ); ndhsh += '#'; } return ndhsh; } // replace all indices in bufr, from pos1 to immediately before pos2, by standard indices void sdndx(string& bufr, size_t pos1, size_t& pos2, const string ndcs) { string ndlst = ndxlst(bufr, pos1, pos2); string sdlst = sdndlst(ndlst, ndcs); rpndx(bufr, pos1, pos2, ndlst, sdlst); } // replace all indices in bufr, from pos1 to immediately before pos2, by indices from rplst void rpndx(string& bufr, size_t pos1, size_t& pos2, const string ndlst, const string rplst) { bool nbrcs = false; size_t ps1 = pos1, ps2; string ndx; while ( ps1 < pos2 ) { ndx = nxtndx(bufr, ps1, ps2, nbrcs); if ( ( ps1 == string::npos ) || ( ps1 >= pos2 ) ) break; ndx = mpnd2nd(ndlst, rplst, ndx); bufr.replace(ps1, ps2 - ps1, ndx); pos2 += ( ndx.length() - (ps2 - ps1) ); ps1 += ndx.length(); } } // find ndx in comma-surrounded list alst and ret elmnt at same pos in comma-srndd list blst string mpnd2nd(const string alst, const string blst, const string ndx) { size_t aps0, aps1, nda, bps1, bps2, ndb; string ndcp = ndx; fndrplc(ndcp, ",", ""); ndcp.insert(0, ","); ndcp += ','; aps1 = alst.find(ndcp); aps0 = nda = 0; while ( aps0 < aps1 ) { aps0 = alst.find(',', aps0 + 1); nda++; } bps1 = ndb = 0; while ( ndb < nda ) { bps1 = blst.find(',', bps1 + 1); ndb++; } bps2 = blst.find(',', bps1 + 1); ndcp.assign(blst, bps1 + 1, bps2 - bps1 - 1); return ndcp; } // replace all indices in bufr by corresponding standard indices, treating bufr as one block void sdndbf(string& bufr, const string ndcs) { size_t pos2; clctnmfc(bufr); pos2 = bufr.length(); sdndx(bufr, 0, pos2, ndcs); snglndbrcs(bufr); clctnmfc(bufr); } // replace all indices like _ab by _{ ab } void snglndbrcs(string& bufr) { size_t ps = 0; while ( ps < bufr.length() ) { ps = bufr.find('_', ps); if ( ps != string::npos ) { ps++; if ( ps >= bufr.length() ) throw 2; if ( bufr[ps] != '{' ) { bufr.insert(ps, "{ "); ps += 2; ps = bufr.find(' ', ps); if ( ps >= bufr.length() ) throw 2; bufr.insert(ps, " }"); } } else ps = bufr.length(); } } // replace all indices in bufr by standard indices term by term, valid if no free indices void sdndtmbtm(string& bufr, const string ndcs) { char c; size_t pos1 = 0, pos2; clctnmfc(bufr); c = fstnb(bufr, pos1); while ( pos1 < bufr.length() ) { pos2 = pos1; c = aftrtrm(bufr, pos2); sdndx(bufr, pos1, pos2, ndcs); pos1 = pos2 + 1; } clctnmfc(bufr); } // return true if bufr is a single non-numerical factor like A_{b c d} and false otherwise bool tstsnglfctr(const string bufr) { bool tst = true; string bfcp = bufr + ' '; size_t pos = bfcp.find_first_of("()+-;:#"); if ( pos != string::npos ) throw 6; clctnmfc(bfcp); pos = 0; sbsaftrfctr(bfcp, pos); if ( fstnb(bfcp, pos) != '\0' ) tst = false; return tst; } // return true if bufr, which gave false with tstsnglfctr, is two non-numerical factors bool tstdblfctr(const string bufr) { bool tst = true; string bfcp = bufr + ' '; size_t pos = 0; clctnmfc(bfcp); sbsaftrfctr(bfcp, pos); sbsaftrfctr(bfcp, pos); if ( fstnb(bfcp, pos) != '\0' ) tst = false; return tst; } // send pos to after next factor of bfcp, which has been prepared from substitution lhs void sbsaftrfctr(const string bfcp, size_t& pos) { char c = fstnb(bfcp, pos); string ntfstnb = "{}_/0123456789\0"; if ( ntfstnb.find(c) != string::npos ) throw 6; pos = bfcp.find_first_of(" {", pos); if ( bfcp[pos] == '{' ) { pos = bfcp.find('}', pos); if ( pos == string::npos ) throw 1; pos++; } } // return comma srrndd list that is setwise a outside b, where a and b are comma srrndd lists string stwsouts(const string a, const string b) { size_t ps1 = 0, ps2; string c = ",", ndx; while ( ps1 < a.length() - 1 ) { ps2 = a.find(',', ps1 + 1); ndx.assign(a, ps1, ps2 + 1 - ps1); // ndx gets both initial and final , ps1 = ps2; ps2 = b.find(ndx); if ( ps2 == string::npos ) { ndx.erase(0,1); c += ndx; } } return c; } // return rplrhs prepared from images in mchlst and rplrnl of mutually disjoint lhslst rnllst string prprplrhs(const string rhslst, const string lhslst, const string mchlst, const string rnllst, const string rplrnl) { size_t ps1 = 0, ps2; string rplrhs = ",", ndx; while ( ps1 < rhslst.length() - 1 ) { ps2 = rhslst.find(',', ps1 + 1); ndx.assign(rhslst, ps1, ps2 + 1 - ps1); // ndx gets both initial , and final , ps1 = ps2; if ( lhslst.find(ndx) != string::npos ) ndx = mpnd2nd(lhslst, mchlst, ndx); else ndx = mpnd2nd(rnllst, rplrnl, ndx); ndx += ','; // mpnd2nd does not put commas around the returned index rplrhs += ndx; } return rplrhs; } // apply the substitution specified in cmnd to expr void sbsttt(const string cmnd, string& bufr, const string ndcs) { char c; bool flg = false; size_t ps1, ps2, ps3, tmps1 = 0, tmps2; string lhscp, rhscp, fld1, fld2 = "", sdlhs, sdtst, lhslst, rhslst, trmlst, mchlst; string rnllst, ndcp, rplrnl, rplrhs, rhs2cp; clctnmfc(bufr); ps1 = cmnd.find(')'); if ( ps1 == string::npos ) throw 6; ps1 = cmnd.find('(', ps1); if ( ps1 == string::npos ) throw 6; ps2 = cmnd.find("->", ps1); if ( ps2 == string::npos ) throw 6; lhscp.assign(cmnd, ps1 + 1, ps2 - ps1 - 1); lhscp += ' '; clctnmfc(lhscp); ps1 = cmnd.rfind(')'); if ( ps1 < ( ps2 + 2 ) ) throw 6; rhscp.assign(cmnd, ps2 + 2, ps1 - ps2 - 2); rhscp += ' '; clctnmfc(rhscp); ps1 = 0; c = rhscp[0]; if ( ( c == '+' ) || ( c == '-' ) ) flg = true; while ( ps1 < rhscp.length() ) { c = nxtc(rhscp, ps1); if ( ( c == '+' ) || ( c == '-' ) ) flg = true; } if ( flg ) { rhscp = " ( " + rhscp; rhscp += " ) "; clctnmfc(rhscp); } flg = tstsnglfctr(lhscp); ps1 = lhscp.find_first_of(" _", 1); fld1.assign(lhscp, 0, ps1 + 1); if ( !flg ) { if ( !tstdblfctr(lhscp) ) throw 6; ps1 = 0; sbsaftrfctr(lhscp, ps1); ps2 = lhscp.find_first_of(" _", ps1 + 1); fld2.assign(lhscp, ps1, ps2 + 1 - ps1); } lhslst = ndxlst(lhscp, 0, lhscp.length()); rhslst = ndxlst(rhscp, 0, rhscp.length()); sdlhs = lhscp; sdndbf(sdlhs, ndcs); c = fstnb(bufr, tmps1); if ( c == '\0' ) throw 2; while ( ( c != ';' ) && ( c != ':' ) ) { if ( ( c != '+' ) && ( c != '-' ) ) tmps1--; tmps2 = tmps1; c = aftrtrm(bufr, tmps2); ps1 = tmps1; while ( ps1 < tmps2 ) { ps1 = bufr.find(fld1, ps1); if ( ps1 != string::npos ) { if ( ps1 < tmps2 ) { flg = false; ps2 = bufr.find_last_of("{}", ps1); if ( ps2 == string::npos ) flg = true; else if ( bufr[ps2] == '}' ) flg = true; if ( flg ) { ps2 = bufr.find_first_of(" {", ps1 + 1); if ( bufr[ps2] == '{' ) { ps2 = bufr.find('}', ps2); if ( ps2 == string::npos ) throw 1; ps2++; } if ( fld2 != "" ) { flg = false; ps3 = bufr.find_first_of(" _", ps2 + 1); if ( bufr.compare(ps2, ps3 + 1 - ps2, fld2) == 0 ) { flg = true; ps2 = bufr.find_first_of(" {", ps2 + 1); if ( bufr[ps2] == '{' ) { ps2 = bufr.find('}', ps2); if ( ps2 == string::npos ) throw 1; ps2++; } } } if ( flg ) { sdtst.assign(bufr, ps1, ps2 + 1 - ps1); sdndbf(sdtst, ndcs); if ( sdtst == sdlhs ) { trmlst = ndxlst(bufr, tmps1, tmps2); mchlst = ndxlst(bufr, ps1, ps2); rnllst = stwsouts(rhslst, lhslst); ndcp = prpndcp(trmlst, ndcs); rplrnl = rpndlst(rnllst, ndcp); rplrhs = prprplrhs(rhslst, lhslst, mchlst, rnllst, rplrnl); rhs2cp = rhscp; ps3 = rhs2cp.length(); rpndx(rhs2cp, 0, ps3, rhslst, rplrhs); bufr.replace(ps1, ps2 + 1 - ps1, rhs2cp); tmps2 += ( rhs2cp.length() - (ps2 + 1 - ps1) ); ps2 = rhs2cp.length() + ps1 - 1; } } } ps1 = ps2; } else ps1 = tmps2; } else ps1 = tmps2; } tmps1 = tmps2; } clctnmfc(bufr); }