exp_vector_t degree_vector(ex e, const exvector& vars) { e = e.expand(); exp_vector_t dvec(vars.size()); for (std::size_t i = vars.size(); i-- != 0; ) { const int deg_i = e.degree(vars[i]); e = e.coeff(vars[i], deg_i); dvec[i] = deg_i; } return dvec; }
/* Extract only the divergent part of a series and discard the rest. */ static ex div_part(const ex &exarg, const symbol &x, unsigned grad) { const ex exser = exarg.series(x==0, grad); if (exser.degree(x)<0) throw runtime_error("divergent part truncation disaster"); ex exser_trunc; for (int i=exser.ldegree(x); i<0; ++i) exser_trunc += exser.coeff(x,i)*pow(x,i); // NB: exser_trunc is by construction collected in x. return exser_trunc; }
ex lsolve(const ex &eqns, const ex &symbols, unsigned options) { // solve a system of linear equations if (eqns.info(info_flags::relation_equal)) { if (!symbols.info(info_flags::symbol)) throw(std::invalid_argument("lsolve(): 2nd argument must be a symbol")); const ex sol = lsolve(lst{eqns}, lst{symbols}); GINAC_ASSERT(sol.nops()==1); GINAC_ASSERT(is_exactly_a<relational>(sol.op(0))); return sol.op(0).op(1); // return rhs of first solution } // syntax checks if (!eqns.info(info_flags::list)) { throw(std::invalid_argument("lsolve(): 1st argument must be a list or an equation")); } for (size_t i=0; i<eqns.nops(); i++) { if (!eqns.op(i).info(info_flags::relation_equal)) { throw(std::invalid_argument("lsolve(): 1st argument must be a list of equations")); } } if (!symbols.info(info_flags::list)) { throw(std::invalid_argument("lsolve(): 2nd argument must be a list or a symbol")); } for (size_t i=0; i<symbols.nops(); i++) { if (!symbols.op(i).info(info_flags::symbol)) { throw(std::invalid_argument("lsolve(): 2nd argument must be a list of symbols")); } } // build matrix from equation system matrix sys(eqns.nops(),symbols.nops()); matrix rhs(eqns.nops(),1); matrix vars(symbols.nops(),1); for (size_t r=0; r<eqns.nops(); r++) { const ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); // lhs-rhs==0 ex linpart = eq; for (size_t c=0; c<symbols.nops(); c++) { const ex co = eq.coeff(ex_to<symbol>(symbols.op(c)),1); linpart -= co*symbols.op(c); sys(r,c) = co; } linpart = linpart.expand(); rhs(r,0) = -linpart; } // test if system is linear and fill vars matrix for (size_t i=0; i<symbols.nops(); i++) { vars(i,0) = symbols.op(i); if (sys.has(symbols.op(i))) throw(std::logic_error("lsolve: system is not linear")); if (rhs.has(symbols.op(i))) throw(std::logic_error("lsolve: system is not linear")); } matrix solution; try { solution = sys.solve(vars,rhs,options); } catch (const std::runtime_error & e) { // Probably singular matrix or otherwise overdetermined system: // It is consistent to return an empty list return lst{}; } GINAC_ASSERT(solution.cols()==1); GINAC_ASSERT(solution.rows()==symbols.nops()); // return list of equations of the form lst{var1==sol1,var2==sol2,...} lst sollist; for (size_t i=0; i<symbols.nops(); i++) sollist.append(symbols.op(i)==solution(i,0)); return sollist; }