/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c desolve.cc -DHAVE_CONFIG_H -DIN_GIAC" -*- */
#include "giacPCH.h"
/*
* Copyright (C) 2000, 2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using namespace std;
#include
#include
#include "desolve.h"
#include "derive.h"
#include "intg.h"
#include "subst.h"
#include "usual.h"
#include "symbolic.h"
#include "unary.h"
#include "poly.h"
#include "sym2poly.h" // for equalposcomp
#include "tex.h"
#include "modpoly.h"
#include "series.h"
#include "solve.h"
#include "ifactor.h"
#include "prog.h"
#include "rpn.h"
#include "lin.h"
#include "intgab.h"
#include "giacintl.h"
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
gen integrate_without_lnabs(const gen & e,const gen & x,GIAC_CONTEXT){
// workaround for desolve(diff(y)*sin(x)=y*ln(y),x,y);
// otherwise it returns ln(-1-cos(x))
bool save_cv=complex_variables(contextptr);
complex_variables(false,contextptr);
gen res=integrate_gen(e,x,contextptr);
if (lop(res,at_abs).empty() && lop(res,at_floor).empty()){
complex_variables(save_cv,contextptr);
return res;
}
bool save_do_lnabs=do_lnabs(contextptr);
do_lnabs(false,contextptr);
res=integrate_gen(e,x,contextptr);
do_lnabs(save_do_lnabs,contextptr);
complex_variables(save_cv,contextptr);
return res;
}
gen gen_t(const vecteur & v,GIAC_CONTEXT){
#ifdef GIAC_HAS_STO_38
identificateur id_t("t38_");
#else
identificateur id_t(" t");
#endif
gen tmp_t,t=t__IDNT;
t=t._IDNTptr->eval(1,tmp_t,contextptr);
if (t!=t__IDNT || equalposcomp(lidnt(v),t__IDNT))
t=id_t;
return t;
}
gen laplace(const gen & f0,const gen & x,const gen & s,GIAC_CONTEXT){
if (x.type!=_IDNT)
return gensizeerr(contextptr);
if (f0.type==_VECT){
vecteur v=*f0._VECTptr;
for (int i=0;ishift(idxt));
f=r2sym(ff,v,contextptr);
if (n%2)
f=-f;
}
}
if (!assume_t_in_ab(t,plus_inf,plus_inf,true,true,contextptr))
return gensizeerr(contextptr);
gen res=_integrate(makesequence(f*exp(-t*x,contextptr),x),contextptr);
if (lop(res,at_integrate).empty())
res=-_limit(makesequence(res,x,0,1),contextptr);
else
res=undef;
if (is_undef(res))
res=_integrate(makesequence(f*exp(-t*x,contextptr),x,0,plus_inf),contextptr);
for (int i=1;i<=n;++i){
if (is_undef(res))
return res;
res = _integrate(gen(makevecteur(res,t,0,t),_SEQ__VECT),contextptr);
res += _integrate(gen(makevecteur(f/pow(-x,i),x,0,plus_inf),_SEQ__VECT),contextptr);
}
purgenoassume(t,contextptr);
if (s==x)
res=subst(res,t,x,false,contextptr);
return ratnormal(res,contextptr);
/*
gen remains,res=integrate(f*exp(-t*x,contextptr),*x._IDNTptr,remains,contextptr);
res=subst(-res,x,zero,false,contextptr);
if (s==x)
res=subst(res,t,x,false,contextptr);
if (!is_zero(remains))
res = res +symbolic(at_integrate,gen(makevecteur(remains,x,0,plus_inf),_SEQ__VECT));
return res;
*/
}
static gen _laplace_(const gen & args,GIAC_CONTEXT){
if (args.type!=_VECT)
return laplace(args,vx_var,vx_var,contextptr);
vecteur & v=*args._VECTptr;
int s=int(v.size());
if (s==2)
return laplace( v[0],v[1],v[1],contextptr);
if (s!=3)
return gensizeerr(contextptr);
return laplace( v[0],v[1],v[2],contextptr);
}
// "unary" version
gen _laplace(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
bool b=approx_mode(contextptr);
approx_mode(false,contextptr);
#ifndef NSPIRE
my_ostream * ptr=logptr(contextptr);
logptr(0,contextptr);
gen res=_laplace_(args,contextptr);
logptr(ptr,contextptr);
#else
gen res=_laplace_(exact(args,contextptr),contextptr);
#endif
approx_mode(b,contextptr);
if (b || has_num_coeff(args))
res=simplifier(evalf(res,1,contextptr),contextptr);
return res;
}
static const char _laplace_s []="laplace";
static define_unary_function_eval (__laplace,&_laplace,_laplace_s);
define_unary_function_ptr5( at_laplace ,alias_at_laplace,&__laplace,0,true);
polynome cstcoeff(const polynome & p){
vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end();
for (;it!=itend;++it){
if (it->index.front()==0)
break;
}
return polynome(p.dim,vector< monomial >(it,itend));
}
// reduction of a fraction with multiple poles to single poles by integration
// by part, use the relation
// ilaplace(P'/P^(k+1))=laplacevar/k*ilaplace(1/P^k)
pf laplace_reduce_pf(const pf & p_cst, tensor & laplacevar ){
pf p(p_cst);
assert(p.mult>0);
if (p.mult==1)
return p_cst;
tensor fprime=p.fact.derivative();
tensor d(fprime.dim),C(fprime.dim),u(fprime.dim),v(fprime.dim);
egcdpsr(p.fact,fprime,u,v,d); // f*u+f'*v=d
tensor usave(u),vsave(v);
// int initial_mult=p.mult-1;
while (p.mult>1){
egcdtoabcuv(p.fact,fprime,p.num,u,v,d,C);
p.mult--;
p.den=(p.den/p.fact)*C*gen(p.mult);
p.num=u*gen(p.mult)+v.derivative()+v*laplacevar;
if ( (p.mult % 5)==1) // simplify from time to time
TsimplifybyTlgcd(p.num,p.den);
if (p.mult==1)
break;
u=usave;
v=vsave;
}
return pf(p);
}
static gen pf_ilaplace(const gen & e0,const gen & x, gen & remains,GIAC_CONTEXT){
vecteur vexp;
gen res;
lin(e0,vexp,contextptr); // vexp = coeff, arg of exponential
const_iterateur it=vexp.begin(),itend=vexp.end();
remains=0;
for (;it!=itend;){
gen coeff=*it;
++it;
gen axb=*it,expa,expb;
++it;
gen e=coeff*exp(axb,contextptr);
if (!is_linear_wrt(axb,x,expa,expb,contextptr)){
remains += e;
continue;
}
if (is_strictly_positive(expa,contextptr))
*logptr(contextptr) << gettext("Warning, exponential x coeff is positive ") << expa << '\n';
vecteur varx(lvarx(coeff,x));
int varxs=int(varx.size());
if (!varxs){ // Dirac function
res += coeff*exp(expb,contextptr)*symbolic(at_Dirac,laplace_var+expa);
continue;
}
if ( (varxs>1) || (varx.front()!=x) ) {
remains += e;
continue;
}
vecteur l;
l.push_back(x); // insure x is the main var
l.push_back(laplace_var); // s var as second var
l=vecteur(1,l);
alg_lvar(makevecteur(coeff,axb),l);
gen glap=e2r(laplace_var,l,contextptr);
if (glap.type!=_POLY) return gensizeerr(gettext("desolve.cc/pf_ilaplace"));
int s=int(l.front()._VECTptr->size());
if (!s){
l.erase(l.begin());
s=int(l.front()._VECTptr->size());
}
gen r=e2r(coeff,l,contextptr);
gen r_num,r_den;
fxnd(r,r_num,r_den);
if (r_num.type==_EXT){
remains += e;
continue;
}
if (r_den.type!=_POLY){
remains += e;
continue;
}
polynome den(*r_den._POLYptr),num(s);
if (r_num.type==_POLY)
num=*r_num._POLYptr;
else
num=polynome(r_num,s);
polynome p_content(lgcd(den));
factorization vden(sqff(den/p_content)); // first square-free factorization
vector< pf > pfde_VECT;
polynome ipnum(s),ipden(s),temp(s),tmp(s);
partfrac(num,den,vden,pfde_VECT,ipnum,ipden);
vector< pf >::iterator it=pfde_VECT.begin();
vector< pf >::const_iterator itend=pfde_VECT.end();
vector< pf > rest,finalde_VECT;
for (;it!=itend;++it){
pf single(laplace_reduce_pf(*it,*glap._POLYptr));
gen extra_div=1;
factor(single.den,p_content,vden,false,withsqrt(contextptr),complex_mode(contextptr),1,extra_div);
partfrac(single.num,single.den,vden,finalde_VECT,temp,tmp);
}
it=finalde_VECT.begin();
itend=finalde_VECT.end();
gen lnpart(0),deuxaxplusb,sqrtdelta,exppart;
polynome a(s),b(s),c(s);
polynome d(s),E(s),lnpartden(s);
polynome delta(s),atannum(s),alpha(s);
vecteur lprime(l);
if (lprime.front().type!=_VECT) return gensizeerr(gettext("desolve.cc/pf_ilaplace"));
lprime.front()=cdr_VECT(*(lprime.front()._VECTptr));
bool uselog;
for (;it!=itend;++it){
int deg=it->fact.lexsorted_degree();
switch (deg) {
case 1: // 1st order
findde(it->den,a,b);
lnpart=lnpart+rdiv(r2e(it->num,l,contextptr),r2e(firstcoeff(a),lprime,contextptr),contextptr)*exp(r2e(rdiv(-b,a,contextptr),lprime,contextptr)*laplace_var,contextptr);
break;
case 2: // 2nd order
findabcdelta(it->fact,a,b,c,delta);
exppart=exp(r2e(rdiv(-b,gen(2)*a,contextptr),lprime,contextptr)*laplace_var,contextptr);
uselog=is_positive(delta);
alpha=(it->den/it->fact).trunc1()*a;
findde(it->num,d,E);
atannum=a*E*gen(2)-b*d;
// cos part d/alpha*ln(fact)
lnpartden=alpha;
simplify(d,lnpartden);
if (uselog){
sqrtdelta=normal(sqrt(r2e(delta,lprime,contextptr),contextptr),contextptr);
gen racine=ratnormal(sqrtdelta/gen(2)/r2e(a,lprime,contextptr),contextptr);
lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*cosh(racine*laplace_var,contextptr)*exppart;
gen aa=ratnormal(r2e(atannum,lprime,contextptr)/r2e(alpha,lprime,contextptr)/sqrtdelta,contextptr);
lnpart=lnpart+aa*sinh(racine*laplace_var,contextptr)*exppart;
}
else {
sqrtdelta=normal(sqrt(r2e(-delta,lprime,contextptr),contextptr),contextptr);
gen racine=ratnormal(sqrtdelta/gen(2)/r2e(a,lprime,contextptr),contextptr);
lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*cos(racine*laplace_var,contextptr)*exppart;
gen aa=ratnormal(r2e(atannum,lprime,contextptr)/r2e(alpha,lprime,contextptr)/sqrtdelta,contextptr);
lnpart=lnpart+aa*sin(racine*laplace_var,contextptr)*exppart;
}
break;
default:
rest.push_back(pf(it->num,it->den,it->fact,1));
break ;
}
}
vecteur ipnumv=polynome2poly1(ipnum,1);
gen deno=r2e(ipden,l,contextptr);
int nums=int(ipnumv.size());
for (int i=0;itype==_SYMB) && (it->_SYMBptr->sommet==at_derive) ){
gen & g=it->_SYMBptr->feuille;
int m=-1,nder=1;
if ( (g.type==_VECT) && (!g._VECTptr->empty()) ){
m=diffeq_order(g._VECTptr->front(),y);
if (g._VECTptr->size()==3){
gen & gg=g._VECTptr->back();
if (gg.type==_INT_)
nder=gg.val;
}
}
else
m=diffeq_order(g,y);
if (m>=0)
n=giacmax(n,m+nder);
}
}
return n;
}
// true if f is a linear differential equation
// & returns the coefficient in v in descending order
// v has size order+2 with last term=cst coeff of the diff equation
static bool is_linear_diffeq(const gen & f_orig,const gen & x,const gen & y,int order,vecteur & v,int step_info,GIAC_CONTEXT){
v.clear();
gen f(f_orig),a,b,cur_y(y);
gen t=gen_t(makevecteur(x,y,f_orig),contextptr);
for (int i=0;i<=order;++i){
gen ftmp(quotesubst(f,cur_y,t,contextptr));
if (!is_linear_wrt(eval(ftmp,eval_level(contextptr),contextptr),t,a,b,contextptr))
return false;
if (!rlvarx(a,y).empty())
return false;
if (!i)
v.push_back(b);
v.push_back(a);
cur_y=symb_derive(y,x,i+1);
}
reverse(v.begin(),v.end());
if (step_info && v.size()>3)
gprintf("Linear differential equation of coefficients %gen\nsecond member %gen",makevecteur(vecteur(v.begin(),v.end()-1),-v.back()),step_info,contextptr);
return true;
}
static bool find_n_derivatives_function(const gen & f,const gen & x,int & nder,gen & fonction){
if ( (f.type!=_SYMB) || (f._SYMBptr->sommet!=at_derive) ){
nder=0;
fonction=f;
return true;
}
if (f._SYMBptr->feuille.type!=_VECT){
if (!find_n_derivatives_function(f._SYMBptr->feuille,x,nder,fonction))
return false;
++nder;
return true;
}
vecteur & v=*f._SYMBptr->feuille._VECTptr;
if ( (v.size()>1) && (v[1]!=x) )
return false; // setsizeerr(contextptr);
if (!find_n_derivatives_function(v[0],x,nder,fonction))
return false;
if ( (v.size()==3) && (v[2].type==_INT_) )
nder += v[2].val;
else
nder += 1;
return true;
}
static gen function_of(const gen & y_orig,const gen & x_orig){
if ( (y_orig.type!=_SYMB) || (y_orig._SYMBptr->sommet!=at_of) )
return gensizeerr(gettext("function_of"));
vecteur & v =*y_orig._SYMBptr->feuille._VECTptr;
if ( (v[1]!=x_orig) || (v[0].type!=_IDNT) )
return gensizeerr(gettext("function_of"));
return v[0];
}
static gen in_desolve_with_conditions(const vecteur & v_,const gen & x,const gen & y,const gen & solution_generale,const vecteur & parameters,const gen & f,int step_info,GIAC_CONTEXT){
gen yy(y);
vecteur v(v_);
if (yy.type!=_IDNT)
yy=function_of(y,x);
if (is_undef(yy))
return yy;
// special handling for systems
if (solution_generale.type==_VECT && v.size()==2){
gen init=v[1],point=0;
if (init.is_symb_of_sommet(at_equal) && init._SYMBptr->feuille.type==_VECT&& init._SYMBptr->feuille._VECTptr->size()>=2){
point=(*init._SYMBptr->feuille._VECTptr)[0];
init=(*init._SYMBptr->feuille._VECTptr)[1];
if (!point.is_symb_of_sommet(at_of) || point._SYMBptr->feuille.type!=_VECT || point._SYMBptr->feuille._VECTptr->size()<2 || point._SYMBptr->feuille._VECTptr->front()!=y)
return gensizeerr("Bad initial condition");
point=(*point._SYMBptr->feuille._VECTptr)[1];
}
gen systeme=subst(solution_generale,x,point,false,contextptr)-init;
gen s=_solve(makesequence(systeme,parameters),contextptr);
if (s.type!=_VECT)
return gensizeerr("Bad initial condition");
vecteur res;
for (unsigned i=0;isize();++i){
gen tmp=subst(solution_generale,parameters,s[i],false,contextptr);
tmp=ratnormal(tmp,contextptr);
res.push_back(tmp);
}
return res;
}
if (solution_generale.type==_VECT)
*logptr(contextptr) << gettext("Boundary conditions for parametric curve not implemented") << '\n';
// solve boundary conditions
iterateur jt=v.begin()+1,jtend=v.end();
for (unsigned ndiff=0;jt!=jtend;++ndiff,++jt){
if (jt->type==_VECT && jt->_VECTptr->size()==2){
if (ndiff)
*jt=symbolic(at_of,makesequence(symbolic(at_derive,makesequence(y,x,int(ndiff))),jt->_VECTptr->front()))-jt->_VECTptr->back();
else
*jt=symbolic(at_of,makesequence(y,jt->_VECTptr->front()))-jt->_VECTptr->back();
}
}
const_iterateur it=v.begin()+1,itend=v.end();
vecteur conditions(remove_equal(it,itend));
if (conditions.empty())
return solution_generale;
// conditions must be in terms of y(value) or derivatives
vecteur condvar(rlvarx(conditions,yy));
vecteur yvar; // will contain triplet (var,n,x) n=nth derivative, x point
it=condvar.begin(),itend=condvar.end();
int maxnder=0;
for (;it!=itend;++it){
if ( (it->type!=_SYMB) || (it->_SYMBptr->sommet!=at_of) )
continue;
vecteur & w=*it->_SYMBptr->feuille._VECTptr;
int nder;
gen fonction;
if (!find_n_derivatives_function(w[0],x,nder,fonction))
return gensizeerr(contextptr);
if (fonction==y){
if ( (w[1].type==_VECT) && (!w[1]._VECTptr->empty()))
yvar.push_back(makevecteur(*it,nder,w[1]._VECTptr->front()));
else
yvar.push_back(makevecteur(*it,nder,w[1]));
}
if (nder>maxnder)
maxnder=nder;
}
// compute all derivatives of the general solution
vecteur derivatives(1,solution_generale);
gen current=solution_generale;
for (int i=1;i<=maxnder;++i){
current=derive(current,x,contextptr);
derivatives.push_back(current);
}
// evaluate at points of yvar making substition vectors
it=yvar.begin(),itend=yvar.end();
vecteur substin,substout;
for (;it!=itend;++it){
vecteur & w=*it->_VECTptr;
substin.push_back(w[0]);
substout.push_back(subst(derivatives[w[1].val],x,w[2],false,contextptr));
}
// replace in conditions
conditions=*eval(subst(conditions,substin,substout,false,contextptr),eval_level(contextptr),contextptr)._VECTptr;
// solve system over _c0..._cn-1
int save_xcas_mode=xcas_mode(contextptr);
xcas_mode(contextptr)=0;
int save_calc_mode=calc_mode(contextptr);
calc_mode(contextptr)=0;
vecteur parameters_solutions=*_solve(gen(makevecteur(conditions,parameters),_SEQ__VECT),contextptr)._VECTptr;
if (step_info)
gprintf("General solution %gen\nSolving initial conditions\n%gen\nunknowns %gen\nSolutions %gen",makevecteur(solution_generale,conditions,parameters,parameters_solutions),step_info,contextptr);
xcas_mode(contextptr)=save_xcas_mode;
calc_mode(contextptr)=save_calc_mode;
// replace _c0..._cn-1 in solution_generale
it=parameters_solutions.begin(),itend=parameters_solutions.end();
vecteur res;
for (;it!=itend;++it){
gen solgen=eval(subst(solution_generale,parameters,*it,false,contextptr),eval_level(contextptr),contextptr);
// check if f is valid at points where conditions hold (3rd column of yvar)
gen solgenchk=eval(subst(f,y,solgen,false,contextptr),1,contextptr);
bool ok=true;
for (unsigned i=0;ibegin(),itend=solution_generale._VECTptr->end();
vecteur res;
res.reserve(itend-it);
for (;it!=itend;++it){
if (it->type==_VECT) it->subtype=0;
gen tmp=in_desolve_with_conditions(v,x,y,*it,parameters,f,step_info,contextptr);
if (is_undef(tmp))
return tmp;
if (tmp.type==_VECT)
res=mergevecteur(res,*tmp._VECTptr);
else
res.push_back(tmp);
}
return num?evalf(res,1,contextptr):res;
}
static gen desolve_with_conditions(const vecteur & v,const gen & x,const gen & y,gen & f,GIAC_CONTEXT){
int st=step_infolevel(contextptr);
step_infolevel(0,contextptr);
gen res=desolve_with_conditions(v,x,y,f,st,contextptr);
step_infolevel(st,contextptr);
return res;
}
// f must be a vector obtained using factors
// x, y are 2 idnt
// xfact and yfact should be initialized to 1
// return true if f=xfact*yfact where xfact depends on x and yfact on y only
bool separate_variables(const gen & f,const gen & x,const gen & y,gen & xfact,gen & yfact,int step_info,GIAC_CONTEXT){
const_iterateur jt=f._VECTptr->begin(),jtend=f._VECTptr->end();
for (;jt!=jtend;jt+=2){
vecteur tmp(*_lname(*jt,contextptr)._VECTptr);
if (equalposcomp(tmp,y)){
if (equalposcomp(tmp,x))
return false;
yfact=yfact*pow(*jt,*(jt+1),contextptr);
}
else
xfact=xfact*pow(*jt,*(jt+1),contextptr);
}
if (step_info)
gprintf("Separable variables d%gen/%gen=%gen*d%gen",makevecteur(y,yfact,xfact,x),step_info,contextptr);
return true;
}
bool separate_variables(const gen & f,const gen & x,const gen & y,gen & xfact,gen & yfact,GIAC_CONTEXT){
return separate_variables(f,x,y,xfact,yfact,step_infolevel(contextptr),contextptr);
}
void ggb_varxy(const gen & f_orig,gen & vx,gen & vy,GIAC_CONTEXT){
vecteur lv=lidnt(f_orig);
vx=vx_var;
vy=y__IDNT_e;
#if 0
if (calc_mode(contextptr)==1){
vx=gen("ggbtmpvarx",contextptr);
vy=gen("ggbtmpvary",contextptr);
}
#endif
for (unsigned i=0;ifeuille;
if (f.type==_VECT){
vecteur w;
for (int j=0;jsize();++j){
gen tmp=desolve_cleanup((*f._VECTptr)[j],x,contextptr);
if (!is_one(tmp))
w.push_back(tmp);
}
return _prod(w,contextptr);
}
}
if (i.is_symb_of_sommet(at_abs) || i.is_symb_of_sommet(at_neg))
return desolve_cleanup(i._SYMBptr->feuille,x,contextptr);
if (is_zero(derive(i,x,contextptr)))
return 1;
return i;
}
// solve linear diff eq of order 1 a*y'+b*y+c=0
static gen desolve_lin1(const gen &a,const gen &b,const gen & c,const gen & x,vecteur & parameters,int step_info,GIAC_CONTEXT){
if (step_info)
gprintf("Linear differential equation of order 1 a*y'+b*y+c=0\na=%gen, b=%gen, c=%gen",makevecteur(a,b,c),step_info,contextptr);
if (a.type==_VECT){
// y'+inv(a)*b(x)*y+inv(a)*c(x)=0
// take laplace transform
// p*Y-Y(0)+bsura*Y+csura=0
// (p+bsura)*Y=Y(0)-csura
int n=int(a._VECTptr->size());
if (!ckmatrix(a) || !ckmatrix(b))
return gensizeerr(contextptr);
gen inva=inv(a,contextptr);
gen bsura=inva*b,csura,cl;
if (!is_zero(derive(bsura,x,contextptr)))
return gensizeerr("Non constant linear differential system");
if (c.type==_VECT){
vecteur & cv=*c._VECTptr;
for (unsigned i=0;isize()==1)
cv[i]=cv[i]._VECTptr->front();
}
csura=inva*c;
cl=_laplace(makesequence(csura,x,x),contextptr);
}
else {
if (!is_zero(c))
return gensizeerr("Invalid second member");
cl=vecteur(n);
}
if (cl.type!=_VECT || int(cl._VECTptr->size())!=n)
return gensizeerr("Invalid second member");
for (int i=0;i y=C(x)exp(-int(b/a)) and a(x)*C'*exp()+c(x)=0
gen & a=v[0];
gen & b=v[1];
gen & c=v[2];
if (ckmatrix(a)){
if (c.type!=_VECT && is_zero(c))
c=c*a;
c=_tran(c,contextptr)[int(a._VECTptr->size())-1];
}
result=desolve_lin1(a,b,c,x,parameters,step_info,contextptr);
return true;
}
// cst coeff?
gen cst=v.back();
v.pop_back();
if (derive(v,x,contextptr)==vecteur(n+1,zero)){
if (step_info)
gprintf("Linear differential equation with constant coefficients\nOrder %gen, coefficients %gen",makevecteur(n,v),step_info,contextptr);
// Yes!
// simpler general solution for small order generic lin diffeq with cst coeff/squarefree case
if (n<=3){
vecteur rac=solve(horner(v,x,contextptr),x,1,contextptr);
comprim(rac);
if (n==2 && rac.size()==1){
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
gen sol = exp(rac.front()*x,contextptr)*(parameters[parameters.size()-2]*x+parameters.back());
if (step_info)
gprintf("Homogeneous solution %gen",makevecteur(sol),step_info,contextptr);
bool b=calc_mode(contextptr)==1;
if (b)
calc_mode(0,contextptr);
gen part=_integrate(makesequence(-cst/v.front()*exp(-rac.front()*x,contextptr),x),contextptr)*x+_integrate(makesequence(cst/v.front()*x*exp(-rac.front()*x,contextptr),x),contextptr);
if (step_info)
gprintf("Particuliar solution %gen",makevecteur(part),step_info,contextptr);
if (b)
calc_mode(1,contextptr);
part=simplify(part*exp(rac.front()*x,contextptr),contextptr);
result=sol+part;
if (step_info)
gprintf("General solution %gen",makevecteur(result),step_info,contextptr);
return true;
}
if (int(rac.size())==n){
gen sol; bool reel=true;
for (int j=0;j=0;--i){
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
tmp=tmp*t+parameters.back();
arbitrary=arbitrary+v[i]*tmp;
}
arbitrary=(laplace_cst+arbitrary)/symb_horner(v,t);
arbitrary=ilaplace(arbitrary,t,x,contextptr);
result=arbitrary;
return true;
}
}
}
if (n==2){ // a(x)*y''+b(x)*y'+c(x)*y+d(x)=0
gen & a=v[0];
gen & b=v[1];
gen & c=v[2];
gen & d=cst;
#if 0
if (is_exactly_zero(c)){
vecteur v1(makevecteur(a,b,d));
if (desolve_linn(x,y,t,1,v1,parameters,result,step_info,contextptr)){
result=_integrate(makesequence(result,x),contextptr);
return true;
}
}
#endif
gen u=-b/a,V=-c/a,w=-d/a,
k=simplify(u*u/4-derive(u,x,contextptr)/2+V,contextptr);
// y''=u*y'+V*y+w (with u,V,w functions of x)
// Pseudo-code from fhub on HP Museum Forum
/*
k:=u^2/4-u'/2+V
if k==const or k*x^2=const then
if k=const
then s:=x; t:=e^(int(u,x)/2);
else u:=u*x+1; k:=u^2/4+V*x^2; s:=ln(x); t:=x^(u/2);
endif;
if k=0 then u:=t*s; V:=t;
elseif k>0 then u:=t*e^(sqrt(k)*s); V:=t*e^(-sqrt(k)*s);
else u:=t*cos(sqrt(-k)*s); V:=t*sin(sqrt(-k)*s);
endif;
w:=w/(u*V'-V*u'); w:=V*int(u*w,x)-u*int(V*w,x);
solution: y=c1*u+c2*V+w
endif
*/
bool cst=is_zero(derive(k,x,contextptr));
bool x2=is_zero(derive(ratnormal(u*x,contextptr),x,contextptr)) && is_zero(derive(ratnormal(v*x*x,contextptr),x,contextptr));
if (cst || x2){
gen s,t;
if (cst){
s=x;
t=simplify(exp(integrate_without_lnabs(u,x,contextptr)/2,contextptr),contextptr);
}
else {
u=u*x+1;
u=simplify(u,contextptr);
k=simplify(u*u/4+V*x*x,contextptr);
s=ln(x,contextptr); t=pow(x,u/2,contextptr);
}
if (is_zero(k)){
u=t*s; V=t;
}
else {
if (is_strictly_positive(-k,contextptr)){
gen tmp=sqrt(-k,contextptr)*s;
u=t*cos(tmp,contextptr);
V=t*sin(tmp,contextptr);
}
else {
if (s.is_symb_of_sommet(at_ln)){
gen tmp=pow(s._SYMBptr->feuille,sqrt(k,contextptr),contextptr);
u=t*tmp;
V=t/tmp;
}
else {
gen tmp=sqrt(k,contextptr)*s;
u=t*exp(tmp,contextptr);
V=t*exp(-tmp,contextptr);
}
}
}
w=simplify(w/(u*derive(V,x,contextptr)-V*derive(u,x,contextptr)),contextptr);
w=V*integrate_without_lnabs(u*w,x,contextptr)-
u*integrate_without_lnabs(V*w,x,contextptr);
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
result=w+parameters[parameters.size()-2]*u+parameters[parameters.size()-1]*V;
return true;
}
// IMPROVE: if a, b, c are polynomials, search for a polynomial solution
// of the homogeneous equation, if found we can solve the diffeq
gen aa(a),bb(b),cc(c);
if (lvarxwithinv(makevecteur(a,b,c),x,contextptr)==vecteur(1,x)){
vecteur l=vecteur(1,x);
gen a0(a),b0(b);
a=_coeff(makesequence(a,x),contextptr);
b=_coeff(makesequence(b,x),contextptr);
c=_coeff(makesequence(c,x),contextptr);
if (a.type==_VECT && b.type==_VECT && c.type==_VECT){
int A=int(a._VECTptr->size())-1,B=int(b._VECTptr->size())-1,C=int(c._VECTptr->size())-1,N=-1;
if (C==B-1){
gen n=-c._VECTptr->front()/b._VECTptr->front();
if (n.type==_INT_ && n.val>N){
if (A-2front(),bb=b._VECTptr->front()-1,cc=c._VECTptr->front();
gen delta=(sqrt(bb*bb-4*aa*cc,contextptr)+bb)/2;
if (delta.type==_INT_ && delta.val>N)
N=delta.val;
}
}
if (A-2==B-1 && Cfront()/a._VECTptr->front()+1;
if (n.type==_INT_ && n.val>N)
N=n.val;
}
if (C==A-2 && B-1front()/a._VECTptr->front(),contextptr))/2;
if (delta.type==_INT_ && delta.val>N)
N=delta.val;
}
if (N>=0){
int nrows=giacmax(giacmax(B,C+1),N==1?0:A)+N;
// search a solution sum(y_k*x*k,k,0,N)
matrice m(nrows);
for (int i=0;isize();++i){
int j=int(a._VECTptr->size())-i-1;
for (int k=2;k<=N;++k){
(*m[j+k-2]._VECTptr)[k] += k*(k-1)*a[i];
}
}
// b*y'
for (int i=0;isize();++i){
int j=int(b._VECTptr->size())-i-1;
for (int k=1;k<=N;++k){
(*m[j+k-1]._VECTptr)[k] += k*b[i];
}
}
// c*y
for (int i=0;isize();++i){
int j=int(c._VECTptr->size())-i-1;
for (int k=0;k<=N;++k){
(*m[j+k]._VECTptr)[k] += c[i];
}
}
m=mker(m,contextptr);
if (!m.empty()){
gen sol=m.front();
if (sol.type==_VECT){
vecteur v=*sol._VECTptr;
reverse(v.begin(),v.end());
sol=symb_horner(-v,x);
*logptr(contextptr) << "Polynomial solution found " << sol << '\n';
// now solve equation a*y''+b*y'+c*y+d=0 with y=sol*z
// a*sol*z''+(2*a*sol'+b*sol)*z'=d
gen res=desolve_lin1(a0*sol,2*a0*derive(sol,x,contextptr)+b0*sol,d,x,parameters,step_info,contextptr);
res=_integrate(makesequence(res,x),contextptr);
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
res += parameters.back();
res=res*sol;
result=res;
return true;
}
}
}
}
} // end polynomial a,b,c
#ifndef USE_GMP_REPLACEMENTS
a=aa; b=bb; c=cc;
if (d==0 && lvarx(makevecteur(a,b,c),x,contextptr)==vecteur(1,x)){
// if a,b,c are rationals and d==0, Kovacic
gen k=_kovacicsols(makesequence(makevecteur(a,b,c),x),contextptr);
if (k.type==_VECT && !k._VECTptr->empty()){
if (k._VECTptr->size()==2){
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
result=parameters[parameters.size()-2]*k._VECTptr->front()+parameters[parameters.size()-1]*k._VECTptr->back();
return true;
}
if (k._VECTptr->size()==1){
// we have one solution Y, find an independent one as z*Y
gen Y=k._VECTptr->front();
// a*(zY)''+b*(zY)'+c*(zY)=0
// a*(z''Y+2z'Y')+b*(z'Y)=0
// z''*(aY)+z'*(2aY'+bY)=0
result=desolve_lin1(a*Y,2*a*derive(Y,x,contextptr)+b*Y,0,x,parameters,step_info,contextptr);
result=_integrate(makesequence(result,x),contextptr);
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
result += parameters.back();
result = result*Y;
return true;
}
}
}
#endif
} // end 2nd order eqdiff
return false;
}
gen desolve_f(const gen & f_orig,const gen & x_orig,const gen & y_orig,int & ordre,vecteur & parameters,gen & fres,int step_info,bool & num,GIAC_CONTEXT){
num=false;
// if x_orig.type==_VECT || y_orig.type==_VECT, they should be evaled
if (x_orig.type!=_VECT && eval(x_orig,1,contextptr)!=x_orig)
return gensizeerr("Independant variable assigned. Run purge("+x_orig.print(contextptr)+")\n");
if (y_orig.type!=_VECT && eval(y_orig,1,contextptr)!=y_orig)
return gensizeerr("Dependant variable assigned. Run purge("+y_orig.print(contextptr)+")\n");
gen x(x_orig);
if ( (x_orig.type==_VECT) && (x_orig._VECTptr->size()==1) )
x=x_orig._VECTptr->front();
if (x.type!=_IDNT){
gen vx,vy;
ggb_varxy(f_orig,vx,vy,contextptr);
if (x_orig.type==_VECT)
return desolve_with_conditions(makevecteur(f_orig,x_orig,y_orig),vx,vy,fres,step_info,contextptr);
else
return desolve_with_conditions(makevecteur(f_orig,makevecteur(x_orig,y_orig)),vx,vy,fres,step_info,contextptr);
}
if (y_orig.type==_VECT) // FIXME: differential system
return gensizeerr(contextptr);
gen f=remove_and(f_orig,at_and);
if (f.type==_VECT){
vecteur fv=*f._VECTptr;
return desolve_with_conditions(fv,x,y_orig,fres,step_info,contextptr);
}
gen y(y_orig),yof(y_orig),partic(undef);
if (y_orig.is_symb_of_sommet(at_equal)){
// particular solution provided
y=y_orig._SYMBptr->feuille[0];
partic=eval(y_orig._SYMBptr->feuille[1],1,contextptr);
}
if (y.type==_IDNT){
yof=symb_of(y,gen(vecteur(1,x),_SEQ__VECT));
f=quotesubst(f,yof,y,contextptr);
f=quotesubst(f,y,yof,contextptr);
}
else
y=function_of(y_orig,x);
if (is_undef(y))
return y;
gen save_vx=vx_var;
vx_var=x;
int save=calc_mode(contextptr);
calc_mode(0,contextptr);
#ifdef GIAC_HAS_STO_38
// HP Prime: if there is a M0-M9 identifier, this will not work
vecteur fid(lidnt(f));
for (unsigned i=0;iid_name;
if (strlen(ch)==2 && ch[0]=='M' && ch[1]>='0' && ch[1]<='9')
return gensizeerr("Home matrix variable "+ string(ch)+" not allowed. Store your matrix in a CAS variable first");
}
}
#endif
f=remove_equal(eval(f,eval_level(contextptr),contextptr));
num=has_num_coeff(f);
if (num)
f=exact(f,contextptr);
if (ckmatrix(f)){
vecteur v = *f._VECTptr;
for (int i=0;i1 && !is_undef(partic)){
// reduce order by one
vecteur s(n,partic);
for (int i=1;isize(),p);
sol=integrate_without_lnabs(sol,x,contextptr)+p;
return sol;
}
if (n==1) { // 1st order
vecteur sol;
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
f=quotesubst(f,symb_derive(y,x),t,contextptr);
// f is an expression of x,y,t where t stands for y'
gen fa,fb,fc,fd,faa,fab;
// Test for Lagrange/Clairault-like eqdiff,
if (x.type==_IDNT && y.type==_IDNT && is_linear_wrt(f,y,fc,fd,contextptr) && is_linear_wrt(fd,x,fa,fb,contextptr)){
// Clairault: fa must be cst*t and fc must be cst (must simplify fa and fc)
// f=y*fc+(fa*x+fb)
fd=gcd(fc,fa);
fa=normal(fa/fd,contextptr); fb=normal(fb/fd,contextptr); fc=normal(fc/fd,contextptr);
if (is_linear_wrt(fa,t,faa,fab,contextptr) && is_zero(fab) && derive(faa,makevecteur(x,y,t),contextptr)==vecteur(3,0) && derive(fc,makevecteur(x,y,t),contextptr)==vecteur(3,0) && derive(fb,makevecteur(x,y),contextptr)==vecteur(2,0)){
// 0=f=fc*y+fd = fc*y+fa*x+fb = fc*y+faa*x*y'+fb
// -> y=-faa/fc*x*y' -fb/fc
if (is_one(ratnormal(-faa/fc,contextptr))){
if (step_info)
gprintf("Order 1 Clairault differential equation",vecteur(0),step_info,contextptr);
// y=x*y'-fb/fc
gen fm=ratnormal(-fb/fc,contextptr);
gen fmp=derive(fm,t,contextptr);
sol.push_back(parameters.back()*x+subst(fm,t,parameters.back(),false,contextptr));
sol.push_back(makevecteur(-fmp,-t*fmp+fm));
return sol;
}
}
// Lagrange-> fa/fb/fc dependent de t uniquement, if fb==0 -> separate var or homogeneous
if (is_zero(derive(makevecteur(fa,fb,fc),x,contextptr)) && !is_zero(fb)){
if (step_info)
gprintf("Order 1 Lagrange differential equation",vecteur(0),step_info,contextptr);
// y+fa/fc*x+fb/fc=0
fa=fa/fc; fb=fb/fc;
// y+fa*x+fb=0
// t=dy/dx, dy/dt=t*dx/dt => t*dx/dt+fa'*x+fb'+fa*dx/dt
// linear equation 1st order (fa+t)*dx/dt+fa'*x+fb'=0
gen res=desolve_lin1(fa+t,derive(fa,t,contextptr),derive(fb,t,contextptr),t,parameters,step_info,contextptr);
vecteur sing(solve(t+fa,t,3,contextptr));
for (int i=0;ifeuille))+prb,contextptr);
}
else
pr=parameters.back()+pr;
#else
if (has_op(pr,*at_ln))
pr=_lncollect(pr,contextptr); // hack to solve y'=y*(1-y)
if (pr.is_symb_of_sommet(at_ln))
pr=symbolic(at_ln,parameters.back()*pr._SYMBptr->feuille);
else
pr=parameters.back()+pr;
#endif
gen implicitsol=pr-integrate_without_lnabs(xfact,x,contextptr);
#ifdef NO_STDEXCEPT
vecteur newsol=solve(implicitsol,*y._IDNTptr,3,contextptr);
if (is_undef(newsol)){
newsol.clear();
*logptr(contextptr) << "Unable to solve implicit equation "<< implicitsol << "=0 in " << y << '\n';
}
#else
vecteur newsol;
int cm=calc_mode(contextptr);
calc_mode(0,contextptr);
try {
newsol=solve(implicitsol,*y._IDNTptr,3,contextptr);
} catch(std::runtime_error & err){
last_evaled_argptr(contextptr)=NULL;
newsol.clear();
*logptr(contextptr) << "Unable to solve implicit equation "<< implicitsol << "=0 in " << y << '\n';
}
calc_mode(cm,contextptr);
#endif
sol=mergevecteur(sol,newsol);
continue;
} // end separate variables
if (is_zero(derive(*it,x,contextptr))){ // x incomplete
if (step_info)
gprintf("Order 1 x-incomplete differential equation",vecteur(0),step_info,contextptr);
if (debug_infolevel)
*logptr(contextptr) << gettext("Incomplete") << '\n';
gen pr=integrate_without_lnabs(inv(*it,contextptr),y,contextptr)+parameters.back();
sol=mergevecteur(sol,solve(pr-x,*y._IDNTptr,3,contextptr));
continue;
}
// check for a linear substitution -> like an x incomplete
fa=derive(*it,x,contextptr); fb=derive(*it,y,contextptr);
fc=simplify(fa/fb,contextptr);
if (is_zero(derive(fc,x,contextptr)) && is_zero(derive(fc,y,contextptr))){
gen eff=subst(*it,y,y-fc*x,false,contextptr); // does not depend on x
gen pr=integrate_without_lnabs(inv(eff+fc,contextptr),y,contextptr)+parameters.back();
pr=subst(pr,y,y+fc*x,false,contextptr);
vecteur l1=lop(lvarx(pr,y),at_floor);
if (!l1.empty()){
vecteur l2(l1.size());
pr=subst(pr,l1,l2,false,contextptr);
}
vecteur sol1=solve(pr-x,*y._IDNTptr,3,contextptr);
sol=mergevecteur(sol,sol1);
continue;
}
// homogeneous?
gen tplus(t);
gen tmpsto=sto(doubleassume_and(vecteur(2,0),0,1,false,contextptr),tplus,contextptr);
if (is_undef(tmpsto))
return tmpsto;
f=quotesubst(*it,makevecteur(x,y),makevecteur(tplus*x,tplus*y),contextptr);
f=recursive_normal(f-*it,contextptr);
purgenoassume(tplus,contextptr);
if (is_zero(f)){
if (step_info)
gprintf("Order 1 Homogeneous differential equation",vecteur(0),step_info,contextptr);
if (debug_infolevel)
*logptr(contextptr) << gettext("Homogeneous differential equation") << '\n';
tmpsto=sto(doubleassume_and(vecteur(2,0),0,1,false,contextptr),x,contextptr);
if (is_undef(tmpsto))
return tmpsto;
f=recursive_normal(quotesubst(*it,y,tplus*x,contextptr)-tplus,contextptr);
purgenoassume(x,contextptr);
// y=tx -> t'x=f
// Singular solutions f(t)=0
vecteur singuliere(multvecteur(x,solve(f,t,complex_mode(contextptr) + 2,contextptr)));
sol=mergevecteur(sol,singuliere);
// Non singular: t'/f(t)=1/x
gen pr=parameters.back()*_simplify(exp(integrate_without_lnabs(inv(f,contextptr),t,contextptr),contextptr),contextptr);
// Try to find t in x=pr
vecteur v=protect_solve(x-pr,*t._IDNTptr,1,contextptr);
if (!v.empty() && !is_undef(v)){
*logptr(contextptr) << "solve(" << pr << "=" << x << "," << t << ") returned " << v << ".\nIf solutions were missed consider paramplot(" << makevecteur(pr,t*pr) << "," << t << ")" << '\n';
for (unsigned j=0;j N dy + M dx=0 where -M/N=y'
gen M,N;
f=_fxnd(*it,contextptr);
M=-f[0];
N=f[1];
// find an integrating factor P such that d_x(P*N)=d_y(P*M)
// If P depends on x then N*d_x(P)+Pd_x(N)=Pd_y(M) ->
// d_x(P)/P=(d_y(M)-d_x(N))/N should depend on x only
// If P depends on y then P d_x(N)=Pd_y(M)+Md_y(P)
// d_y(P)/P=(d_x(N)-d_y(M))/M
// Then solve P*Ndy+P*Mdx=dF
f=normal((derive(M,y,contextptr)-derive(N,x,contextptr))/N,contextptr);
if (is_zero(derive(f,y,contextptr))){
gen P=simplify(exp(integrate_without_lnabs(f,x,contextptr),contextptr),contextptr);
// D_y(F)=P*N
gen F=P*integrate_without_lnabs(N,y,contextptr);
if (step_info)
gprintf("Order 1 Integrating factor %gen",makevecteur(P),step_info,contextptr);
// D_x(F)=P*M
parameters.push_back(diffeq_constante(int(parameters.size()),contextptr));
F=F+integrate_without_lnabs(normal(P*M-derive(F,x,contextptr),contextptr),x,contextptr)+parameters.back();
sol=mergevecteur(sol,solve(F,*y._IDNTptr,3,contextptr));
continue;
}
f=normal((derive(N,x,contextptr)-derive(M,y,contextptr))/M,contextptr);
if (is_zero(derive(f,x,contextptr))){
gen P=simplify(exp(integrate_without_lnabs(f,y,contextptr),contextptr),contextptr);
gen F=P*integrate_without_lnabs(M,x,contextptr);
// D_y(F)=P*N
if (step_info)
gprintf("Order 1 Integrating factor %gen",makevecteur(P),step_info,contextptr);
F=F+integrate_without_lnabs(normal(P*N-derive(F,y,contextptr),contextptr),y,contextptr)+diffeq_constante(int(parameters.size()),contextptr);
sol=mergevecteur(sol,solve(F,*y._IDNTptr,3,contextptr));
continue;
}
// Bernoulli?
// y'=a(x)*y+b(x)*y^k
// Let z=y^(1-k)
// z'=(1-k)*y^(-k)*y'=(1-k)*[a(x)*z+b(x)]
// Solve for z then for y
f=subst(*it,y,2*y,false,contextptr);
f=factors(f-2*(*it),vx_var,contextptr); // should be (2^k-2)*b(x)*y^k
xfact=plus_one;
yfact=plus_one;
if (separate_variables(f,x,y,xfact,yfact,step_info,contextptr)){
// xfact should be (2^k-2)*b(x) and yfact=y^k
if ( (yfact.type==_SYMB) && (yfact._SYMBptr->sommet==at_pow) &&
(yfact._SYMBptr->feuille._VECTptr->front()==y) ){
if (step_info)
gprintf("Order 1 Bernoulli differential equation",vecteur(0),step_info,contextptr);
gen k=yfact._SYMBptr->feuille._VECTptr->back();
gen B=normal(xfact/(pow(plus_two,k,contextptr)-plus_two),contextptr);
gen A=normal((*it-B*pow(y,k,contextptr))/y,contextptr);
gen b=(k-1)*A;
gen c=(k-1)*B;
gen i=simplify(integrate_without_lnabs(b,x,contextptr),contextptr);
gen C=integrate_without_lnabs(-c*exp(i,contextptr),x,contextptr);
f= (C+parameters.back())*exp(-i,contextptr);
gen sol1=pow(f,inv(1-k,contextptr),contextptr);
sol.push_back(sol1);
// FIXME: we should add other roots of unity in complex mode
if (k.type==_INT_ && k.val %2)
sol.push_back(-sol1);
}
}
// Ricatti f=*it quadratic in y
gen P,Q,R;
if (is_quadratic_wrt(*it,y,R,Q,P,contextptr)){
if (step_info)
gprintf("Order 1 Riccati differential equation",vecteur(0),step_info,contextptr);
gen result;
// y'=P+Q*y+R*y^2=q0+q1*y+q2*y^2
if (!is_undef(partic)){
// z'+(q1+2*q2*partic)*z+q2=0
result=desolve_lin1(1,Q+2*R*partic,R,x,parameters,step_info,contextptr);
return makevecteur(partic,partic+inv(result,contextptr));
}
// let y=-1/(R*F)*dF/dx, then F''-(1/R*R'+Q)*F'+R*P*F=0
vecteur v(makevecteur(1,-normal(Q+derive(R,x,contextptr)/R,contextptr),normal(R*P,contextptr),0));
if (desolve_linn(x,y,t,2,v,parameters,result,step_info,contextptr)){
result=lnexpand(ln(result,contextptr),contextptr);
result=-derive(result,x,contextptr)/R;
result=ratnormal(result,contextptr);
gen lastp=parameters.back();
parameters.pop_back();
gen partic=subst(result,lastp,0,false,contextptr);
partic=ratnormal(partic,contextptr);
result=subst(result,lastp,1,false,contextptr);
result=ratnormal(result,contextptr);
//result=-derive(result,x,contextptr)/(R*result);
return makevecteur(partic,result);
}
}
} // end for (;it!=itend;)
return sol;
} // end if n==1
if (n==2){
// y''=f(y,y'), set u=y' -> u'=f(y,u)/u
gen der1=substout[0],der2=substout[1];
gen soly2=_cSolve(makesequence(symb_equal(ff,0),der2),contextptr);
vecteur paramsave=parameters;
if (soly2.type==_VECT && !is_undef(soly2)){
vecteur sol;
const vecteur & soly2v = *soly2._VECTptr;
for (unsigned i=0;isize();++j){
parameters=paramsavein;
gen usolj=(*usol._VECTptr)[j];
gen ysol=desolve(symb_equal(symbolic(at_derive,makesequence(y,x)),usolj),x,y,ordre,parameters,contextptr);
if (is_undef(ysol))
return unable_to_solve_diffeq();
sol=mergevecteur(sol,gen2vecteur(ysol));
}
continue;
} // end x-incomplete
gen res(string2gen(gettext("Unable to solve differential equation"),false));
res.subtype=-1;
sol.push_back(res);
}
ordre=2;
return sol;
}
}
return unable_to_solve_diffeq();
}
gen ggbputinlist(const gen & g,GIAC_CONTEXT){
if (g.type==_VECT || calc_mode(contextptr)!=1)
return g;
return makevecteur(g);
}
static gen point2vecteur(const gen & g_,GIAC_CONTEXT){
if (!g_.is_symb_of_sommet(at_point))
return g_;
gen g=g_._SYMBptr->feuille;
gen x,y;
if (g.type==_VECT){
if (g._VECTptr->size()!=2)
return gensizeerr(contextptr);
x=g._VECTptr->front();
y=g._VECTptr->back();
}
else
reim(g,x,y,contextptr);
g=makevecteur(x,y);
return g;
}
// "unary" version
gen _desolve(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
//if (has_num_coeff(args)) return evalf(_desolve(exact(args,contextptr),contextptr),1,contextptr);
int ordre;
vecteur parameters;
if (args.type!=_VECT || args.subtype!=_SEQ__VECT || (!args._VECTptr->empty() && is_equal(args._VECTptr->back()) && args._VECTptr->back()._SYMBptr->feuille[0].type!=_IDNT)){
// guess x and y
vecteur lv(lop(args,at_of));
vecteur f;
if (lv.size()>=1 && lv[0]._SYMBptr->feuille.type==_VECT && (f=*lv[0]._SYMBptr->feuille._VECTptr).size()==2){
if (f[1].type==_IDNT || f[1].is_symb_of_sommet(at_at)){
return desolve(args,f[1],f[0],ordre,parameters,contextptr);
}
}
gen vx,vy;
lv=lidnt(evalf(args,1,contextptr));
if (lv.size()==2){
vx=lv[0];
vy=lv[1];
lv=lvar(apply(args,equal2diff));
lv=lop(lv,at_derive);
lv=lidnt(lv);
if (lv.size()==1 && vx==lv.front())
swapgen(vx,vy);
return _desolve(makesequence(args,vx,vy),contextptr);
}
ggb_varxy(args,vx,vy,contextptr);
return _desolve(makesequence(args,vx,vy),contextptr);
}
vecteur v=*args._VECTptr;
int s=int(v.size());
for (int i=0;isize()==2){
gen a=eval(v[1]._VECTptr->front(),1,contextptr);
gen b=eval(v[1]._VECTptr->back(),1,contextptr);
v[1]=a;
v.insert(v.begin()+2,b);
++s;
}
if (s==2){
if ( (v[1].type==_SYMB && v[1]._SYMBptr->sommet==at_of && v[1]._SYMBptr->feuille.type==_VECT &&v [1]._SYMBptr->feuille._VECTptr->size()==2 ) )
return desolve(v[0],(*v[1]._SYMBptr->feuille._VECTptr)[1],(*v[1]._SYMBptr->feuille._VECTptr)[0],ordre,parameters,contextptr);
return ggbputinlist(desolve( v[0],vx_var,v[1],ordre,parameters,contextptr),contextptr);
}
gen f;
if (s==4)
return ggbputinlist(desolve_with_conditions(makevecteur(v[0],v[3]),v[1],v[2],f,contextptr),contextptr);
if (s==5)
return ggbputinlist(desolve_with_conditions(makevecteur(v[0],v[3],v[4]),v[1],v[2],f,contextptr),contextptr);
if (s!=3)
return gensizeerr(contextptr);
return ggbputinlist(desolve( v[0],v[1],v[2],ordre,parameters,contextptr),contextptr);
}
static const char _desolve_s []="desolve";
static define_unary_function_eval_quoted (__desolve,&_desolve,_desolve_s);
define_unary_function_ptr5( at_desolve ,alias_at_desolve,&__desolve,1,true);
static const char _dsolve_s []="dsolve";
static define_unary_function_eval_quoted (__dsolve,&_desolve,_dsolve_s);
define_unary_function_ptr5( at_dsolve ,alias_at_dsolve,&__dsolve,_QUOTE_ARGUMENTS,true);
gen ztrans(const gen & f,const gen & x,const gen & s,GIAC_CONTEXT){
if (x.type!=_IDNT)
return gensizeerr(contextptr);
gen t(s);
if (s==x){
#ifdef GIAC_HAS_STO_38
t=identificateur("z38_");
#else
t=identificateur(" tztrans");
#endif
}
if (!assume_t_in_ab(t,plus_inf,plus_inf,true,true,contextptr))
return gensizeerr(contextptr);
gen tmp=expand(f*pow(t,-x,contextptr),contextptr);
gen res=_sum(gen(makevecteur(tmp,x,0,plus_inf),_SEQ__VECT),contextptr);
purgenoassume(t,contextptr);
if (s==x)
res=subst(res,t,x,false,contextptr);
return ratnormal(res,contextptr);
}
gen desolve(const gen & f_orig,const gen & x_orig,const gen & y_orig,int & ordre,vecteur & parameters,GIAC_CONTEXT){
gen f;
gen x(x_orig),y(y_orig);
if (x.is_symb_of_sommet(at_unquote))
x=eval(x,1,contextptr);
if (y.is_symb_of_sommet(at_unquote))
y=eval(y,1,contextptr);
int st=step_infolevel(contextptr);
step_infolevel(0,contextptr);
bool num=false;
gen res=desolve_f(f_orig,x,y,ordre,parameters,f,st,num,contextptr);
if (num)
res=evalf(res,1,contextptr);
step_infolevel(st,contextptr);
return res;
}
// "unary" version
gen _ztrans(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type!=_VECT)
return ztrans(args,vx_var,vx_var,contextptr);
vecteur & v=*args._VECTptr;
int s=int(v.size());
if (s==2)
return ztrans( v[0],v[1],v[1],contextptr);
if (s!=3)
return gensizeerr(contextptr);
return ztrans( v[0],v[1],v[2],contextptr);
}
static const char _ztrans_s []="ztrans";
static define_unary_function_eval (__ztrans,&_ztrans,_ztrans_s);
define_unary_function_ptr5( at_ztrans ,alias_at_ztrans,&__ztrans,0,true);
static gen invztranserr(GIAC_CONTEXT){
return gensizeerr(gettext("Inverse z-transform of non rational functions not implemented or unable to fully factor rational function"));
}
// limited to rational fractions
gen invztrans(const gen & f,const gen & x,const gen & s,GIAC_CONTEXT){
if (x.type!=_IDNT)
return gensizeerr(contextptr);
gen t(s);
if (s==x){
#ifdef GIAC_HAS_STO_38
t=identificateur("s38_");
#else
t=identificateur(" tinvztrans");
#endif
}
vecteur varx(lvarx(f,x));
int varxs=int(varx.size());
gen res;
if (varxs==0)
res=f*_Kronecker(t,contextptr);
else {
if (varxs>1)
return invztranserr(contextptr);
res=f/x;
vecteur l;
l.push_back(x); // insure x is the main var
l.push_back(t); // s var as second var
l=vecteur(1,l);
alg_lvar(res,l);
vecteur lprime(l);
if (lprime.front().type!=_VECT) return gensizeerr(gettext("desolve.cc/invztrans"));
lprime.front()=cdr_VECT(*(lprime.front()._VECTptr));
gen glap=e2r(s,l,contextptr);
if (glap.type!=_POLY) return gensizeerr(gettext("desolve.cc/invztrans"));
int dim=int(l.front()._VECTptr->size());
if (!dim){
l.erase(l.begin());
dim=int(l.front()._VECTptr->size());
}
gen r=e2r(res,l,contextptr);
res=0;
gen r_num,r_den;
fxnd(r,r_num,r_den);
if (r_num.type==_EXT)
return invztranserr(contextptr);
if (r_den.type!=_POLY)
return invztranserr(contextptr);
polynome den(*r_den._POLYptr),num(dim);
if (r_num.type==_POLY)
num=*r_num._POLYptr;
else
num=polynome(r_num,dim);
polynome p_content(lgcd(den));
den=den/p_content;
factorization vden; gen an;
gen extra_div;
if (!cfactor(den,an,vden,true,extra_div))
return invztranserr(contextptr);
vector< pf > pfde_VECT;
polynome ipnum(dim),ipden(dim);
partfrac(num,den,vden,pfde_VECT,ipnum,ipden);
if (!is_zero(ipnum))
*logptr(contextptr) << gettext("Warning, z*argument has a non-zero integral part") << '\n';
vector< pf >::iterator it=pfde_VECT.begin();
vector< pf >::const_iterator itend=pfde_VECT.end();
gen a,A,B;
polynome b,c;
for (;it!=itend;++it){
if (it->fact.lexsorted_degree()>1)
return invztranserr(contextptr);
findde(it->fact,b,c);
a=-gen(c)/gen(b); // pole
B=r2e(Tfirstcoeff(it->den),l,contextptr);
if (is_zero(a)){
int mult=it->mult;
gen res0;
vecteur vnum;
polynome2poly1(it->num,1,vnum);
for (int i=0;inum/it->den in terms of 1/(z-a), a/(z-a)^2, a^2/(z-a)^3, etc.
gen cur=r2e(it->num,l,contextptr);
A=r2e(a,lprime,contextptr);
gen z_minus_a=x-A,res0;
for (int i=it->mult-1;i>=0;--i){
gen tmp=_quorem(makesequence(cur,z_minus_a,x),contextptr);
if (is_undef(tmp)) return tmp;
gen rem=tmp[1];
cur=tmp[0];
rem=rem/pow(A,i,contextptr)/factorial(i);
for (int j=0;jfeuille,s,a,b,contextptr)){
// res==A*Kronecker(a*x+b)+B
if (is_one(a) && is_zero(b)){
gen B0=subst(B,s,0,false,contextptr);
if (is_zero(ratnormal(B0+A,contextptr)))
res=B*symbolic(at_Heaviside,s-1);
}
}
return res;
}
gen _invztrans(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type!=_VECT)
return invztrans(args,vx_var,vx_var,contextptr);
vecteur & v=*args._VECTptr;
int s=int(v.size());
if (s==2)
return invztrans( v[0],v[1],v[1],contextptr);
if (s!=3)
return gensizeerr(contextptr);
return invztrans( v[0],v[1],v[2],contextptr);
}
static const char _invztrans_s []="invztrans";
static define_unary_function_eval (__invztrans,&_invztrans,_invztrans_s);
define_unary_function_ptr5( at_invztrans ,alias_at_invztrans,&__invztrans,0,true);
gen _Kronecker(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT)
return apply(args,_Kronecker,contextptr);
if (!is_integer(args))
return symbolic(at_Kronecker,args);
if (is_zero(args))
return 1;
else
return 0;
}
static const char _Kronecker_s []="Kronecker";
static define_unary_function_eval (__Kronecker,&_Kronecker,_Kronecker_s);
define_unary_function_ptr5( at_Kronecker ,alias_at_Kronecker,&__Kronecker,0,true);
#ifndef USE_GMP_REPLACEMENTS
// this code slice (c) 2018 Luka Marohnić
/* returns the coefficient of t in (fraction, Taylor or Laurent) expansion e */
gen expansion_coeff(const gen &e,const gen &t,GIAC_CONTEXT) {
gen ret(0),g;
if (e.is_symb_of_sommet(at_plus) && e._SYMBptr->feuille.type==_VECT) {
const vecteur &feu=*e._SYMBptr->feuille._VECTptr;
for (const_iterateur it=feu.begin();it!=feu.end();++it) {
g=_ratnormal(*it/t,contextptr);
if (_evalf(g,contextptr).type==_DOUBLE_) {
ret=g;
break;
}
}
} else {
g=_ratnormal(e/t,contextptr);
if (_evalf(g,contextptr).type==_DOUBLE_)
ret=g;
}
return ret;
}
bool kovacic_iscase1(const vecteur &poles,int dinf) {
if (dinf%2!=0 && dinf<=2)
return false;
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
int order=it->_VECTptr->back().val;
if (order%2!=0 && order!=1)
return false;
}
return true;
}
bool kovacic_iscase2(const vecteur &poles) {
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
int order=it->_VECTptr->back().val;
if (order==2 || (order>2 && order%2!=0))
return true;
}
return false;
}
bool kovacic_iscase3(const gen &cpfr,const gen &x,const vecteur &poles,int dinf,GIAC_CONTEXT) {
if (dinf<2)
return false;
vecteur alpha,beta;
gen a,b,g(0),p;
int d;
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
p=it->_VECTptr->front();
d=it->_VECTptr->back().val;
if (d>2)
return false;
if (d>1) {
alpha.push_back(a=expansion_coeff(cpfr,pow(x-p,-2),contextptr));
g+=a;
a=_eval(sqrt(1+4*a,contextptr),contextptr);
if (!_numer(a,contextptr).is_integer() || !_denom(a,contextptr).is_integer())
return false;
}
beta.push_back(b=expansion_coeff(cpfr,_inv(x-p,contextptr),contextptr));
g+=b*p;
}
g=_eval(sqrt(1+4*g,contextptr),contextptr);
return is_zero(_ratnormal(_sum(beta,contextptr),contextptr)) &&
_numer(g,contextptr).is_integer() && _denom(g,contextptr).is_integer();
}
void build_E_families(const gen_map &E,const vecteur &cv,vecteur &family,matrice &families) {
int i=family.size();
if (i>=int(cv.size()))
return;
const vecteur ev=*E.find(cv[i])->second._VECTptr;
for (const_iterateur it=ev.begin();it!=ev.end();++it) {
family.push_back(*it);
if (family.size()==cv.size())
families.push_back(family);
else build_E_families(E,cv,family,families);
family.pop_back();
}
}
void create_identifiers(vecteur &vars,int n) {
vars.reserve(n);
stringstream ss;
for (int i=0;ifeuille;
if (g.type==_SYMB) {
gen args;
if (g._SYMBptr->feuille.type==_VECT) {
args=vecteur(0);
const vecteur &feu=*g._SYMBptr->feuille._VECTptr;
for (const_iterateur it=feu.begin();it!=feu.end();++it) {
args._VECTptr->push_back(strip_abs(*it));
}
} else args=strip_abs(g._SYMBptr->feuille);
return symbolic(g._SYMBptr->sommet,args);
}
return g;
}
gen explnsimp(const gen &g,GIAC_CONTEXT) {
gen e=expand(strip_abs(g),contextptr);
e=symbolic(at_exp2pow,symbolic(at_expexpand,symbolic(at_lncollect,e)));
return ratnormal(_lin(_eval(e,contextptr),contextptr),contextptr);
}
bool isroot(const gen &g,gen °,GIAC_CONTEXT) {
if (!g.is_symb_of_sommet(at_pow))
return false;
const gen &pw=g._SYMBptr->feuille._VECTptr->at(1);
return (deg=_inv(pw,contextptr)).is_integer() && !is_minus_one(deg);
}
void partialrad(const gen &g,const gen °,gen &outside,gen &inside,bool isdenom,GIAC_CONTEXT) {
gen s;
if (g.is_integer() && (s=_pow(makesequence(g,_inv(deg,contextptr)),contextptr)).is_integer()) {
outside=outside*(isdenom?_inv(s,contextptr):s);
} else if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) {
vecteur &fv=*g._SYMBptr->feuille._VECTptr,qr;
for (const_iterateur it=fv.begin();it!=fv.end();++it) {
if (it->is_integer()) {
s=_pow(makesequence(*it,_inv(deg,contextptr)),contextptr);
outside=outside*(isdenom?_inv(s,contextptr):s);
continue;
} else if (it->is_symb_of_sommet(at_pow)) {
const gen &pw=it->_SYMBptr->feuille._VECTptr->at(1);
const gen &b=it->_SYMBptr->feuille._VECTptr->front();
if (pw.is_integer()) {
qr=*_iquorem(makesequence(pw,deg),contextptr)._VECTptr;
if (isdenom) {
outside=outside/_pow(makesequence(b,qr.front()),contextptr);
inside=inside/_pow(makesequence(b,qr.back()),contextptr);
} else {
outside=outside*_pow(makesequence(b,qr.front()),contextptr);
inside=inside*_pow(makesequence(b,qr.back()),contextptr);
}
continue;
}
} else if (it->is_symb_of_sommet(at_inv)) {
partialrad(it->_SYMBptr->feuille,deg,outside,inside,!isdenom,contextptr);
continue;
}
inside=inside*(isdenom?_inv(*it,contextptr):*it);
}
} else if (g.is_symb_of_sommet(at_inv))
partialrad(g._SYMBptr->feuille,deg,outside,inside,!isdenom,contextptr);
else inside=inside*(isdenom?_inv(g,contextptr):g);
}
gen radsimp(const gen &g,GIAC_CONTEXT) {
gen deg;
if (g.type==_VECT) {
vecteur ret;
for (const_iterateur it=g._VECTptr->begin();it!=g._VECTptr->end();++it) {
ret.push_back(radsimp(*it,contextptr));
}
return change_subtype(ret,g.subtype);
}
if (isroot(g,deg,contextptr)) {
gen radic=_collect(radsimp(g._SYMBptr->feuille._VECTptr->front(),contextptr),contextptr);
gen inside(1),outside(1),inum;
partialrad(radic,deg,outside,inside,false,contextptr);
gen ideg=_inv(deg,contextptr);
inside=_eval(symb_normal(inside),contextptr);
if (!(inum=_eval(_pow(makesequence(_numer(inside,contextptr),ideg),contextptr),contextptr)).is_symb_of_sommet(at_pow) ||
inum._SYMBptr->feuille._VECTptr->at(1).is_integer())
return _collect(outside,contextptr)*inum/_pow(makesequence(_collect(_denom(inside,contextptr),contextptr),ideg),contextptr);
return _collect(outside,contextptr)*_pow(makesequence(_collect(inside,contextptr),ideg),contextptr);
}
if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) {
vecteur &feu=*g._SYMBptr->feuille._VECTptr,degv;
gen den(1);
for (const_iterateur it=feu.begin();it!=feu.end();++it) {
if (it->is_symb_of_sommet(at_pow)) {
gen dg=_inv(it->_SYMBptr->feuille._VECTptr->at(1),contextptr);
if (is_greater(dg,2,contextptr))
degv.push_back(dg);
} else if (it->is_symb_of_sommet(at_inv))
den=den*it->_SYMBptr->feuille;
}
if (den.is_symb_of_sommet(at_prod) && den._SYMBptr->feuille.type==_VECT) {
vecteur &dfeu=*den._SYMBptr->feuille._VECTptr;
for (const_iterateur it=dfeu.begin();it!=dfeu.end();++it) {
if (it->is_symb_of_sommet(at_pow)) {
gen dg=_inv(it->_SYMBptr->feuille._VECTptr->at(1),contextptr);
if (is_greater(dg,2,contextptr))
degv.push_back(dg);
}
}
}
gen gd=_lcm(degv,contextptr);
gen p=_collect(ratnormal(pow(g,gd.val),contextptr),contextptr);
if (p.is_symb_of_sommet(at_pow)) {
gen ppw=p._SYMBptr->feuille._VECTptr->at(1);
if (ppw.is_integer())
gd=_eval(gd/ppw,contextptr);
}
gen ret=_pow(makesequence(p,_inv(gd,contextptr)),contextptr);
return isroot(ret,deg,contextptr)?radsimp(ret,contextptr):ratnormal(ret,contextptr);
}
if (g.type==_SYMB) {
gen &feu=g._SYMBptr->feuille;
if (feu.type==_VECT) {
vecteur res;
for (const_iterateur it=feu._VECTptr->begin();it!=feu._VECTptr->end();++it) {
res.push_back(radsimp(*it,contextptr));
}
return symbolic(g._SYMBptr->sommet,change_subtype(res,feu.subtype));
}
return symbolic(g._SYMBptr->sommet,radsimp(feu,contextptr));
}
return g;
}
vecteur strip_gcd(const vecteur &v,GIAC_CONTEXT) {
gen g1=_gcd(_apply(makesequence(at_numer,v),contextptr),contextptr);
gen g2=_gcd(_apply(makesequence(at_denom,v),contextptr),contextptr);
return *_collect(_ratnormal(multvecteur(g2/g1,v),contextptr),contextptr)._VECTptr;
}
gen ratsimp_nonexp(const gen &g,GIAC_CONTEXT) {
if (g.type==_VECT) {
vecteur res;
for (const_iterateur it=g._VECTptr->begin();it!=g._VECTptr->end();++it) {
res.push_back(ratsimp_nonexp(*it,contextptr));
}
return change_subtype(res,g.subtype);
}
if (g.is_symb_of_sommet(at_plus) && g._SYMBptr->feuille==_VECT) {
vecteur &terms=*g._SYMBptr->feuille._VECTptr;
gen res(0);
for (const_iterateur it=terms.begin();it!=terms.end();++it) {
res+=ratsimp_nonexp(*it,contextptr);
}
return res;
}
if (g.is_symb_of_sommet(at_prod) && g._SYMBptr->feuille.type==_VECT) {
vecteur &facs=*g._SYMBptr->feuille._VECTptr;
gen e(1),ne(1);
for (const_iterateur it=facs.begin();it!=facs.end();++it) {
if (it->is_symb_of_sommet(at_exp))
e=*it*e;
else ne=*it*ne;
}
return _ratnormal(ne,contextptr)*e;
}
return g;
}
gen fullsimp(const gen &g,GIAC_CONTEXT) {
return ratsimp_nonexp(_collect(radsimp(explnsimp(exp(_ratnormal(g,contextptr),contextptr),
contextptr),contextptr),contextptr),contextptr);
}
/*
* This routine solves the general homogeneous linear second-order ODE
* y''=r(t)*y, where r is a non-constant rational function, using Kovacic's
* algorithm (https://core.ac.uk/download/pdf/82509765.pdf). A list of
* solutions is returned (possibly empty).
*/
gen kovacicsols(const gen &r_orig,const gen &x,const gen &dy_coeff,GIAC_CONTEXT) {
gen r=_ratnormal(r_orig,contextptr),inf=symbolic(at_plus,_IDNT_infinity());
gen s=_numer(r,contextptr),t=_denom(r,contextptr),a,b,c,e,w=identificateur("omega_");
int ds=_degree(makesequence(s,x),contextptr).val;
int dt=_degree(makesequence(t,x),contextptr).val,dinf=dt-ds,order,nu;
vecteur poles=*_roots(makesequence(t,x),contextptr)._VECTptr,solutions(0);
gen cpfr=_cpartfrac(makesequence(r,x),contextptr);
gen laur=_series(makesequence(r,x,inf,1,_POLY1__VECT),contextptr);
bool success=false;
if (kovacic_iscase1(poles,dinf)) {
cerr << "Case 1 of Kovacic algorithm" << '\n';
/* step 1 */
gen_map alpha_plus,alpha_minus,sqrt_r;
gen alpha_inf_plus,alpha_inf_minus;
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
c=it->_VECTptr->front();
order=it->_VECTptr->back().val;
if (order==1) {
sqrt_r[c]=0;
alpha_plus[c]=alpha_minus[c]=1;
} else if (order==2) {
sqrt_r[c]=0;
b=expansion_coeff(cpfr,pow(x-c,-2),contextptr);
alpha_plus[c]=(1+sqrt(1+4*b,contextptr))/2;
alpha_minus[c]=(1-sqrt(1+4*b,contextptr))/2;
} else if (order%2==0 && order>=4) {
nu=order/2;
e=_series(makesequence(sqrt(r,contextptr),x,c,1,_POLY1__VECT),contextptr);
for (int i=2;i<=nu;++i) {
gen cf=expansion_coeff(e,pow(x-c,-i),contextptr);
if (i==nu)
a=cf;
sqrt_r[c]+=cf/pow(x-c,i);
}
if (is_zero(a))
return false;
b=expansion_coeff(cpfr,pow(x-c,-nu-1),contextptr);
b-=expansion_coeff(_cpartfrac(makesequence(sq(sqrt_r[c]),x),contextptr),pow(x-c,-nu-1),contextptr);
alpha_plus[c]=(nu+b/a)/2;
alpha_minus[c]=(nu-b/a)/2;
} else assert(false);
}
if (dinf>2) {
sqrt_r[inf]=0;
alpha_inf_plus=0;
alpha_inf_minus=1;
} else if (dinf==2) {
sqrt_r[inf]=0;
b=_lcoeff(makesequence(s,x),contextptr)/_lcoeff(makesequence(t,x),contextptr);
alpha_inf_plus=(1+sqrt(1+4*b,contextptr))/2;
alpha_inf_minus=(1-sqrt(1+4*b,contextptr))/2;
} else if (dinf%2==0 && dinf<=0) {
nu=-dinf/2;
e=_series(makesequence(sqrt(r,contextptr),x,inf,1,_POLY1__VECT),contextptr);
for (int i=0;i<=nu;++i) {
gen cf=expansion_coeff(e,pow(x,i),contextptr);
if (i==nu)
a=cf;
sqrt_r[inf]+=cf*pow(x,i);
}
if (is_zero(a))
return false;
b=expansion_coeff(_propfrac(makesequence(r,x),contextptr),pow(x,nu-1),contextptr);
b-=expansion_coeff(expand(sq(sqrt_r[inf]),contextptr),pow(x,nu-1),contextptr);
alpha_inf_plus=(b/a-nu)/2;
alpha_inf_minus=(-b/a-nu)/2;
} else assert(false);
/* step 2 */
int np=poles.size()+1,N=(1<first);
}
for (int i=0;i_VECTptr->front().val; fw=it->_VECTptr->back();
v=vecteur(vars.begin(),vars.begin()+d);
P=0;
for (int i=0;iempty()) {
lsol=_subst(makesequence(lsol._VECTptr->front(),v,vecteur(d,0)),contextptr);
solutions.push_back(_subst(makesequence(P,v,lsol),contextptr)*
fullsimp(_int(makesequence(fw-dy_coeff/2,x),contextptr),contextptr));
success=true;
}
}
}
if (!success && kovacic_iscase2(poles)) {
cerr << "Case 2 of Kovacic algorithm" << '\n';
/* step 1 */
gen_map E;
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
c=it->_VECTptr->front();
order=it->_VECTptr->back().val;
if (order==1)
E[c]=vecteur(1,4);
else if (order==2) {
b=expansion_coeff(cpfr,pow(x-c,-2),contextptr);
E[c]=vecteur(0);
for (int k=-1;k<=1;++k) {
gen tmp=_eval(2+2*k*sqrt(1+4*b,contextptr),contextptr);
if (tmp.is_integer())
E[c]._VECTptr->push_back(tmp);
}
} else if (order>2)
E[c]=vecteur(1,order);
}
vecteur Einf(0);
if (dinf>2)
Einf=makevecteur(0,2,4);
else if (dinf==2) {
b=expansion_coeff(laur,pow(x,-2),contextptr);
for (int k=-1;k<=1;++k) {
gen tmp=_eval(2+2*k*sqrt(1+4*b,contextptr),contextptr);
if (tmp.is_integer())
Einf.push_back(tmp);
}
} else if (dinf<2)
Einf.push_back(dinf);
/* step 2 */
vecteur family,families,fam,cv,vars,v;
for (gen_map::const_iterator it=E.begin();it!=E.end();++it) {
cv.push_back(it->first);
}
build_E_families(E,cv,family,families);
int maxdeg=0,deg;
for (const_iterateur it=Einf.begin();it!=Einf.end();++it) {
if (families.empty()) {
e=*it/2;
if (e.is_integer() && is_positive(e,contextptr)) {
fam.push_back(makevecteur(e,0));
maxdeg=std::max(maxdeg,e.val);
}
}
for (const_iterateur jt=families.begin();jt!=families.end();++jt) {
gen th(0);
bool discard=is_one(_even(*it,contextptr));
const vecteur &fm=*(jt->_VECTptr);
for (const_iterateur kt=fm.begin();kt!=fm.end();++kt) {
th+=(*kt)/(x-cv[kt-fm.begin()]);
if (is_zero(_even(*kt,contextptr)))
discard=false;
}
//if (discard) continue;
e=_eval(*it-_sum(fm,contextptr),contextptr)/2;
if (e.is_integer() && is_positive(e,contextptr)) {
fam.push_back(makevecteur(e,th/2));
maxdeg=std::max(maxdeg,e.val);
}
}
}
/* step 3 */
create_identifiers(vars,maxdeg);
gen P,th,dth;
for (const_iterateur it=fam.begin();it!=fam.end() && !success;++it) {
deg=it->_VECTptr->front().val; th=it->_VECTptr->back();
v=vecteur(vars.begin(),vars.begin()+deg);
P=0;
for (int i=0;iempty())) {
if (deg>0) {
cfs=_subst(makesequence(cfs._VECTptr->front(),v,vecteur(deg,0)),contextptr);
P=_subst(makesequence(P,v,cfs),contextptr);
}
gen ph=th+_derive(makesequence(P,x),contextptr)/P;
gen qsol=_solve(makesequence(symb_equal(sq(w)-w*ph+(_derive(makesequence(ph,x),contextptr)/2+sq(ph)/2-r),0),w),contextptr);
if (qsol.type==_VECT) for (const_iterateur jt=qsol._VECTptr->begin();jt!=qsol._VECTptr->end();++jt) {
solutions.push_back(fullsimp(_int(makesequence(*jt-dy_coeff/2,x),contextptr),contextptr));
success=true;
}
}
}
}
if (!success && kovacic_iscase3(cpfr,x,poles,dinf,contextptr)) {
cerr << "Case 3 of Kovacic algorithm" << '\n';
vector nv=vecteur_2_vector_int(makevecteur(4,6,12));
for (vector::const_iterator nt=nv.begin();nt!=nv.end();++nt) {
int n=*nt;
/* step 1 */
gen_map E;
for (const_iterateur it=poles.begin();it!=poles.end();++it) {
c=it->_VECTptr->front();
order=it->_VECTptr->back().val;
if (order==1)
E[c]=vecteur(1,12);
else if (order==2) {
a=expansion_coeff(cpfr,pow(x-c,-2),contextptr);
E[c]=vecteur(0);
for (int k=-n/2;k<=n/2;++k) {
gen tmp=_eval(6+k*(12/n)*sqrt(1+4*a,contextptr),contextptr);
if (tmp.is_integer())
E[c]._VECTptr->push_back(tmp);
}
}
}
vecteur Einf(0);
b=dinf>2?gen(0):expansion_coeff(laur,pow(x,-2),contextptr);
for (int k=-n/2;k<=n/2;++k) {
gen tmp=_eval(6+k*(12/n)*sqrt(1+4*b,contextptr),contextptr);
if (tmp.is_integer())
Einf.push_back(tmp);
}
/* step 2 */
vecteur family,families,fam,cv,vars,v;
for (gen_map::const_iterator it=E.begin();it!=E.end();++it) {
cv.push_back(it->first);
}
build_E_families(E,cv,family,families);
int maxdeg=0,deg;
for (const_iterateur it=Einf.begin();it!=Einf.end();++it) {
if (families.empty()) {
e=*it*gen(n)/12;
if (e.is_integer() && is_positive(e,contextptr)) {
fam.push_back(makevecteur(e,0));
maxdeg=std::max(maxdeg,e.val);
}
}
for (const_iterateur jt=families.begin();jt!=families.end();++jt) {
gen th(0);
const vecteur &fm=*(jt->_VECTptr);
for (const_iterateur kt=fm.begin();kt!=fm.end();++kt) {
th+=(*kt)/(x-cv[kt-fm.begin()]);
}
e=gen(n)*_eval(*it-_sum(*jt,contextptr),contextptr)/12;
if (e.is_integer() && is_positive(e,contextptr)) {
fam.push_back(makevecteur(e,gen(n)*th/12));
maxdeg=std::max(maxdeg,e.val);
}
}
}
/* step 3 */
gen S(1);
for (const_iterateur it=cv.begin();it!=cv.end();++it) {
S=S*(x-*it);
}
gen dS=_derive(makesequence(S,x),contextptr),th;
vecteur P(n+2,0);
create_identifiers(vars,maxdeg);
for (const_iterateur it=fam.begin();it!=fam.end();++it) {
deg=it->_VECTptr->front().val; th=it->_VECTptr->back();
v=vecteur(vars.begin(),vars.begin()+deg);
for (int i=0;i0;) {
P[i]=-S*_derive(makesequence(P[i+1],x),contextptr)+((n-i)*dS-S*th)*P[i+1]-(n-i)*(i+1)*sq(S)*r*P[i+2];
if (P[i].type==_SYMB) P[i]=_collect(P[i],contextptr);
}
gen cfs;
if ((deg==0 && is_zero(P[0])) ||
(deg>0 && (cfs=_solve(makesequence(_coeff(makesequence(P[0],x),contextptr),v),contextptr)).type==_VECT &&
!cfs._VECTptr->empty())) {
if (deg>0) {
cfs=_subst(makesequence(cfs._VECTptr->front(),v,vecteur(deg,0)),contextptr);
P=*_subst(makesequence(P,v,cfs),contextptr)._VECTptr;
}
vecteur ac(n+1);
for (int i=0;i<=n;++i) {
ac[i]=_collect(pow(S,i)*P[i+1]/_factorial(n-i,contextptr),contextptr);
}
*logptr(contextptr) << "Warning: outputting the algebraic expression for ω" << '\n';
ac=strip_gcd(ac,contextptr);
gen omg=pow(w,4)*ac[4]+pow(w,3)*ac[3]+pow(w,2)*ac[2]+w*ac[1]+ac[0];
if (!is_zero(dy_coeff)) {
vecteur C=*_coeff(makesequence(_subst(makesequence(omg,w,w+dy_coeff/2),contextptr),w),contextptr)._VECTptr;
for (int i=0;i<=n;++i) {
ac[i]=_collect(_ratnormal(C[i],contextptr),contextptr);
}
ac=strip_gcd(ac,contextptr);
omg=pow(w,4)*ac[4]+pow(w,3)*ac[3]+pow(w,2)*ac[2]+w*ac[1]+ac[0];
}
return omg;
}
}
}
}
return solutions;
}
/*
* Return the solution(s) of a second-order linear homogeneous ODE using
* Kovacic's algorithm. The first argument is the ODE a(x)*y''+b(x)*y'+c(x)*y=0
* itself, which may be given as an expression (left-hand side), an equation or
* a list [a,b,c]. The functions a, b and c must be rational in x. The second
* and third (both optional) arguments are the independent variable x and the
* dependent variable y, respectively. By default, the symbols "x" and "y" are
* used.
*/
gen _kovacicsols(const gen &g,GIAC_CONTEXT) {
if (g.type==_STRNG && g.subtype==-1) return g;
gen x=identificateur("x"),y=identificateur("y"),eq,p(0),q(0),r(0);
if (g.type!=_VECT || g.subtype!=_SEQ__VECT) {
eq=g;
} else if (g.subtype==_SEQ__VECT) {
vecteur &gv=*g._VECTptr;
if (gv.size()<2) return gensizeerr(contextptr);
eq=gv.front();
if (gv.size()==2) {
if (eq.type==_VECT && gv.back().type==_IDNT)
x=gv.back();
else if (gv.back().is_symb_of_sommet(at_of)) {
y=gv.back()._SYMBptr->feuille._VECTptr->front();
x=gv.back()._SYMBptr->feuille._VECTptr->back();
} else return gensizeerr(contextptr);
} else {
if (eq.type==_VECT)
return gensizeerr(contextptr);
x=gv[1];
y=gv[2];
}
if (y.type!=_IDNT || x.type!=_IDNT)
return gensizeerr(contextptr);
}
eq=idnteval(eq,contextptr);
if (eq.type==_VECT) {
vecteur &cfs=*eq._VECTptr;
if (cfs.size()!=3)
return gensizeerr(contextptr);
p=cfs[1]; q=cfs[2]; r=cfs[0];
} else if (eq.type==_SYMB) {
gen dy=identificateur(" dy"),d2y=identificateur(" d2y"),yx=symb_of(y,x);
gen diffy=symbolic(at_derive,y),diff2y=symbolic(at_derive,diffy);
eq=_subst(makesequence(eq,makevecteur(_derive(makesequence(yx,x),contextptr),_derive(makesequence(yx,x,2),contextptr)),
makevecteur(dy,d2y)),contextptr);
eq=_subst(makesequence(_subst(makesequence(_subst(makesequence(eq,diff2y,d2y),contextptr),diffy,dy),contextptr),yx,y),contextptr);
if (eq.is_symb_of_sommet(at_equal))
eq=equal2diff(eq);
eq=expand(eq,contextptr);
vecteur terms=eq.is_symb_of_sommet(at_plus) && eq._SYMBptr->feuille.type==_VECT?
*eq._SYMBptr->feuille._VECTptr:vecteur(1,eq);
gen tmp;
vecteur yvars=makevecteur(y,dy,d2y);
for (const_iterateur it=terms.begin();it!=terms.end();++it) {
if (is_constant_wrt_vars(tmp=_ratnormal(*it/y,contextptr),yvars,contextptr))
q+=tmp;
else if (is_constant_wrt_vars(tmp=_ratnormal(*it/dy,contextptr),yvars,contextptr))
p+=tmp;
else if (is_constant_wrt_vars(tmp=_ratnormal(*it/d2y,contextptr),yvars,contextptr))
r+=tmp;
else return gensizeerr(contextptr);
}
} else return gensizeerr(contextptr);
if (is_zero(r)) // not a second order ODE
return gensizeerr(contextptr);
p=_ratnormal(p/r,contextptr);
q=_ratnormal(q/r,contextptr);
if (rlvarx(p,x).size()+rlvarx(q,x).size()>2) // p or q is not rational in x
return gensizeerr(contextptr);
/* solve the equation y''+p(x)*y'+q(x)*y=0, transform it first to z''=r(x)*z */
r=sq(p)/4+_derive(makesequence(p,x),contextptr)/2-q;
return kovacicsols(r,x,p,contextptr);
}
static const char _kovacicsols_s []="kovacicsols";
static define_unary_function_eval_quoted (__kovacicsols,&_kovacicsols,_kovacicsols_s);
define_unary_function_ptr5(at_kovacicsols,alias_at_kovacicsols,&__kovacicsols,_QUOTE_ARGUMENTS,true)
/*
* Return true iff the expression 'e' is constant with respect to
* variables in 'vars'.
*/
bool is_constant_wrt_vars(const gen &e,const vecteur &vars,GIAC_CONTEXT) {
for (const_iterateur it=vars.begin();it!=vars.end();++it) {
if (!is_constant_wrt(e,*it,contextptr))
return false;
}
return true;
}
gen idnteval(const gen &g,GIAC_CONTEXT) {
if (g.type==_IDNT)
return _eval(g,contextptr);
if (g.type==_SYMB) {
gen &feu=g._SYMBptr->feuille;
if (feu.type==_VECT) {
vecteur v;
for (const_iterateur it=feu._VECTptr->begin();it!=feu._VECTptr->end();++it) {
v.push_back(idnteval(*it,contextptr));
}
return symbolic(g._SYMBptr->sommet,change_subtype(v,feu.subtype));
}
return symbolic(g._SYMBptr->sommet,idnteval(feu,contextptr));
}
return g;
}
#endif
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC