123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- #include "sysdiffeqn.h"
- #include <regex>
-
- //объявление статичных переменных
- std::vector<int> sys_diff_equation::vp_num ={};
- std::vector<int> sys_diff_equation::circ_num ={};
- state_type sys_diff_equation::circ_coord ={};
- unsigned sys_diff_equation::dim_line=2;
- std::vector<GiNaC::symbol> sys_diff_equation::var_name ={};
-
- sys_diff_equation::sys_diff_equation(sys_osn_dan &sod_): sod(&sod_)
- {
- std::string str, str_sm, dimension;
- std::stringstream _isstemp, mystreamin;
- std::vector<GiNaC::symbol> uprav_par_ex;
- // for (std::string str; std::getline(mystreamin_, str);)
- // if (!str.empty())
- // mystreamin << str << '\n';
- N=sod->get_par_diff().N;
- dt=sod->get_par_diff().dt;
- dim_line=sod->get_par_diff().dln;
- str_sm=sod->get_par_diff().str_sm;
- // mystreamin>>str_sm>>dt>>N>>dimension;
- // dim_line=dimension[0]-'0';
- // std::getline(mystreamin, str);
- // std::getline(mystreamin, str);
- x=sod->get_par_diff().x0;
- uprav_par_naz=sod->get_par_diff().up;
- // _isstemp.str(str);
- // for (double temp; _isstemp>>temp;)
- // x.push_back(temp);
-
- //чтение нач. коорд. преобразование для ginac согласно 5.15.2 Expression input
- for (unsigned i=0;i<x.size();i++)
- {
- str=str_sm + "_"+ std::to_string(i)+ "_";
- var_name.push_back(GiNaC::symbol(str));
- table[str]=var_name[i];
- }
- // var_name.push_back(GiNaC::symbol("a"));
- //table["a"]=var_name.back();//проверку на наличия сделать здесь
-
- //for (std::vector<std::string>::iterator it = uprav_par.begin(); it != uprav_par.end(); it++)
- // table[*it]=GiNaC::symbol(*it);
-
- table["xy"]=GiNaC::symbol("xy");//в функцую + проверять есть circle3
- table["xz"]=GiNaC::symbol("xz");
- table["yx"]=GiNaC::symbol("yx");
- table["yz"]=GiNaC::symbol("yz");
- table["zx"]=GiNaC::symbol("zx");
- table["zy"]=GiNaC::symbol("zy");
-
- for (unsigned i=0;i<uprav_par_naz.size();i++)
- {
- uprav_par_ex.push_back(GiNaC::symbol(uprav_par_naz[i]));
- table[uprav_par_naz[i]]=uprav_par_ex[i];
- }
-
- // GiNaC::ex cc=GiNaC::symbol("a");
- // table["a"]=cc;
-
- GiNaC::parser reader(table, true); //если есть различие между переменными в уравнениях и объявлении, то true выдает ошибку
- equations=sod->get_par_diff().eqn;
- equations_svob=sod->get_par_diff().eqn_svob;
-
- est_uprav=false; //по умолчанию считаем
- for (auto it = equations.begin(); it != equations.end(); it++)
- {
- expr_in.push_back(reader(*it));
- for (size_t j=0; j<uprav_par_ex.size(); j++)
- est_uprav=est_uprav || GiNaC::has(expr_in.back(),uprav_par_ex[j]);
- }
-
- equations.insert(equations.end(), equations_svob.begin(), equations_svob.end());
-
- for (auto it = equations_svob.begin(); it != equations_svob.end(); it++)
- {
- expr_svob.push_back(reader(*it));
- for (size_t j=0; j<uprav_par_ex.size(); j++)
- est_uprav=est_uprav || GiNaC::has(expr_svob.back(),uprav_par_ex[j]);
- }
- sod->est_upr_par(est_uprav);
-
- if (x.size()-expr_in.size() != 1 && (expr_svob.size() == 0 || expr_svob.size() % (x.size()-expr_in.size()-1) != 0))
- {
- _isstemp.str("");
- _isstemp << "Неправильное число данных. Число начальных координат " << x.size() << " число постоянных уравнений " << expr_in.size() << " число уравнений для степени свободы больше одной " << expr_svob.size();
- throw std::invalid_argument(_isstemp.str());
- }
-
- n_svob=sod->get_par_diff().nsv;
- N_var=sod->get_par_diff().nv;
- N_ex=expr_in.size(); //число уравнений
- if (!sod->get_par_diff().npp)
- det_comp();
- else
- {
- std::ifstream _cppsdu("test.cpp");
- if (_cppsdu.fail())
- throw std::invalid_argument("Файл сду cpp отсутствует");
- }
- }
-
- void sys_diff_equation::det_comp()
- {
- std::ofstream ofst{"test.cpp"}; // текстовая форма сду
-
- if (uprav_par_naz.size()>0 && !est_uprav)
- {
- ofst <<"//Не используется управляемый параметр" << std::endl;
- // _isstemp.str("");
- // _isstemp << "Не используется управляемый параметр";
- // throw std::invalid_argument(_isstemp.str());
- }
- ofst << "#include <cmath> " << std::endl;
- ofst << "#include \"virteqn.h\"" << '\n' << std::endl;
- ofst << "class funcinst : public diffeqninterface {" << std::endl << "public:" <<std::endl;
- ofst << "virtual std::vector<syseqn> funcv();" << std::endl;
- ofst << "virtual state_type get_upr_par()";
-
- // if (!est_uprav)
- // ofst << " {return {};}" << std::endl;
- //else
- ofst << ";" << std::endl;
-
- ofst << "private:" << std::endl;
-
- for (auto it = uprav_par_naz.begin(); it != uprav_par_naz.end(); it++)
- ofst << "static double "<< *it <<";" << std::endl;
- //ofst << "virtual void set_par_a(double &_a) {a=_a;}" <<std::endl;
-
- GiNaC::ex temp_1=expr_in.back();
- //bool check_t=false;
-
- //плохой код, доработать
- // for (int i=0; i<N_ex;i++)
- // if (expr_in[i].diff(var_name.back()) != 0)
- // check_t=true;
- // if (check_t) N_var++;
-
- for (int k=0; k < n_svob;k++)
- ofst << "static void func_" << k+1 << "(const state_type &, state_type &, const double);" << std::endl;
- ofst << "};" << std::endl << std::endl;
- ofst << "extern \"C\" diffeqninterface* create() {" << "return new funcinst;" << "}"<<std::endl;
-
- ofst << "extern \"C\" void destroy(diffeqninterface *p) {" << "delete p;" << "}"<<std::endl <<std::endl;
- for (auto it = uprav_par_naz.begin(); it != uprav_par_naz.end(); it++)
- ofst << "double funcinst::"<< *it << "=0;" << std::endl;
-
- // if (est_uprav)
- // {
- ofst << "state_type funcinst::get_upr_par() {" << std::endl << "state_type _upr_par;" << std::endl;
- for (auto it = uprav_par_naz.begin(); it != uprav_par_naz.end(); it++)
- ofst << "_upr_par.push_back("<< *it << ");" << std::endl;
- ofst << "return _upr_par;" << std::endl << "}" << std::endl << std::endl;
- // }
- ofst << "std::vector<syseqn> funcinst::funcv() {" << std::endl;
- ofst << "std::vector<syseqn> temp_;" << std::endl;
- for (int k=0; k < n_svob;k++)
- ofst << "temp_.push_back(func_" << k+1 << ");" << std::endl;
- ofst << "return temp_;" << std::endl << "}" << std::endl << std::endl;
- for (int k=0; k < n_svob;k++)
- {
- if (n_svob != 1)
- expr_in.push_back(expr_svob[k]);
-
- GiNaC::lst biglst, lst_svb;
- for (int j=0; j<N_var-1;j++)
- for (int i=0; i<N_var-1;i++)
- biglst.append(expr_in[i].diff(var_name[j]));
- //столбец свободных членов со знаком "-"
- for (int i=0; i<N_var-1;i++)
- lst_svb.append(-expr_in[i].diff(var_name[N_var-1]));
- //матрица имеет N_var*N_var, но счет начинается с 0, поэтому N_var-1
- expr_in.pop_back();
- GiNaC::matrix A_mat(N_var-1, N_var-1, biglst);
- GiNaC::matrix b_mat(1, N_var-1, lst_svb), b_temp(1, N_var-1, lst_svb);
- ofst << "void funcinst::func_"<<k+1<<"(const state_type &x, state_type &f, const double t)" << std::endl;
- ofst << "{" << std::endl;
- for (int count=0; count<N_var-1; ++count)
- {
- ofst << "f[" << count << "] = (";
- //ginac нету функции менять столбец, удаление столбца для четных значений приводит к неправильному знаку
- for (int i=0; i<N_var-1;i++)
- {
- b_temp(0,i)=A_mat(count,i);
- A_mat(count,i)=b_mat(0,i);
- }
- std::stringstream prav_ch; //правая часть
- GiNaC::determinant(A_mat).print(GiNaC::print_csrc_double(prav_ch));
- ofst << vnut_pred(prav_ch).rdbuf() << ");" << std::endl;
- for (int i=0; i<N_var-1;i++)
- A_mat(count,i)=b_temp(0,i);
- }
- ofst << "f[" << N_var-1 << "] = (";
- std::stringstream prav_ch; //правая часть
- GiNaC::determinant(A_mat).print(GiNaC::print_csrc_double(prav_ch));
- ofst << vnut_pred(prav_ch).rdbuf() << ");" << std::endl << "}" << std::endl;
- }
- if (n_svob == 1)
- expr_in.push_back(temp_1);
- ofst.close();
- }
-
- ginacdata sys_diff_equation::get_ginacdata()
- {
- ginacdata A;
- A.vpnum=vp_num;
- A.cnum=circ_num;
- A.ccord=circ_coord;
- return A;
- }
-
- void sys_diff_equation::info_eqn_octave(std::stringstream &error_stream, std::stringstream &eqn_stream)
- {
- eqn_stream<<"#{\n";
- std::regex regSn(":"), regz("\\*|\\^|\\/");
-
- for (size_t i=0; i<expr_in.size(); i++)
- {
- std::stringstream strsm,strsm_;
- expr_in[i].print(GiNaC::print_dflt(strsm_));
- strsm << vnut_pred(strsm_).rdbuf();
- std::string str(strsm.str());
- const char coord_name[]="xyz";
- std::size_t pos_l = str.find('[', 0)+1;//следующий символ цифра
- std::size_t pos_r = str.find(']', 0)+1;
- while( pos_l !=std::string::npos+1)
- {
- unsigned _numb=std::stoi(str.substr(pos_l, pos_r-pos_l));
- std::string _str_r;
- _str_r=coord_name[_numb % dim_line];
- _str_r+="(:," + std::to_string(_numb/dim_line+1) + ")";
- str.replace(pos_l-2, pos_r-(pos_l-2), _str_r);//начиная с x[ т.е -2
- pos_l = str.find('[', pos_l+1)+1;
- pos_r = str.find(']', pos_r+1)+1;
- }
- str=regex_replace(str, regz, ".$&");
- eqn_stream << "eqn(:," << i+1 << ")=" << str << ";" << std::endl;
- error_stream << "error_eqn(:," << i+1 << ")=" << str << " - (" <<regex_replace(str, regSn, "1") << ");" <<std::endl;
- }
- if (uprav_par_naz.size() == 0)
- {
- eqn_stream << "#}\n";
- error_stream << "max_error=max(abs(error_eqn));\n\n";
- }
- else
- error_stream << "max_error=max(abs(error_eqn));\n#}\n\n";
- }
-
- std::stringstream &sys_diff_equation::vnut_pred(std::stringstream &prav_ch)
- {
- std::string input=prav_ch.str();
- std::regex left_s("_([[:d:]]+)"), right_s("([[:d:]]+)_");
-
- input=regex_replace(input,left_s,"[$1");
- input=regex_replace(input,right_s,"$1]");
- prav_ch.str("");
- prav_ch << input;
- return prav_ch;
- }
|