SyFi
0.3
|
00001 // Copyright (C) 2006-2009 Kent-Andre Mardal and Simula Research Laboratory 00002 // 00003 // This file is part of SyFi. 00004 // 00005 // SyFi is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 2 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // SyFi is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with SyFi. If not, see <http://www.gnu.org/licenses/>. 00017 00018 #include "ginac_tools.h" 00019 #include "symbol_factory.h" 00020 00021 #include <ginac/ginac.h> 00022 00023 #include <iostream> 00024 #include <sstream> 00025 #include <fstream> 00026 #include <stdexcept> 00027 00028 using namespace std; 00029 using namespace GiNaC; 00030 00031 namespace SyFi 00032 { 00033 00034 GiNaC::lst cross(GiNaC::lst& v1, GiNaC::lst& v2) 00035 { 00036 GiNaC::lst ret; 00037 if ( v1.nops() != v2.nops() ) 00038 { 00039 cout <<"incompatible vectors "<<endl; 00040 cout <<"v1.nops() "<<v1.nops(); 00041 cout <<" v2.nops() "<<v2.nops()<<endl; ; 00042 return GiNaC::lst(); 00043 } 00044 ret.append( v1.op(1)*v2.op(2) - v1.op(2)*v2.op(1)); 00045 ret.append(- v1.op(0)*v2.op(2) + v1.op(2)*v2.op(0)); 00046 ret.append( v1.op(0)*v2.op(1) - v1.op(1)*v2.op(0)); 00047 return ret; 00048 } 00049 00050 GiNaC::ex inner(GiNaC::ex a, GiNaC::ex b, bool transposed) 00051 { 00052 if (GiNaC::is_a<GiNaC::matrix>(a) && GiNaC::is_a<GiNaC::matrix>(b)) 00053 { 00054 GiNaC::matrix ma = GiNaC::ex_to<GiNaC::matrix>(a); 00055 GiNaC::matrix mb = GiNaC::ex_to<GiNaC::matrix>(b); 00056 if ( !transposed ) 00057 { 00058 if (ma.cols() != mb.cols() || ma.rows() != mb.rows() ) 00059 { 00060 cout <<"Incompatible matrices "<<endl; 00061 cout <<"a.cols() "<<ma.cols()<<endl; 00062 cout <<"a.rows() "<<ma.rows()<<endl; 00063 cout <<"b.cols() "<<mb.cols()<<endl; 00064 cout <<"b.rows() "<<mb.rows()<<endl; 00065 cout <<"a="<<a<<endl; 00066 cout <<"b="<<b<<endl; 00067 throw std::runtime_error("Incompatible matrices."); 00068 } 00069 00070 GiNaC::ex ret; 00071 for (unsigned int i=0; i<ma.rows(); i++) 00072 { 00073 for (unsigned int j=0; j<ma.cols(); j++) 00074 { 00075 ret += ma(i,j)*mb(i,j); 00076 } 00077 } 00078 return ret; 00079 } 00080 else 00081 { 00082 if (ma.cols() != mb.rows() || ma.rows() != mb.cols() ) 00083 { 00084 cout <<"Incompatible matrices "<<endl; 00085 cout <<"a.cols() "<<ma.cols()<<endl; 00086 cout <<"a.rows() "<<ma.rows()<<endl; 00087 cout <<"b.cols() "<<mb.cols()<<endl; 00088 cout <<"b.rows() "<<mb.rows()<<endl; 00089 cout <<"a="<<a<<endl; 00090 cout <<"b="<<b<<endl; 00091 throw std::runtime_error("Incompatible matrices."); 00092 } 00093 00094 GiNaC::ex ret; 00095 for (unsigned int i=0; i<ma.rows(); i++) 00096 { 00097 for (unsigned int j=0; j<ma.cols(); j++) 00098 { 00099 ret += ma(i,j)*mb(j,i); 00100 } 00101 } 00102 return ret; 00103 } 00104 } 00105 else if (GiNaC::is_a<GiNaC::lst>(a) 00106 && GiNaC::is_a<GiNaC::lst>(b)) 00107 { 00108 return inner(GiNaC::ex_to<GiNaC::lst>(a), GiNaC::ex_to<GiNaC::lst>(b)); 00109 } 00110 else 00111 { 00112 return a*b; 00113 } 00114 } 00115 00116 GiNaC::ex inner(GiNaC::lst v1, GiNaC::lst v2) 00117 { 00118 GiNaC::ex ret; 00119 00120 if ( v1.nops() != v2.nops() ) 00121 { 00122 cout <<"incompatible vectors "<<endl; 00123 cout <<"v1.nops() "<<v1.nops(); 00124 cout <<" v2.nops() "<<v2.nops()<<endl; ; 00125 return 0; 00126 } 00127 for (unsigned i = 0; i <= v1.nops()-1 ; ++i) 00128 { 00129 if ( GiNaC::is_a<GiNaC::lst>(v1.op(i)) && 00130 GiNaC::is_a<GiNaC::lst>(v2.op(i)) ) 00131 { 00132 ret += inner(GiNaC::ex_to<GiNaC::lst>(v1.op(i)), 00133 GiNaC::ex_to<GiNaC::lst>(v2.op(i))); 00134 } 00135 else 00136 { 00137 ret += v1.op(i)*v2.op(i); 00138 } 00139 } 00140 return ret; 00141 } 00142 00143 GiNaC::ex inner(GiNaC::exvector& v1, GiNaC::exvector& v2) 00144 { 00145 GiNaC::ex ret; 00146 for (unsigned int i=0; i< v1.size(); i++) 00147 { 00148 ret += v1[i]*v2[i]; 00149 } 00150 return ret; 00151 } 00152 00153 GiNaC::lst matvec(GiNaC::matrix& M, GiNaC::lst& x) 00154 { 00155 GiNaC::lst ret; 00156 int nr = M.rows(); 00157 int nc = M.cols(); 00158 for (int i = 0; i < nr; i++) 00159 { 00160 GiNaC::ex tmp; 00161 for (int j = 0; j < nc; j++) 00162 { 00163 tmp = tmp + M(i,j)*(x.op(j)); 00164 } 00165 ret.append(tmp); 00166 } 00167 return ret; 00168 } 00169 00170 GiNaC::ex matvec(GiNaC::ex A, GiNaC::ex x) 00171 { 00172 ex sol; 00173 00174 if (GiNaC::is_a<GiNaC::matrix>(A) && GiNaC::is_a<GiNaC::matrix>(x)) 00175 { 00176 GiNaC::matrix AA = GiNaC::ex_to<GiNaC::matrix>(A); 00177 GiNaC::matrix xx = GiNaC::ex_to<GiNaC::matrix>(x); 00178 sol = AA.mul(xx); 00179 } 00180 else 00181 { 00182 throw std::runtime_error("Invalid argument types, need matrices"); 00183 } 00184 return sol; 00185 } 00186 00187 GiNaC::lst ex2equations(GiNaC::ex rel) 00188 { 00189 GiNaC::ex lhs = rel.lhs(); 00190 GiNaC::ex rhs = rel.rhs(); 00191 00192 GiNaC::ex l; 00193 GiNaC::ex r; 00194 00195 GiNaC::lst eqs; 00196 00197 for (int i=lhs.ldegree(x); i<=lhs.degree(x); ++i) 00198 { 00199 for (int j=lhs.ldegree(y); j<=lhs.degree(y); ++j) 00200 { 00201 for (int k=lhs.ldegree(z); k<=lhs.degree(z); ++k) 00202 { 00203 l = lhs.coeff(x,i).coeff(y, j).coeff(z,k); 00204 r = rhs.coeff(x,i).coeff(y, j).coeff(z,k); 00205 // if (! (l == 0 && r == 0 ) ) eqs.append(l == r); OLD VERSION 00206 if ( (l != 0 && (r == 0 || r == 1) ) ) eqs.append(l == r); 00207 } 00208 } 00209 } 00210 eqs.sort(); 00211 return eqs; 00212 } 00213 00214 GiNaC::lst collapse(GiNaC::lst l) 00215 { 00216 GiNaC::lst lc; 00217 GiNaC::lst::const_iterator iter1, iter2; 00218 00219 for (iter1 = l.begin(); iter1 != l.end(); ++iter1) 00220 { 00221 if (GiNaC::is_a<GiNaC::lst>(*iter1)) 00222 { 00223 for (iter2 = GiNaC::ex_to<GiNaC::lst>(*iter1).begin(); iter2 != GiNaC::ex_to<GiNaC::lst>(*iter1).end(); ++iter2) 00224 { 00225 lc.append(*iter2); 00226 } 00227 } 00228 else 00229 { 00230 lc.append(*iter1); 00231 } 00232 } 00233 lc.sort(); 00234 lc.unique(); 00235 return lc; 00236 } 00237 00238 GiNaC::matrix equations2matrix(const GiNaC::ex &eqns, const GiNaC::ex &symbols) 00239 { 00240 00241 GiNaC::matrix sys(eqns.nops(),symbols.nops()); 00242 GiNaC::matrix rhs(eqns.nops(),1); 00243 GiNaC::matrix vars(symbols.nops(),1); 00244 00245 for (size_t r=0; r<eqns.nops(); r++) 00246 { 00247 // lhs-rhs==0 00248 const GiNaC::ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); 00249 GiNaC::ex linpart = eq; 00250 for (size_t c=0; c<symbols.nops(); c++) 00251 { 00252 const GiNaC::ex co = eq.coeff(GiNaC::ex_to<GiNaC::symbol>(symbols.op(c)),1); 00253 linpart -= co*symbols.op(c); 00254 sys(r,c) = co; 00255 } 00256 linpart = linpart.expand(); 00257 rhs(r,0) = -linpart; 00258 } 00259 return sys; 00260 } 00261 00262 void matrix_from_equations(const GiNaC::ex &eqns, const GiNaC::ex &symbols, GiNaC::matrix& A, GiNaC::matrix& b) 00263 { 00264 // build matrix from equation system 00265 GiNaC::matrix sys(eqns.nops(),symbols.nops()); 00266 GiNaC::matrix rhs(eqns.nops(),1); 00267 GiNaC::matrix vars(symbols.nops(),1); 00268 00269 for (size_t r=0; r<eqns.nops(); r++) 00270 { 00271 // lhs-rhs==0 00272 const GiNaC::ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); 00273 GiNaC::ex linpart = eq; 00274 for (size_t c=0; c<symbols.nops(); c++) 00275 { 00276 const GiNaC::ex co = eq.coeff(GiNaC::ex_to<GiNaC::symbol>(symbols.op(c)),1); 00277 linpart -= co*symbols.op(c); 00278 sys(r,c) = co; 00279 } 00280 linpart = linpart.expand(); 00281 rhs(r,0) = -linpart; 00282 } 00283 A = sys; 00284 b = rhs; 00285 } 00286 00287 GiNaC::ex lst_to_matrix2(const GiNaC::lst& l) 00288 { 00289 GiNaC::lst::const_iterator itr, itc; 00290 00291 // Find number of rows and columns 00292 size_t rows = l.nops(), cols = 0; 00293 for (itr = l.begin(); itr != l.end(); ++itr) 00294 { 00295 if (!GiNaC::is_a<GiNaC::lst>(*itr)) 00296 // throw (std::invalid_argument("lst_to_matrix: argument must be a list of lists")); 00297 cols = 1; 00298 if (itr->nops() > cols) 00299 cols = itr->nops(); 00300 } 00301 // Allocate and fill matrix 00302 GiNaC::matrix &M = *new GiNaC::matrix(rows, cols); 00303 M.setflag(GiNaC::status_flags::dynallocated); 00304 00305 unsigned i; 00306 for (itr = l.begin(), i = 0; itr != l.end(); ++itr, ++i) 00307 { 00308 unsigned j; 00309 if (cols == 1) 00310 { 00311 M(i, 0) = *itr; 00312 } 00313 else 00314 { 00315 for (itc = GiNaC::ex_to<GiNaC::lst>(*itr).begin(), j = 0; itc != GiNaC::ex_to<GiNaC::lst>(*itr).end(); ++itc, ++j) 00316 M(i, j) = *itc; 00317 } 00318 } 00319 return M; 00320 } 00321 00322 GiNaC::lst matrix_to_lst2(const GiNaC::ex& m) 00323 { 00324 if (GiNaC::is_a<GiNaC::matrix>(m)) 00325 { 00326 GiNaC::matrix A = GiNaC::ex_to<GiNaC::matrix>(m); 00327 int cols = A.cols(); 00328 int rows = A.rows(); 00329 00330 GiNaC::lst ret; 00331 if ( cols == 1 ) 00332 { 00333 for (unsigned int i=0; i<=A.rows()-1; i++) 00334 { 00335 ret.append(A(i,0)); 00336 } 00337 } 00338 else if ( rows == 1 ) 00339 { 00340 for (unsigned int i=0; i<=A.cols()-1; i++) 00341 { 00342 ret.append(A(0,i)); 00343 } 00344 } 00345 else 00346 { 00347 for (unsigned int i=0; i<=A.rows()-1; i++) 00348 { 00349 GiNaC::lst rl; 00350 for (unsigned int j=0; j<=A.cols()-1; j++) 00351 { 00352 rl.append(A(i,j)); 00353 } 00354 ret.append(rl); 00355 } 00356 } 00357 return ret; 00358 } 00359 else 00360 { 00361 return GiNaC::lst(); 00362 } 00363 } 00364 00365 GiNaC::lst lst_equals(GiNaC::ex a, GiNaC::ex b) 00366 { 00367 GiNaC::lst ret; 00368 if ( (GiNaC::is_a<GiNaC::lst>(a)) && (GiNaC::is_a<GiNaC::lst>(b)) /*&& (a.nops() == b.nops())*/ ) { 00369 for (unsigned int i=0; i<= a.nops()-1; i++) 00370 { 00371 ret.append(b.op(i) == a.op(i)); 00372 } 00373 } 00374 else if ( !(GiNaC::is_a<GiNaC::lst>(a)) && !(GiNaC::is_a<GiNaC::lst>(b))) 00375 { 00376 ret.append(b == a); 00377 } 00378 else if ( !(GiNaC::is_a<GiNaC::lst>(a)) && (GiNaC::is_a<GiNaC::lst>(b))) 00379 { 00380 ret.append(b.op(0) == a); 00381 } 00382 else 00383 { 00384 throw(std::invalid_argument("Make sure that the lists a and b are comparable.")); 00385 } 00386 return ret; 00387 } 00388 00389 00390 int find(GiNaC::ex e, GiNaC::lst list) 00391 { 00392 for (unsigned int i=0; i< list.nops(); i++) 00393 { 00394 if ( e == list.op(i) ) return i; 00395 } 00396 return -1; 00397 } 00398 00399 00400 void visitor_subst_pow(GiNaC::ex e, GiNaC::exmap& map, ex_int_map& intmap, string a) 00401 { 00402 static int i=0; 00403 if (map.find(e) != map.end()) 00404 { 00405 intmap[e] = intmap[e]+1; 00406 return; 00407 } 00408 if (GiNaC::is_exactly_a<GiNaC::power>(e)) 00409 { 00410 std::ostringstream s; 00411 s <<a<<i++; 00412 map[e] = GiNaC::symbol(s.str()); 00413 intmap[e] = 0; 00414 for (unsigned int i=0; i< e.nops(); i++) 00415 { 00416 GiNaC::ex e2 = e.op(i); 00417 // cout <<"power e "<<e2<<endl; 00418 visitor_subst_pow(e2,map,intmap, a); 00419 } 00420 } 00421 else if (GiNaC::is_a<GiNaC::function>(e)) 00422 { 00423 std::ostringstream s; 00424 s <<a<<i++; 00425 map[e] = GiNaC::symbol(s.str()); 00426 intmap[e] = 0; 00427 for (unsigned int i=0; i< e.nops(); i++) 00428 { 00429 GiNaC::ex e2 = e.op(i); 00430 // cout <<"function e "<<e2<<endl; 00431 visitor_subst_pow(e2,map,intmap, a); 00432 } 00433 } 00434 else if (GiNaC::is_a<GiNaC::mul>(e)) 00435 { 00436 if (e.nops() > 4 && e.nops() < 10 ) 00437 { 00438 std::ostringstream s; 00439 s <<a<<i++; 00440 map[e] = GiNaC::symbol(s.str()); 00441 intmap[e] = 0; 00442 } 00443 00444 for (unsigned int i=0; i< e.nops(); i++) 00445 { 00446 GiNaC::ex e2 = e.op(i); 00447 visitor_subst_pow(e2,map,intmap, a); 00448 } 00449 } 00450 else if (GiNaC::is_a<GiNaC::add>(e)) 00451 { 00452 for (unsigned int i=0; i< e.nops(); i++) 00453 { 00454 GiNaC::ex e2 = e.op(i); 00455 visitor_subst_pow(e2,map,intmap,a); 00456 } 00457 } 00458 } 00459 00460 00461 void check_visitor(GiNaC::ex e, GiNaC::lst& exlist) 00462 { 00463 if (find(e, exlist) >= 0) return; 00464 00465 // cout <<"ex e "<<e<<endl; 00466 if (GiNaC::is_a<GiNaC::numeric>(e)) 00467 { 00468 } 00469 else if (GiNaC::is_a<GiNaC::add>(e) ) 00470 { 00471 // cout <<"e "<<e <<endl; 00472 // cout <<"e.nops() "<<e.nops() <<endl; 00473 if (e.nops() > 4 && e.nops() < 10 ) exlist.append(e); 00474 for (unsigned int i=0; i< e.nops(); i++) 00475 { 00476 GiNaC::ex e2 = e.op(i); 00477 // cout <<"add e "<<e2<<endl; 00478 // exlist.append(e2); 00479 check_visitor(e2,exlist); 00480 } 00481 } 00482 else if (GiNaC::is_a<GiNaC::mul>(e)) 00483 { 00484 for (unsigned int i=0; i< e.nops(); i++) 00485 { 00486 GiNaC::ex e2 = e.op(i); 00487 // cout <<"mul e "<<e2<<endl; 00488 exlist.append(e2); 00489 check_visitor(e2,exlist); 00490 } 00491 } 00492 else if (GiNaC::is_a<GiNaC::lst>(e)) 00493 { 00494 for (unsigned int i=0; i< e.nops(); i++) 00495 { 00496 GiNaC::ex e2 = e.op(i); 00497 // cout <<"GiNaC::lst e "<<e2<<endl; 00498 // exlist.append(e2); 00499 check_visitor(e2,exlist); 00500 } 00501 } 00502 else if (GiNaC::is_exactly_a<GiNaC::power>(e)) 00503 { 00504 exlist.append(e); 00505 for (unsigned int i=0; i< e.nops(); i++) 00506 { 00507 GiNaC::ex e2 = e.op(i); 00508 // cout <<"power e "<<e2<<endl; 00509 check_visitor(e2,exlist); 00510 } 00511 } 00512 else if (GiNaC::is_a<GiNaC::function>(e)) 00513 { 00514 exlist.append(e); 00515 for (unsigned int i=0; i< e.nops(); i++) 00516 { 00517 GiNaC::ex e2 = e.op(i); 00518 // cout <<"function e "<<e2<<endl; 00519 check_visitor(e2,exlist); 00520 } 00521 } 00522 00523 else 00524 { 00525 // exlist.append(e); 00526 // cout <<"atom e "<<e<<endl; 00527 } 00528 00529 exlist.sort(); 00530 exlist.unique(); 00531 } 00532 00533 00534 GiNaC::ex homogenous_pol(unsigned int order, unsigned int nsd, const string a) 00535 { 00536 using SyFi::x; 00537 using SyFi::y; 00538 using SyFi::z; 00539 00540 if ( nsd == 1) 00541 { 00542 GiNaC::symbol a0(istr(a,0)); 00543 return GiNaC::lst(a0*pow(x,order), a0, pow(x,order)); 00544 } 00545 else if ( nsd == 2 ) 00546 { 00547 GiNaC::ex variables = get_symbolic_matrix(1,order+1, a); 00548 GiNaC::lst basis; 00549 GiNaC::ex ret; 00550 for (unsigned int i=0; i<= order; i++) 00551 { 00552 basis.append(pow(x,i)*pow(y,order-i)); 00553 ret += variables.op(i)*basis.op(i); 00554 } 00555 return GiNaC::lst(ret, matrix_to_lst2(variables), basis); 00556 } 00557 else if ( nsd == 3 ) 00558 { 00559 GiNaC::lst basis; 00560 for (unsigned int i=0; i<= order; i++) 00561 { 00562 for (unsigned int j=0; j<= order; j++) 00563 { 00564 for (unsigned int k=0; k<= order; k++) 00565 { 00566 if ( i + j + k == order ) 00567 { 00568 basis.append(pow(x,i)*pow(y,j)*pow(z,k)); 00569 } 00570 } 00571 } 00572 } 00573 GiNaC::ex variables = get_symbolic_matrix(1,basis.nops(), a); 00574 GiNaC::ex ret; 00575 for (unsigned int i=0; i<basis.nops(); i++) 00576 { 00577 ret += variables.op(i)*basis.op(i); 00578 } 00579 return GiNaC::lst(ret, matrix_to_lst2(variables), basis); 00580 } 00581 throw std::runtime_error("Homogenous polynomials only implemented in 1D, 2D and 3D"); 00582 } 00583 00584 00585 GiNaC::lst homogenous_polv(unsigned int no_fields, unsigned int order, unsigned int nsd, const string a) 00586 { 00587 GiNaC::lst ret1; // contains the polynom 00588 GiNaC::lst ret2; // contains the coefficients 00589 GiNaC::lst ret3; // constains the basis functions 00590 GiNaC::lst basis_tmp; 00591 for (unsigned int i=0; i< no_fields; i++) 00592 { 00593 GiNaC::lst basis; 00594 std::ostringstream s; 00595 s <<a<<""<<i<<"_"; 00596 GiNaC::ex polspace = homogenous_pol(order, nsd, s.str()); 00597 ret1.append(polspace.op(0)); 00598 ret2.append(polspace.op(1)); 00599 basis_tmp = GiNaC::ex_to<GiNaC::lst>(polspace.op(2)); 00600 for (GiNaC::lst::const_iterator basis_iterator = basis_tmp.begin(); 00601 basis_iterator != basis_tmp.end(); ++basis_iterator) 00602 { 00603 GiNaC::lst tmp_lst; 00604 for (unsigned int d=1; d<=no_fields; d++) tmp_lst.append(0); 00605 tmp_lst.let_op(i) = (*basis_iterator); 00606 ret3.append(tmp_lst); 00607 } 00608 } 00609 return GiNaC::lst(ret1,ret2,ret3); 00610 } 00611 00612 00613 GiNaC::ex pol(unsigned int order, unsigned int nsd, const string a) 00614 { 00615 using SyFi::x; 00616 using SyFi::y; 00617 using SyFi::z; 00618 00619 GiNaC::ex ret; // ex to return 00620 int dof; // degrees of freedom 00621 GiNaC::ex A; // ex holding the coefficients a_0 .. a_dof 00622 GiNaC::lst basis; 00623 00624 if (nsd == 1) 00625 { 00626 /* 1D: 00627 * P^n = a_0 + a_1*x + .... + a_n*x^n 00628 * dof : n+1 00629 */ 00630 dof = order+1; 00631 A = get_symbolic_matrix(1,dof, a); 00632 int o=0; 00633 for (GiNaC::const_iterator i = A.begin(); i != A.end(); ++i) 00634 { 00635 ret += (*i)*pow(x,o); 00636 basis.append(pow(x,o)); 00637 o++; 00638 } 00639 } 00640 else if ( nsd == 2) 00641 { 00642 00643 /* 2D: structure of coefficients (a_i) 00644 * [ a_0 a_1 x a_3 x^2 a_6 x^3 00645 * [ a_2 y a_4 xy a_7 x^2y 00646 * [ a_5 y^2 a_8 xy^2 00647 * [ a_9 y^3 00648 */ 00649 dof = (order+1)*(order+2)/2; 00650 A = get_symbolic_matrix(1, dof , a); 00651 00652 size_t i=0; 00653 for (unsigned int o = 0; o <= order; o++) 00654 { 00655 for (unsigned int d = 0; d <= o; d++) 00656 { 00657 ret += A.op(i)*pow(y,d)*pow(x,o-d); 00658 basis.append(pow(y,d)*pow(x,o-d)); 00659 i++; 00660 } 00661 } 00662 } 00663 else if (nsd == 3) 00664 { 00665 00666 /* Similar structure as in 2D, but 00667 * structured as a tetraheder, i.e., 00668 * a_o + a_1 x + a_2 y + a_3 z 00669 * + a_4 x^2 + a_5 xy + 00670 */ 00671 dof = 0; 00672 for (unsigned int j=0; j<= order; j++) 00673 { 00674 dof += (j+1)*(j+2)/2; 00675 } 00676 A = get_symbolic_matrix(1, dof , a); 00677 00678 size_t i=0; 00679 for (unsigned int o = 0; o <= order; o++) 00680 { 00681 for (unsigned int d = 0; d <= o; d++) 00682 { 00683 for (unsigned int f = 0; f <= o; f++) 00684 { 00685 if ( int(o)-int(d)-int(f) >= 0) 00686 { 00687 ret += A.op(i)*pow(y,f)*pow(z,d)*pow(x,o-d-f); 00688 basis.append(pow(y,f)*pow(z,d)*pow(x,o-d-f)); 00689 i++; 00690 } 00691 } 00692 } 00693 } 00694 } 00695 return GiNaC::lst(ret,matrix_to_lst2(A), basis); 00696 } 00697 00698 00699 GiNaC::lst polv(unsigned int no_fields, unsigned int order, unsigned int nsd, const string a) 00700 { 00701 GiNaC::lst ret1; // contains the polynom 00702 GiNaC::lst ret2; // contains the coefficients 00703 GiNaC::lst ret3; // constains the basis functions 00704 GiNaC::lst basis_tmp; 00705 for (unsigned int i=0; i< no_fields; i++) 00706 { 00707 GiNaC::lst basis; 00708 std::ostringstream s; 00709 s <<a<<""<<i<<"_"; 00710 GiNaC::ex polspace = pol(order, nsd, s.str()); 00711 ret1.append(polspace.op(0)); 00712 ret2.append(polspace.op(1)); 00713 basis_tmp = GiNaC::ex_to<GiNaC::lst>(polspace.op(2)); 00714 for (GiNaC::lst::const_iterator basis_iterator = basis_tmp.begin(); 00715 basis_iterator != basis_tmp.end(); ++basis_iterator) 00716 { 00717 GiNaC::lst tmp_lst; 00718 for (unsigned int d=1; d<=no_fields; d++) tmp_lst.append(0); 00719 tmp_lst.let_op(i) = (*basis_iterator); 00720 ret3.append(tmp_lst); 00721 } 00722 } 00723 return GiNaC::lst(ret1,ret2,ret3); 00724 00725 /* Old Code: 00726 GiNaC::lst ret; 00727 for (int i=1; i<= nsd; i++) { 00728 std::ostringstream s; 00729 s <<a<<"^"<<i<<"_"; 00730 GiNaC::ex p = pol(order, nsd, s.str()); 00731 ret.append(p); 00732 } 00733 return ret; 00734 */ 00735 } 00736 00737 00738 GiNaC::ex polb(unsigned int order, unsigned int nsd, const string a) 00739 { 00740 using SyFi::x; 00741 using SyFi::y; 00742 using SyFi::z; 00743 00744 GiNaC::ex ret; // ex to return 00745 int dof; // degrees of freedom 00746 GiNaC::ex A; // ex holding the coefficients a_0 .. a_dof 00747 GiNaC::lst basis; 00748 00749 if (nsd == 1) 00750 { 00751 /* 1D: 00752 * P^n = a_0 + a_1*x + .... + a_n*x^n 00753 * dof : n+1 00754 */ 00755 dof = order+1; 00756 A = get_symbolic_matrix(1,dof, a); 00757 int o=0; 00758 for (GiNaC::const_iterator i = A.begin(); i != A.end(); ++i) 00759 { 00760 ret += (*i)*pow(x,o); 00761 basis.append(pow(x,o)); 00762 o++; 00763 } 00764 } 00765 else if ( nsd == 2) 00766 { 00767 00768 /* 2D: structure of coefficients (a_i) 00769 * [ a_0 a_1 x a_3 x^2 a_6 x^3 00770 * [ a_2 y a_4 xy a_7 x^2y 00771 * [ a_5 y^2 a_8 xy^2 00772 * [ a_9 y^3 00773 */ 00774 00775 dof = (order+1)*(order+1); 00776 A = get_symbolic_matrix(1, dof , a); 00777 00778 size_t i=0; 00779 for (unsigned int o = 0; o <= order; o++) 00780 { 00781 for (unsigned int d = 0; d <= order; d++) 00782 { 00783 ret += A.op(i)*pow(y,d)*pow(x,o); 00784 basis.append(pow(y,d)*pow(x,o)); 00785 i++; 00786 } 00787 } 00788 } 00789 else if (nsd == 3) 00790 { 00791 00792 /* Similar structure as in 2D, but 00793 * structured as a tetraheder, i.e., 00794 * a_o + a_1 x + a_2 y + a_3 z 00795 * + a_4 x^2 + a_5 xy + 00796 */ 00797 dof = (order+1)*(order+1)*(order+1); 00798 A = get_symbolic_matrix(1, dof , a); 00799 00800 size_t i=0; 00801 for (unsigned int o = 0; o <= order; o++) 00802 { 00803 for (unsigned int d = 0; d <= order; d++) 00804 { 00805 for (unsigned int f = 0; f <= order; f++) 00806 { 00807 ret += A.op(i)*pow(y,f)*pow(z,d)*pow(x,o); 00808 basis.append(pow(y,f)*pow(z,d)*pow(x,o)); 00809 i++; 00810 } 00811 } 00812 } 00813 } 00814 00815 return GiNaC::lst(ret,matrix_to_lst2(A), basis); 00816 } 00817 00818 00819 GiNaC::lst coeffs(GiNaC::lst pols) 00820 { 00821 GiNaC::lst cc; 00822 GiNaC::lst tmp; 00823 for (unsigned int i=0; i<= pols.nops()-1; i++) 00824 { 00825 tmp = coeffs(pols.op(i)); 00826 cc = collapse(GiNaC::lst(cc, tmp)); 00827 } 00828 return cc; 00829 } 00830 00831 00832 GiNaC::lst coeffs(GiNaC::ex pol) 00833 { 00834 using SyFi::x; 00835 using SyFi::y; 00836 using SyFi::z; 00837 00838 GiNaC::lst cc; 00839 GiNaC::ex c, b; 00840 for (int i=pol.ldegree(x); i<=pol.degree(x); ++i) 00841 { 00842 for (int j=pol.ldegree(y); j<=pol.degree(y); ++j) 00843 { 00844 for (int k=pol.ldegree(z); k<=pol.degree(z); ++k) 00845 { 00846 c = pol.coeff(x,i).coeff(y, j).coeff(z,k); 00847 if ( c != 0 ) cc.append(c); 00848 } 00849 } 00850 } 00851 return cc; 00852 } 00853 00854 00855 GiNaC::exvector coeff(GiNaC::ex pol) 00856 { 00857 using SyFi::x; 00858 using SyFi::y; 00859 using SyFi::z; 00860 00861 GiNaC::exvector cc; 00862 GiNaC::ex c, b; 00863 for (int i=pol.ldegree(x); i<=pol.degree(x); ++i) 00864 { 00865 for (int j=pol.ldegree(y); j<=pol.degree(y); ++j) 00866 { 00867 for (int k=pol.ldegree(z); k<=pol.degree(z); ++k) 00868 { 00869 c = pol.coeff(x,i).coeff(y, j).coeff(z,k); 00870 if ( c != 0 ) cc.insert(cc.begin(),c); 00871 } 00872 } 00873 } 00874 return cc; 00875 } 00876 00877 00878 GiNaC::exmap pol2basisandcoeff(GiNaC::ex e, GiNaC::ex s) 00879 { 00880 if (GiNaC::is_a<GiNaC::symbol>(s)) 00881 { 00882 GiNaC::symbol ss = GiNaC::ex_to<GiNaC::symbol>(s); 00883 e = expand(e); 00884 GiNaC::ex c; 00885 GiNaC::ex b; 00886 GiNaC::exmap map; 00887 for (int i=e.ldegree(ss); i<=e.degree(ss); ++i) 00888 { 00889 c = e.coeff(ss,i); 00890 b = pow(ss,i); 00891 map[b] = c; 00892 } 00893 return map; 00894 } 00895 else 00896 { 00897 throw(std::invalid_argument("The second argument must be a symbol.")); 00898 } 00899 } 00900 00901 00902 GiNaC::exmap pol2basisandcoeff(GiNaC::ex e) 00903 { 00904 using SyFi::x; 00905 using SyFi::y; 00906 using SyFi::z; 00907 00908 e = expand(e); 00909 GiNaC::ex c; 00910 GiNaC::ex b; 00911 GiNaC::exmap map; 00912 for (int i=e.ldegree(x); i<=e.degree(x); ++i) 00913 { 00914 for (int j=e.ldegree(y); j<=e.degree(y); ++j) 00915 { 00916 for (int k=e.ldegree(z); k<=e.degree(z); ++k) 00917 { 00918 c = e.coeff(x,i).coeff(y, j).coeff(z,k); 00919 b = pow(x,i)*pow(y,j)*pow(z,k); 00920 map[b] = c; 00921 } 00922 } 00923 } 00924 return map; 00925 } 00926 00927 00928 GiNaC::ex legendre1D(const GiNaC::symbol x, unsigned int n) 00929 { 00930 GiNaC::ex P; 00931 // Rodrigue's formula for Legendre polynomial of 1D 00932 // The interval [-1, 1] 00933 P=1/(pow(2,n)*GiNaC::factorial(n))*GiNaC::diff(GiNaC::pow((x*x-1),n),x,n); 00934 // ----------------- 00935 // The interval [0,1] 00936 // GiNaC::ex xx = 2*x - 1; 00937 // P=1/(pow(2,2*n)*GiNaC::factorial(n))*GiNaC::diff(GiNaC::pow((xx*xx-1),n),x,n); 00938 return P; 00939 } 00940 00941 00942 GiNaC::ex legendre(unsigned int order, unsigned int nsd, const string s) 00943 { 00944 using SyFi::x; 00945 using SyFi::y; 00946 using SyFi::z; 00947 00948 // The Legendre polynomials to be used in FiniteElement 00949 GiNaC::ex leg; 00950 GiNaC::ex A; 00951 GiNaC::lst basis; 00952 int dof; 00953 00954 GiNaC::ex b; 00955 00956 // 1D 00957 if(nsd == 1) 00958 { 00959 dof = order+1; 00960 A = get_symbolic_matrix(1,dof,s); 00961 int o=0; 00962 for(GiNaC::const_iterator i = A.begin(); i!=A.end(); ++i) 00963 { 00964 b= legendre1D(x,o); 00965 leg+= (*i)*b; 00966 basis.append(b); 00967 o++; 00968 } 00969 } 00970 // 2D 00971 /* 00972 else if(nsd == 2){ // NB: Only for tensor products on TRIANGLES (not boxes) 00973 / * 2D: structure of coefficients (a_i) 00974 * [ a_0 a_1 P_1(x) a_3 P_2(x) a_6 P_3(x) 00975 * [ a_2 P_1(y) a_4 P_1(x)*P_1(y) a_7 P_2(x)*P_1(y) 00976 * [ a_5 P_2(y) a_8 P_1(x)*P_2(y) 00977 * [ a_9 P_3(y) 00978 * / 00979 dof = (order+1)*(order+2)/2; 00980 A = get_symbolic_matrix(1,dof,s); 00981 size_t i=0; 00982 for (int o = 0; o <= order; o++) { 00983 for (int d = 0; d <= o; d++) { 00984 b = legendre1D(y,d)*legendre1D(x,o-d); 00985 leg += A.op(i)*b; 00986 basis.append(b); 00987 i++; 00988 00989 } 00990 } 00991 } 00992 */ 00993 else if(nsd == 2) // NB: Only for tensor products on rectangles 00994 { 00995 dof = (order+1)*(order+1); 00996 A = get_symbolic_matrix(1,dof,s); 00997 size_t i=0; 00998 for (unsigned int o = 0; o <= order; o++) 00999 { 01000 for (unsigned int d = 0; d <= order; d++) 01001 { 01002 b = legendre1D(y,d)*legendre1D(x,o); 01003 leg += A.op(i)*b; 01004 basis.append(b); 01005 i++; 01006 01007 } 01008 } 01009 } 01010 01011 /* tetrahedron 01012 else if(nsd==3){ 01013 dof = 0; 01014 for (int j=0; j<= order; j++) { 01015 dof += (j+1)*(j+2)/2; 01016 } 01017 A = get_symbolic_matrix(1, dof , s); 01018 01019 size_t i=0; 01020 for (int o = 0; o <= order; o++) { 01021 for (int d = 0; d <= o; d++) { 01022 for (int f = 0; f <= o; f++) { 01023 if ( o-d-f >= 0) { 01024 b = legendre1D(y,f)*legendre1D(z,d)*legendre1D(x,o-d-f); 01025 leg += A.op(i)*b; 01026 basis.append(b); 01027 i++; 01028 } 01029 } 01030 } 01031 } 01032 } 01033 */ 01034 01035 else if(nsd==3) 01036 { 01037 dof = (order+1)*(order+1)*(order+1); 01038 A = get_symbolic_matrix(1, dof , s); 01039 01040 size_t i=0; 01041 for (unsigned int o = 0; o <= order; o++) 01042 { 01043 for (unsigned int d = 0; d <= order; d++) 01044 { 01045 for (unsigned int f = 0; f <= order; f++) 01046 { 01047 b = legendre1D(y,f)*legendre1D(z,d)*legendre1D(x,o); 01048 leg += A.op(i)*b; 01049 basis.append(b); 01050 i++; 01051 } 01052 } 01053 } 01054 } 01055 return GiNaC::lst(leg,matrix_to_lst2(A), basis); 01056 } 01057 01058 01059 GiNaC::lst legendrev(unsigned int no_fields, unsigned int order, unsigned int nsd, const string a) 01060 { 01061 GiNaC::lst ret1; // contains the polynom 01062 GiNaC::lst ret2; // contains the coefficients 01063 GiNaC::lst ret3; // constains the basis functions 01064 GiNaC::lst basis_tmp; 01065 for (unsigned int i=1; i<= no_fields; i++) 01066 { 01067 GiNaC::lst basis; 01068 std::ostringstream s; 01069 s <<a<<""<<i<<"_"; 01070 GiNaC::ex polspace = legendre(order, nsd, s.str()); 01071 ret1.append(polspace.op(0)); 01072 ret2.append(polspace.op(1)); 01073 basis_tmp = GiNaC::ex_to<GiNaC::lst>(polspace.op(2)); 01074 for (GiNaC::lst::const_iterator basis_iterator = basis_tmp.begin(); 01075 basis_iterator != basis_tmp.end(); ++basis_iterator) 01076 { 01077 GiNaC::lst tmp_lst; 01078 for (unsigned int d=1; d<=no_fields; d++) tmp_lst.append(0); 01079 tmp_lst.let_op(i-1) = (*basis_iterator); 01080 ret3.append(tmp_lst); 01081 } 01082 } 01083 return GiNaC::lst(ret1,ret2,ret3); 01084 } 01085 01086 01087 bool compare(const ex & e, const string & s) 01088 { 01089 ostringstream ss; 01090 ss << e; 01091 return ss.str() == s; 01092 } 01093 01094 01095 void EQUAL_OR_DIE(const ex & e, const string & s) 01096 { 01097 if (!compare(e, s)) 01098 { 01099 ostringstream os; 01100 os << "ERROR: expression e: " <<e<<" is not equal to "<<s<<endl; 01101 throw runtime_error(os.str()); 01102 } 01103 } 01104 01105 01106 // =========== expression inspection utilities 01107 01108 class SymbolMapBuilderVisitor: 01109 public visitor, 01110 public symbol::visitor 01111 { 01112 public: 01113 SymbolMapBuilderVisitor(GiNaC::exmap & em): symbolmap(em) {} 01114 01115 GiNaC::exmap & symbolmap; 01116 01117 void visit(const symbol & s) 01118 { 01119 GiNaC::exmap::iterator it = symbolmap.find(s); 01120 if(it != symbolmap.end()) 01121 { 01122 it->second++; 01123 } 01124 else 01125 { 01126 //GiNaC::exmap::value_type p(ex(s), ex(s)); 01127 //symbolmap.insert(p); 01128 symbolmap[ex(s)] = ex(s); 01129 } 01130 } 01131 }; 01132 01133 class SymbolCounterVisitor: 01134 public visitor, 01135 public symbol::visitor, 01136 public basic::visitor 01137 { 01138 public: 01139 exhashmap<int> symbolcount; 01140 01141 void visit(const basic & s) 01142 { 01143 std::cout << "visiting basic " << std::endl; 01144 } 01145 01146 void visit(const symbol & s) 01147 { 01148 ex e = s; 01149 std::cout << "visiting symbol " << e << std::endl; 01150 exhashmap<int>::iterator it = symbolcount.find(s); 01151 if(it != symbolcount.end()) 01152 { 01153 std::cout << "found symbol " << e << std::endl; 01154 it->second++; 01155 } 01156 else 01157 { 01158 std::cout << "adding symbol " << e << std::endl; 01159 pair<ex,int> p; 01160 p.first = ex(s); 01161 p.second = 1; 01162 symbolcount.insert(p); 01163 } 01164 } 01165 }; 01166 01167 exhashmap<int> count_symbols(const ex & e) 01168 { 01169 SymbolCounterVisitor v; 01170 e.traverse(v); 01171 return v.symbolcount; 01172 } 01173 01174 01175 /* 01176 GiNaC::exvector get_symbols3(const GiNaC::ex & e) 01177 { 01178 // Implemented directly to avoid copying map: 01179 SymbolCounterVisitor v; 01180 e.traverse(v); 01181 exhashmap<int> & sc = v.symbolcount; 01182 01183 int i = 0; 01184 GiNaC::exvector l(sc.size()); 01185 for(exhashmap<int>::iterator it=sc.begin(); it!=sc.end(); it++) 01186 { 01187 //l.push_back(it->first); 01188 l[i] = it->first; 01189 i++; 01190 } 01191 return l; 01192 } 01193 01194 std::list<GiNaC::ex> get_symbols2(const ex & e) 01195 { 01196 // Implemented directly to avoid copying map: 01197 SymbolCounterVisitor v; 01198 e.traverse(v); 01199 exhashmap<int> & sc = v.symbolcount; 01200 01201 list<ex> l; 01202 for(exhashmap<int>::iterator it=sc.begin(); it!=sc.end(); it++) 01203 { 01204 l.push_back(it->first); 01205 } 01206 return l; 01207 } 01208 01209 void get_symbols(const ex & e, GiNaC::exmap & em) 01210 { 01211 SymbolMapBuilderVisitor v(em); 01212 e.traverse(v); 01213 } 01214 */ 01215 ex extract_symbols(const ex & e) 01216 { 01217 // Implemented directly to avoid copying map: 01218 SymbolCounterVisitor v; 01219 e.traverse(v); 01220 exhashmap<int> & sc = v.symbolcount; 01221 01222 lst l; 01223 for(exhashmap<int>::iterator it=sc.begin(); it!=sc.end(); it++) 01224 { 01225 l.append(it->first); 01226 std::cout << (it->first) << std::endl; 01227 } 01228 ex ret = l; 01229 return ret; 01230 } 01231 01232 01233 // Collect all symbols of an expression 01234 void collect_symbols(const GiNaC::ex & e, exset & v) 01235 { 01236 if (GiNaC::is_a<GiNaC::symbol>(e)) 01237 { 01238 v.insert(e); 01239 } 01240 else 01241 { 01242 for (size_t i=0; i<e.nops(); i++) 01243 { 01244 collect_symbols(e.op(i), v); 01245 } 01246 } 01247 } 01248 01249 01250 GiNaC::exvector collect_symbols(const GiNaC::ex & e) 01251 { 01252 exset s; 01253 collect_symbols(e, s); 01254 GiNaC::exvector v(s.size()); 01255 for(exset::iterator i=s.begin(); i!= s.end(); i++) 01256 { 01257 v.push_back(*i); 01258 } 01259 return v; 01260 } 01261 01262 01263 bool compare_archives(const string & first, const string & second, std::ostream & os) 01264 { 01265 bool ret = true; 01266 01267 // read both archives 01268 archive a1, a2; 01269 ifstream if1(first.c_str()), if2(second.c_str()); 01270 if1 >> a1; 01271 if2 >> a2; 01272 01273 // compare size 01274 int n = a1.num_expressions(); 01275 int n2 = a2.num_expressions(); 01276 if(n != n2) 01277 { 01278 os << "Archives " << first << " and " << second 01279 << " has a different number of expressions, " << n << " and " << n2 << "." << endl; 01280 os << "Comparing common expressions." << endl; 01281 ret = false; 01282 } 01283 01284 // iterate over all expressions in first archive 01285 ex e1,e2; 01286 for(int i=0; i<n; i++) 01287 { 01288 lst syms; 01289 string exname; 01290 01291 e1 = a1.unarchive_ex(syms, exname, i); 01292 01293 syms = ex_to<lst>(extract_symbols(e1)); 01294 // os << "Comparing " << exname << " with symbols " << syms << endl; 01295 01296 // is this in the second archive? 01297 try 01298 { 01299 e2 = a2.unarchive_ex(syms, exname.c_str()); 01300 01301 // got it, now compare 01302 bool isequal = is_zero(e1-e2); 01303 if(!isequal) 01304 { 01305 if(ret) 01306 { 01307 os << "Archives " << first << " and " << second 01308 << " are not equal, details follow:" << endl; 01309 } 01310 os << "Expression with name " << exname << " is not equal:" << endl; 01311 os << "First: " << endl << e1 << endl; 01312 os << "Second: " << endl << e2 << endl; 01313 ret = false; 01314 } 01315 } 01316 catch(...) 01317 { 01318 os << "Expression " << exname << " is missing from " << second << "." << endl; 01319 ret = false; 01320 } 01321 } 01322 01323 return ret; 01324 } 01325 01326 01327 class ExStatsVisitor: 01328 public visitor, 01329 public power::visitor, 01330 public mul::visitor, 01331 public add::visitor, 01332 public function::visitor 01333 { 01334 public: 01335 ExStats es; 01336 01337 void visit(const power & e) 01338 { 01339 //cout << "pow" << endl; 01340 ex b = e.op(1); 01341 ex c = b.evalf(); 01342 if( is_a<numeric>(c) ) 01343 { 01344 numeric nu = ex_to<numeric>(c); 01345 int n = (int) to_double(nu); 01346 if( is_zero(nu-n) ) 01347 { 01348 // is an integer power, interpret as a sequence of multiplications 01349 es.muls += n-1; 01350 es.flops += n-1; 01351 } 01352 } 01353 01354 es.pows++; 01355 } 01356 01357 void visit(const mul & e) 01358 { 01359 //cout << "mul" << endl; 01360 es.muls += e.nops()-1; 01361 es.flops += e.nops()-1; 01362 } 01363 01364 void visit(const add & e) 01365 { 01366 //cout << "add" << endl; 01367 es.adds += e.nops()-1; 01368 es.flops += e.nops()-1; 01369 } 01370 01371 void visit(const function & e) 01372 { 01373 //cout << "func" << endl; 01374 es.functions++; 01375 } 01376 }; 01377 01378 ExStats count_ops(const ex & e) 01379 { 01380 //cout << "count_ops " << e << endl; 01381 //cout << "is an add: " << GiNaC::is<GiNaC::add>(e) << endl; 01382 //cout << "is a mul: " << GiNaC::is<GiNaC::mul>(e) << endl; 01383 ExStatsVisitor v; 01384 e.traverse(v); 01385 return v.es; 01386 } 01387 01388 01389 // =========== expression manipulation utilities 01390 01391 // Returns in sel a list with symbol/expression pairs for all 01392 // power replacement variables introduced. Works best on 01393 // expressions in expanded form. 01394 ex replace_powers(const ex & ein, const list<symbol> & symbols, list<symexpair> & sel, const string & tmpsymbolprefix) 01395 { 01396 ex e = ein; 01397 // build power expressions 01398 list<symbol>::const_iterator it = symbols.begin(); 01399 for(; it != symbols.end(); it++) 01400 { 01401 int deg = e.degree(*it); 01402 if(deg > 0) 01403 { 01404 symbol sym = ex_to<symbol>(*it); 01405 string sname = tmpsymbolprefix + sym.get_name(); 01406 01407 // make list of new symbols 01408 vector<symbol> symbols(deg); 01409 symbols[0] = sym; 01410 for(int i=1; i<deg; i++) 01411 { 01412 symbols[i] = get_symbol( sname + int2string(i+1) ); 01413 sel.push_back(make_pair(symbols[i], symbols[i-1]*sym)); 01414 } 01415 01416 // with highest order first, subs in e 01417 ex prod = sym; 01418 for(int i=deg-1; i>=1; i--) 01419 { 01420 e = e.subs(power(sym,i+1) == symbols[i], subs_options::algebraic); 01421 } 01422 } 01423 } 01424 return e; 01425 } 01426 01427 01428 }; // namespace SyFi