[Applied Algebra] a method for calculating a large number of polynomials with c + + symbols (compilation error when the symbol table is too large)

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

Tags: C++

Posted on Sun, 10 Oct 2021 08:52:18 -0400 by peteraub