A method for computing a large number of polynomials with c + + symbols (compilation error when the symbol table is too large)
When using the C + + symbolic computation library GiNaC for symbolic computation, because there are too many polynomials to be processed and they are defined in the. cpp/.h file, g + + compilation always fails after running for a long time; We conceive a method of reading text from the outside and parsing it into corresponding symbols to solve this problem;
Problem description
When using the C + + symbolic calculation library GiNaC for symbolic calculation, because there are too many polynomials to be processed, they are defined in the. cpp/.h file:
std::vector<GiNaC::ex> ITEMS_ZTT {t1*z664, t2*z664,...}; // There are more than 2000 monomials; std::vector<GiNaC::ex> EQUATIONS_420 {t39*z979 + t40*z979 + z749...,...}; // This has more than 2000 polynomials;
When compiling, an error will be reported due to insufficient memory (the symbol table is too large):
[hanss@Tenda cpp]$ g++ app_gauss.cpp -o app -lginac -lcln g++: internal compiler error: Segmentation fault (program cc1plus) Please submit a full bug report, with preprocessed source if appropriate. See <file:///usr/share/doc/gcc-7/README.Bugs> for instructions.
resolvent
A direct idea is that since there are too many symbols defined in the operation of "write formula", can it be defined at runtime instead of at compile time?
How can C + + dynamically declare a variable with a string?
In fact, no; Because the symbol table is generated at the beginning of program creation;
So the compromise idea is: I only create basic symbols, such as arguments:
GiNaC::symbol x1("x1"), x2("x2"), x3("x3"), x4("x4"), x5("x5"), x6("x6"), x7("x7"), x8("x8"), x9("x9");
Then store the formula to be calculated in the static. dat file, and then just read it and analyze it:
z1*c1 + z2*c2 + z3*c3 + z4*c4 + z5*c5 + z6*c6 + z7 + z8 z1*c2 + z3*c4 + z1 + z3 ...
Therefore, the required functions include file reading / symbol analysis / formula generation. The whole program is as follows:
#include <vector> #include <string> #include <iostream> #include <cstring> #include <fstream> #include <ginac/ginac.h> #include <map> // g++ formula_resolution.cpp -o hello -lginac -lcln #define MAX_LEN_LINE 200 using namespace std; std::vector<string> read_formulas(const string& FILE_NAME) { char THIS_LINE[MAX_LEN_LINE]; string FORMULA_STRING; string TMP_VAR; std::ifstream FILEIN(FILE_NAME); std::vector<string> FORMULA_STRING_SET; for (;;) { FILEIN.getline( THIS_LINE, sizeof(THIS_LINE)); if ( FILEIN.eof()){break;} std::vector<int> COEFF; for (int j = 0; j < MAX_LEN_LINE; ++j) { if ( THIS_LINE[j]=='\0'){break;} TMP_VAR = THIS_LINE[j]; FORMULA_STRING += TMP_VAR; } FORMULA_STRING_SET.push_back(FORMULA_STRING); FORMULA_STRING.clear(); } FILEIN.close(); return FORMULA_STRING_SET; } vector<string> split(const string& PROCESS_STRING, const string& DELIM) { vector<string> res; if("" == PROCESS_STRING) return res; char * strs = new char[PROCESS_STRING.length() + 1] ; strcpy(strs, PROCESS_STRING.c_str()); char * d = new char[DELIM.length() + 1]; strcpy(d, DELIM.c_str()); char *p = strtok(strs, d); while(p) { string s = p; res.push_back(s); p = strtok(NULL, d); } return res; } GiNaC::ex make_poly_from_string(const string& PROCESS_STRING,std::map<string,GiNaC::symbol> MAP_STR_SYMBOL) { std::vector<string> STR_MONOMIALS = split(PROCESS_STRING, " + "); GiNaC::ex POLYNOMIAL = 0; for (int INDEX_i = 0; INDEX_i < STR_MONOMIALS.size(); ++INDEX_i) { std::vector<string> STR_SYMBOLS = split(STR_MONOMIALS[INDEX_i], "*"); if (STR_SYMBOLS.size()==1) { POLYNOMIAL+=MAP_STR_SYMBOL[STR_SYMBOLS[0] ]; continue; } GiNaC::ex MONOMIAL = 1; for (int INDEX_j = 0; INDEX_j < STR_SYMBOLS.size(); ++INDEX_j) { MONOMIAL *= MAP_STR_SYMBOL[STR_SYMBOLS[INDEX_j] ]; } POLYNOMIAL += MONOMIAL; } return POLYNOMIAL; } std::map<string,GiNaC::symbol> construct_map(const std::vector<GiNaC::symbol>& ITEMS_X) { std::map<string,GiNaC::symbol> MAP_STR_SYMBOL; for (int INDEX_i = 0; INDEX_i < ITEMS_X.size(); ++INDEX_i) { MAP_STR_SYMBOL[ITEMS_X[INDEX_i].get_name()] = ITEMS_X[INDEX_i]; } return MAP_STR_SYMBOL; } std::vector<GiNaC::ex> ppsh_read_formulas_from_file(const string& FILE_NAME, std::map<string,GiNaC::symbol> MAP_STR_SYMBOL) { std::vector<GiNaC::ex> EQUATIONS_192; std::vector<string> FORMULA_STRING_SET = read_formulas("poly.dat"); for (int INDEX_i = 0; INDEX_i < FORMULA_STRING_SET.size(); ++INDEX_i) { EQUATIONS_192.push_back(make_poly_from_string(FORMULA_STRING_SET[INDEX_i],MAP_STR_SYMBOL)); } return EQUATIONS_192; } int main() { GiNaC::symbol x1("x1"), x2("x2"), x3("x3"), x4("x4"), x5("x5"), x6("x6"), x7("x7"), x8("x8"), x9("x9"); std::vector<GiNaC::symbol> ITEMS_X {x1, x2, x3, x4, x5, x6, x7, x8, x9}; std::map<string,GiNaC::symbol> MAP_STR_SYMBOL = construct_map(ITEMS_X); std::vector<GiNaC::ex> EQUATIONS_192 = ppsh_read_formulas_from_file("poly.dat",MAP_STR_SYMBOL); for (int i = 0; i < EQUATIONS_192.size(); ++i) { cout << EQUATIONS_192[i] <<endl; } }
For the whole project, we can refer to the symbolic calculation program of polynomials over finite fields written by our group:
https://github.com/Luomin1993/PPSH-41
Another small problem: how to compile the source code and reference it on a server without root permission
On a server without root permission, you need to compile a library (CLN) and a library GiNac that depends on CLN. Finally, you need to compile your GiNac dependent c + + program with g + +. All these can be done as follows:
[hanss@Tenda cpp]$ ./configure --prefix=$HOME/usr // Before compiling CLN [hanss@Tenda cpp]$ make // Compile CLN [hanss@Tenda cpp]$ make install // Install CLN [hanss@Tenda cpp]$ export PKG_CONFIG_PATH=$HOME/usr/lib/pkgconfig // Indicates the CLN library [hanss@Tenda cpp]$ ./configure --prefix=$HOME/usr // Before compiling GiNaC [hanss@Tenda cpp]$ make // Compile GiNaC [hanss@Tenda cpp]$ make install // Install GiNaC [hanss@Tenda cpp]$ g++ hello.cc -o hello -I$HOME/usr/include -L$HOME/usr/lib -lginac -lcln // Compile your program [hanss@Tenda cpp]$ export LD_LIBRARY_PATH=$HOME/usr/lib // Before running the program [hanss@Tenda cpp]$ ./hello // Run program