/* -*- mode:C++ ; compile-command: "g++-3.4 -DHAVE_CONFIG_H -I. -I.. -DIN_GIAC -g -c derive.cc" -*- */
#include "giacPCH.h"
/*
* Copyright (C) 2000,14 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 "derive.h"
#include "usual.h"
#include "symbolic.h"
#include "unary.h"
#include "poly.h"
#include "sym2poly.h" // for equalposcomp
#include "tex.h"
#include "prog.h"
#include "intg.h"
#include "subst.h"
#include "plot.h"
#include "modpoly.h"
#include "moyal.h"
#include "alg_ext.h"
#include "giacintl.h"
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
gen eval_before_diff(const gen & expr,const gen & variable,GIAC_CONTEXT){
identificateur tmp_x_id(" eval_before_diff_x");
gen tmp_x(tmp_x_id);
gen res=subst(expr,variable,tmp_x,false,contextptr); // replace variable by a non affected identifier
gen save_vx_var=vx_var;
if (variable==vx_var) vx_var=tmp_x;
int m=calc_mode(contextptr);
calc_mode(0,contextptr);
res=eval(res,1,contextptr); // eval res (all identifiers except X will be replaced by their values)
res=eval(res,1,contextptr); // eval res (all identifiers except X will be replaced by their values)
calc_mode(m,contextptr);
vx_var=save_vx_var;
res=subst(res,tmp_x,variable,false,contextptr);
return res;
}
bool depend(const gen & g,const identificateur & i){
if (g.type==_IDNT)
return *g._IDNTptr==i;
if (g.type==_SYMB)
return depend(g._SYMBptr->feuille,i);
if (g.type!=_VECT)
return false;
const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it){
if (depend(*it,i))
return true;
}
return false;
}
static int count_noncst(const gen & g,const identificateur & i){
if (g.type!=_VECT)
return depend(g,i)?1:0;
int res=0;
for (unsigned j=0;jsize();++j){
if (depend((*g._VECTptr)[j],i))
++res;
}
return res;
}
static gen derive_SYMB(const gen &g_orig,const identificateur & i,GIAC_CONTEXT){
const symbolic & s = *g_orig._SYMBptr;
if (s.sommet==at_pnt){
gen f=g_orig._SYMBptr->feuille;
if (f.type==_VECT && !f._VECTptr->empty()){
vecteur v=*f._VECTptr;
v[0]=derive(v[0],i,contextptr);
f=gen(v,f.subtype);
return symbolic(at_pnt,f);
}
}
// if s does not depend on i return 0
if (!depend(g_orig,i))
return zero;
// rational operators are treated first for efficiency
if (s.sommet==at_plus){
bool do_step=step_infolevel(contextptr)>1 && count_noncst(s.feuille,i)>1;
if (do_step)
gprintf(gettext("Derivative of %gen apply linearity: (u+v+...)'=u'+v'+..."),makevecteur(s),contextptr);
if (s.feuille.type!=_VECT)
return derive(s.feuille,i,contextptr);
vecteur::const_iterator iti=s.feuille._VECTptr->begin(),itend=s.feuille._VECTptr->end();
int taille=int(itend-iti);
if (taille==2)
return derive(*iti,i,contextptr)+derive(*(iti+1),i,contextptr);
vecteur v;
v.reserve(taille);
gen e;
for (;iti!=itend;++iti){
e=derive(*iti,i,contextptr);
if (is_undef(e))
return e;
if (!is_zero(e))
v.push_back(e);
}
if (v.size()==1)
return v.front();
if (v.empty())
return zero;
gen res=_plus(gen(v,_SEQ__VECT),contextptr); // symbolic(at_plus,v);
if (do_step)
gprintf(gettext("Hence derivative of %gen by linearity is %gen"),makevecteur(g_orig,res),contextptr);
return res;
}
if (s.sommet==at_prod){
bool do_step=step_infolevel(contextptr)>1 && count_noncst(s.feuille,i)>1;
if (s.feuille.type==_VECT && s.feuille._VECTptr->size()==2 && s.feuille._VECTptr->back().is_symb_of_sommet(at_inv) && !is_constant_wrt(s.feuille._VECTptr->back()._SYMBptr->feuille,i,contextptr)){
gen u=s.feuille._VECTptr->front(),v=s.feuille._VECTptr->back()._SYMBptr->feuille;
if (do_step)
gprintf(gettext("Derivative of %gen/%gen, a quotient: (u/v)'=(u'*v-u*v')/v^2"),makevecteur(u,v),contextptr);
return (derive(u,i,contextptr)*v-u*derive(v,i,contextptr))/pow(v,2,contextptr);
}
if (do_step)
gprintf(gettext("Derivative of %gen, apply product rule: (u*v*...)'=u'*v*...+u*v'*...+..."),makevecteur(s),contextptr);
if (s.feuille.type!=_VECT)
return derive(s.feuille,i,contextptr);
vecteur::const_iterator itbegin=s.feuille._VECTptr->begin(),itj,iti,itend=s.feuille._VECTptr->end();
int taille=int(itend-itbegin);
// does not work because of is_linear_wrt e.g. for cos(3*pi/4)
// if (taille==2) return derive(*itbegin,i,contextptr)*(*(itbegin+1))+(*itbegin)*derive(*(itbegin+1),i,contextptr);
vecteur v,w;
v.reserve(taille);
w.reserve(taille);
gen e;
for (iti=itbegin;iti!=itend;++iti){
w.clear();
e=derive(*iti,i,contextptr);
if (is_undef(e))
return e;
if (!is_zero(e)){
for (itj=itbegin;itj!=iti;++itj)
w.push_back(*itj);
w.push_back(e);
++itj;
for (;itj!=itend;++itj)
w.push_back(*itj);
v.push_back(_prod(w,contextptr));
}
}
if (v.size()==1)
return v.front();
if (v.empty())
return zero;
gen res=symbolic(at_plus,gen(v,_SEQ__VECT));
if (do_step)
gprintf(gettext("Hence derivative of %gen by product rule is %gen"),makevecteur(g_orig,res),contextptr);
return res;
}
if (s.sommet==at_neg)
return -derive(s.feuille,i,contextptr);
if (s.sommet==at_pow){
if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2)
return gensizeerr(contextptr);
gen base = s.feuille._VECTptr->front(),exponent=s.feuille._VECTptr->back();
if (step_infolevel(contextptr)>1){
if (is_constant_wrt(exponent,i,contextptr))
gprintf(gettext("Derivative of a power: (%gen)'=(%gen)*(%gen)'*%gen"),makevecteur(symb_pow(base,exponent),exponent,base,symb_pow(base,exponent-1)),contextptr);
else
gprintf(gettext("Derivative of a power: (%gen)'=%gen*(%gen)'*ln(%gen)+(%gen)*(%gen)'*%gen"),makevecteur(symb_pow(base,exponent),symb_pow(base,exponent),exponent,base,exponent,base,symb_pow(base,exponent-1)),contextptr);
}
gen dbase=derive(base,i,contextptr),dexponent=derive(exponent,i,contextptr);
// diff(base^exponent)=diff(exp(exponent*ln(base)))
// =base^exponent*diff(exponent)*ln(base)+base^(exponent-1)*exponent*diff(base)
gen expm1=exponent+gen(-1);
if (is_zero(dexponent))
return exponent*dbase*pow(base,expm1,contextptr);
return dexponent*ln(base,contextptr)*s+exponent*dbase*pow(base,expm1,contextptr);
}
if (s.sommet==at_inv){
if (step_infolevel(contextptr)>1)
gprintf(gettext("Derivative of inv(u)=-u'/u^2 with u=%gen"),makevecteur(s.feuille),contextptr);
if (s.feuille.is_symb_of_sommet(at_pow)){
gen & f = s.feuille._SYMBptr->feuille;
if (f.type==_VECT && f._VECTptr->size()==2)
return derive(symb_pow(f._VECTptr->front(),-f._VECTptr->back()),i,contextptr);
}
return rdiv(-derive(s.feuille,i,contextptr),pow(s.feuille,2),contextptr);
}
if (equalposcomp(inequality_tab,s.sommet))
return 0;
if (s.sommet==at_fsolve && s.feuille.type==_VECT && s.feuille._VECTptr->size()>=2){
vecteur v=*s.feuille._VECTptr;
if (v[1].is_symb_of_sommet(at_equal) && v[1]._SYMBptr->feuille.type==_VECT && !v[1]._SYMBptr->feuille._VECTptr->empty())
v[1]=v[1]._SYMBptr->feuille._VECTptr->front();
gen eq=remove_equal(v[0]),y=v[1],x=i; // fsolve(eq(x,y),y) -> y(x), dy/dx=-(deq/dx)/(deq/dy)
gen res=-derive(eq,x,contextptr)/derive(eq,y,contextptr);
res=subst(res,y,s,false,contextptr);
return res;
}
if (s.sommet==at_rootof){
gen f=s.feuille;
if (f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->front().type==_VECT && f._VECTptr->back().type==_VECT){
vecteur P=*f._VECTptr->front()._VECTptr;
vecteur Q=*f._VECTptr->back()._VECTptr;
// d/dx(P(y))=(dP/dx)(y) + (dP/dy) (dy/dx)
// =(dP/dx)(y) - (dP/dy) (dQ/dx)/(dQ/dy)
// where y dependency is in the list polynomial P/Q
gen Px=trim(*derive(P,i,contextptr)._VECTptr,0);
Px=symb_rootof(Px,Q,contextptr);
gen Qx=trim(*derive(Q,i,contextptr)._VECTptr,0);
Qx=symb_rootof(Qx,Q,contextptr);
gen Py=derivative(P);
Py=symb_rootof(Py,Q,contextptr);
gen Qy=derivative(Q);
Qy=symb_rootof(Qy,Q,contextptr);
gen res=Px-(Py*Qx)/Qy;
res=normal(res,contextptr);
return res;
}
return gensizeerr(gettext("Derivative of rootof currently not handled"));
}
if (step_infolevel(contextptr)>1 && s.feuille.type!=_VECT){
if (s.feuille==i){
int save_step=step_infolevel(contextptr);
step_infolevel(contextptr)=0;
gen der=derive_SYMB(g_orig,i,contextptr);
step_infolevel(contextptr)=save_step;
gprintf(gettext("Derivative of elementary function %gen is %gen"),makevecteur(g_orig,der),contextptr);
}
else
gprintf(gettext("Derivative of a composition: (%gen)'=(%gen)'*f'(%gen) where f=%gen"),makevecteur(g_orig,s.feuille,s.feuille,s.sommet),contextptr);
}
if (s.sommet==at_UTPT){
if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2)
return gensizeerr(contextptr);
gen & arg=s.feuille._VECTptr->back();
return -derive(arg,i,contextptr)*_student(s.feuille,contextptr);
}
if (s.sommet==at_UTPC){
if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=2)
return gensizeerr(contextptr);
gen & arg=s.feuille._VECTptr->back();
return -derive(arg,i,contextptr)*_chisquare(s.feuille,contextptr);
}
if (s.sommet==at_UTPF){
if (s.feuille.type!=_VECT || s.feuille._VECTptr->size()!=3)
return gensizeerr(contextptr);
gen & arg=s.feuille._VECTptr->back();
return -derive(arg,i,contextptr)*_snedecor(s.feuille,contextptr);
}
if (s.sommet==at_program){
return gensizeerr(gettext("Expecting an expression, not a function"));
}
if (s.sommet==at_ln){
if (s.feuille.is_symb_of_sommet(at_abs) )
return rdiv(derive(s.feuille._SYMBptr->feuille,i,contextptr),s.feuille._SYMBptr->feuille,contextptr);
if (s.feuille.is_symb_of_sommet(at_inv))
return -derive(symbolic(at_ln,s.feuille._SYMBptr->feuille),i,contextptr);
if (s.feuille.is_symb_of_sommet(at_prod)){
gen res;
const gen &f=s.feuille._SYMBptr->feuille;
if (f.type==_VECT){
const_iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end();
for (;it!=itend;++it)
res=res+derive(symbolic(at_ln,*it),i,contextptr);
return res;
}
}
}
if (s.feuille.type==_VECT){
vecteur v=*s.feuille._VECTptr;
int vs=int(v.size());
if (vs>=3 && (s.sommet==at_ifte || s.sommet==at_when) ){
for (int j=1;j=3 && s.sommet==at_Beta){
gen v0=v[0],v1=v[1],v2=v[2];
if (!is_zero(derive(v0,i,contextptr)) || !is_zero(derive(v1,i,contextptr)) )
return gensizeerr("diff of incomplete beta with respect to non constant 1st or 2nd arg not implemented");
// diff/v2 of int_0^v2 t^(v0-1)*(1-t)^(v1-1) dt
gen tmp=pow(v2,v0-1,contextptr)*pow(1-v2,v1-1,contextptr)*derive(v2,i,contextptr);
if (vs==4){
gen v3=v[3];
if (is_one(v3))
return tmp/Beta(v0,v1,contextptr);
return gensizeerr(contextptr);
gen v3p=derive(v3,i,contextptr);
if (!is_zero(v3p))
return tmp-pow(v3,v0-1,contextptr)*pow(1-v3,v1-1,contextptr)*v3p;
}
return tmp;
}
if (vs==4 && s.sommet==at_sum){
gen v0=v[0],v1=v[1],v2=v[2],v3=v[3];
if (!is_zero(derive(v1,i,contextptr)) || !is_zero(derive(v2,i,contextptr)) || ! is_zero(derive(v3,i,contextptr)) )
return gensizeerr("diff of sum with boundaries or mute variable depending on differentiation variable");
if (is_inf(v2) || is_inf(v3))
*logptr(contextptr) << "Warning, assuming derivative commutes with infinite sum" << endl;
return _sum(makesequence(derive(v0,i,contextptr),v1,v2,v3),contextptr);
}
if ( (vs==2 || (vs==3 && is_zero(v[2]))) && (s.sommet==at_upper_incomplete_gamma || s.sommet==at_lower_incomplete_gamma || s.sommet==at_Gamma)){
gen v0=v[0],v1=v[1];
if (!is_zero(derive(v0,i,contextptr)))
return gensizeerr("diff of incomplete gamma with respect to non constant 1st arg not implemented");
// diff(int_v1^inf exp(-t)*t^(v0-1) dt)
gen tmp1=exp(-v1,contextptr)*pow(v1,v0-1,contextptr)*derive(v1,i,contextptr);
return (s.sommet==at_lower_incomplete_gamma)?tmp1:-tmp1;
}
if (vs==3 && (s.sommet==at_upper_incomplete_gamma || s.sommet==at_lower_incomplete_gamma || s.sommet==at_Gamma)){
return derive(symbolic(s.sommet,makesequence(v[0],v[1]))/symbolic(at_Gamma,v[0]),i,contextptr);
}
}
// now look at other operators, first onearg operator
if (s.sommet.ptr()->D){
if (s.feuille.type!=_VECT)
return derive(s.feuille,i,contextptr)*(*s.sommet.ptr()->D)(1)(s.feuille,contextptr);
// multiargs operators
int taille=int(s.feuille._VECTptr->size());
vecteur v;
v.reserve(taille);
vecteur::const_iterator iti=s.feuille._VECTptr->begin(),itend=s.feuille._VECTptr->end();
gen e;
for (int j=1;iti!=itend;++iti,++j){
e=derive(*iti,i,contextptr);
if (is_undef(e))
return e;
if (!is_zero(e))
v.push_back(e*(*s.sommet.ptr()->D)(j)(s.feuille,contextptr));
}
if (v.size()==1)
return v.front();
if (v.empty())
return zero;
return symbolic(at_plus,gen(v,_SEQ__VECT));
}
// integrate
if (s.sommet==at_integrate || s.sommet==at_HPINT){
if (s.feuille.type!=_VECT)
return s.feuille;
vecteur v=*s.feuille._VECTptr;
int nargs=int(v.size());
if (nargs<=1)
return s.feuille;
if (nargs==2 && is_equal(v[1])){
gen v1f=v[1]._SYMBptr->feuille;
if (v1f.type==_VECT && v1f._VECTptr->size()==2){
gen v1f1=v1f._VECTptr->front();
gen v1f2=v1f._VECTptr->back();
v[1]=v1f1;
if (v1f2.is_symb_of_sommet(at_interval)){
v.push_back(v1f2._SYMBptr->feuille._VECTptr->front());
v.push_back(v1f2._SYMBptr->feuille._VECTptr->back());
nargs=4;
}
}
}
gen res,newint;
if (v[1]==i)
res=v[0];
else {
res=subst(v[0],v[1],i,false,contextptr);
newint=derive(v[0],i,contextptr);
if (nargs<4)
newint=integrate_gen(newint,v[1],contextptr);
}
if (nargs==2)
return res+newint;
if (nargs==3)
return derive(v[2],i,contextptr)*subst(res,i,v[2],false,contextptr);
if (nargs==4){
gen a3=derive(v[3],i,contextptr);
gen b3=is_zero(a3)?zero:limit(res,i,v[3],-1,contextptr);
gen a2=derive(v[2],i,contextptr);
gen b2=is_zero(a2)?zero:limit(res,i,v[2],1,contextptr);
return a3*b3-a2*b2+_integrate(gen(makevecteur(newint,v[1],v[2],v[3]),_SEQ__VECT),contextptr);
}
return gensizeerr(contextptr);
}
if (s.sommet==at_of && s.feuille.type==_VECT && s.feuille._VECTptr->size()==2){
// assuming we do not have an index in a list or matrix!
gen f=s.feuille._VECTptr->front();
gen arg=s.feuille._VECTptr->back();
gen darg=derive(arg,i,contextptr);
if (!is_one(darg)){
if (darg.type==_VECT){
gen res=0;
for (int i=0;isize());++i){
gen fprime=symbolic(at_derive,makesequence(f,i));
res += darg[i]*symbolic(at_of,makesequence(fprime,arg));
}
return res;
}
// f(arg)'=arg'*f'(arg)
gen fprime=symbolic(at_derive,f);
return darg*symbolic(at_of,makesequence(fprime,arg));
}
}
// multi derivative and multi-indice derivatives
if (s.sommet==at_derive){
if (s.feuille.type!=_VECT)
return symbolic(at_derive,gen(makevecteur(s.feuille,vx_var,2),_SEQ__VECT));
if (s.feuille._VECTptr->size()==2){ // derive(f,x)
gen othervar=(*s.feuille._VECTptr)[1];
if (othervar.type!=_IDNT) return gensizeerr(gettext("derive.cc/derive_SYMB"));
if (*othervar._IDNTptr==i){ // _FUNCnd derivative
vecteur res(*s.feuille._VECTptr);
symbolic sprime(s);
res.push_back(2);
return symbolic(at_derive,gen(res,_SEQ__VECT));
}
else {
vecteur var;
var.push_back(othervar);
var.push_back(i);
vecteur nderiv;
nderiv.push_back(1);
nderiv.push_back(1);
return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],var,nderiv),_SEQ__VECT));
}
}
else { // derive(f,x,n)
if (s.feuille._VECTptr->size()!=3) return gensizeerr(gettext("derive.cc/derive_SYMB"));
gen othervar=(*s.feuille._VECTptr)[1];
if (othervar.type==_IDNT){
if (*othervar._IDNTptr==i){ // n+1 derivative
vecteur vprime=(*s.feuille._VECTptr);
vprime[2] += 1;
return symbolic(s.sommet,gen(vprime,_SEQ__VECT));
}
else {
vecteur var;
var.push_back(othervar);
var.push_back(i);
vecteur nderiv;
nderiv.push_back((*s.feuille._VECTptr)[2]);
nderiv.push_back(1);
return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],var,nderiv),_SEQ__VECT));
}
} // end if othervar.type==_IDNT
else { // othervar.type must be _VECT
if (othervar.type!=_VECT) return gensizeerr(gettext("derive.cc/derive_SYMB"));
gen nder((*s.feuille._VECTptr)[2]);
if (nder.type!=_VECT ||
nder._VECTptr->size()!=othervar._VECTptr->size()) return gensizeerr(gettext("derive.cc/derive_SYMB"));
vecteur nderiv(*nder._VECTptr);
int pos=equalposcomp(*othervar._VECTptr,i);
if (pos){
nderiv[pos-1]=nderiv[pos-1]+1;
}
else {
othervar._VECTptr->push_back(i);
nderiv.push_back(1);
}
return symbolic(at_derive,gen(makevecteur((*s.feuille._VECTptr)[0],othervar,nderiv),_SEQ__VECT));
}
}
}
if (s.sommet==at_re || s.sommet==at_im || s.sommet==at_conj){
return s.sommet(derive(s.feuille,i,contextptr),contextptr);
}
// no info about derivative
return symbolic(at_derive,gen(makevecteur(s,i),_SEQ__VECT));
//i.dbgprint();
//s.dbgprint();
}
static gen derive_VECT(const vecteur & v,const identificateur & i,GIAC_CONTEXT){
vecteur w;
w.reserve(v.size());
vecteur::const_iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it){
gen tmp=derive(*it,i,contextptr);
if (is_undef(tmp))
return tmp;
w.push_back(tmp);
}
return w;
}
gen derive(const gen & e,const identificateur & i,GIAC_CONTEXT){
if (abs_calc_mode(contextptr)==38 && i.id_name[0]>='A' && i.id_name[0]<='Z'){
identificateur tmp("xdiff");
gen ee=subst(e,i,tmp,true,contextptr);
ee=eval(ee,1,contextptr);
ee=subst(ee,i,tmp,true,contextptr);
ee=derive(ee,tmp,contextptr);
ee=subst(ee,tmp,i,true,contextptr);
return ee;
}
switch (e.type){
case _INT_: case _DOUBLE_: case _ZINT: case _CPLX: case _MOD: case _REAL: case _USER: case _FLOAT_:
return 0;
case _IDNT:
if (is_undef(e))
return e;
if (*e._IDNTptr==i)
return 1;
else
return 0;
case _SYMB:
return derive_SYMB(e,i,contextptr);
case _VECT: {
gen res=derive_VECT(*e._VECTptr,i,contextptr);
if (res.type==_VECT) res.subtype=e.subtype;
return res;
}
case _FRAC:
return fraction(derive(e._FRACptr->num,i,contextptr)*e._FRACptr->den-(e._FRACptr->num)*derive(e._FRACptr->den,i,contextptr),e._FRACptr->den);
default:
return gentypeerr(contextptr);
}
return 0;
}
static gen _VECTderive(const gen & e,const vecteur & v,GIAC_CONTEXT){
vecteur w;
w.reserve(v.size());
vecteur::const_iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it){
gen tmp=derive(e,*it,contextptr);
if (is_undef(tmp))
return tmp;
w.push_back(tmp);
}
return w;
}
static gen derivesymb(const gen& e,const gen & var,GIAC_CONTEXT){
identificateur x(" x");
gen xx(x);
gen f=subst(e,var,xx,false,contextptr);
f=derive(f,x,contextptr);
f=subst(f,xx,var,false,contextptr);
return f;
}
gen derive(const gen & e,const gen & vars,GIAC_CONTEXT){
// cout << e << " " << vars << endl;
if (is_equal(e))
return symb_equal(derive(e._SYMBptr->feuille[0],vars,contextptr),
derive(e._SYMBptr->feuille[1],vars,contextptr));
switch (vars.type){
case _INT_:
return symbolic(at_derive,makesequence(e,vars));
case _IDNT:
return derive(e,*vars._IDNTptr,contextptr);
case _VECT:
return _VECTderive(e,*vars._VECTptr,contextptr);
case _SYMB:
return derivesymb(e,vars,contextptr);
default:
return gensizeerr(contextptr);
}
return 0;
}
gen derive(const gen & e,const gen & vars,const gen & nderiv,GIAC_CONTEXT){
if (is_equal(e))
return symb_equal(derive(e._SYMBptr->feuille[0],vars,nderiv,contextptr),
derive(e._SYMBptr->feuille[1],vars,nderiv,contextptr));
if (nderiv.type==_INT_){
int n=nderiv.val;
gen ecopie(e),eprime(e);
int j=1;
for (;j<=n;++j){
eprime=ratnormal(derive(ecopie,vars,contextptr),contextptr);
if (is_undef(eprime))
return eprime;
if ( (eprime.type==_SYMB) && (eprime._SYMBptr->sommet==at_derive))
break;
ecopie=eprime;
}
if (j==n+1)
return eprime;
return symbolic(at_derive,gen(makevecteur(ecopie,vars,n+1-j),_SEQ__VECT));
}
// multi-index derivation
if (nderiv.type!=_VECT ||
vars.type!=_VECT) return gensizeerr(gettext("derive.cc/derive"));
int s=int(nderiv._VECTptr->size());
if (s!=signed(vars._VECTptr->size())) return gensizeerr(gettext("derive.cc/derive"));
int j=0;
gen ecopie(e);
for (;j1 && v[1].is_symb_of_sommet(at_unquote))
v[1]=eval(v[1],1,contextptr);
if (is_undef(v))
return v;
if (step_infolevel(contextptr) && v.size()==2 && v[0].type==_SYMB)
gprintf(step_derive_header,gettext("===== Derive %gen with respect to %gen ====="),makevecteur(v[0],v[1]),contextptr);
gen var,res;
if (args.type!=_VECT && is_algebraic_program(v[0],var,res)){
if (var.type==_VECT && var.subtype==_SEQ__VECT && var._VECTptr->size()==1)
var=var._VECTptr->front();
res=derive(res,var,contextptr);
return symbolic(at_program,makesequence(var,0,res));
}
int s=int(v.size());
if (s==2){
if (v[1].type==_VECT && v[1].subtype==_SEQ__VECT){
vecteur & w=*v[1]._VECTptr;
int ss=int(w.size());
gen res=v[0];
for (int i=0;iexponent;
it->coeff=it->coeff*e;
it->exponent=e-1;
}
return res;
}
if (args.type!=_VECT && v[0].type==_VECT && v[0].subtype==_POLY1__VECT)
return gen(derivative(*v[0]._VECTptr),_POLY1__VECT);
return derive(v[0],v[1],contextptr);
}
if (s==3 && (v[2].type==_INT_ || (v[2].type==_VECT && v[2].subtype!=_SEQ__VECT)) )
return derive( v[0],v[1],v[2],contextptr);
if (s<3)
return gensizeerr(contextptr);
if (s>=3 && v.back().is_symb_of_sommet(at_equal)){
gen v_=gen(vecteur(v.begin(),v.end()-1),_SEQ__VECT);
v_=_derive(v_,contextptr);
return _subst(makesequence(v_,v.back()),contextptr);
}
const_iterateur it=v.begin()+1,itend=v.end();
res=v[0];
for (;it!=itend;++it)
res=ratnormal(_derive(gen(makevecteur(res,*it),_SEQ__VECT),contextptr),contextptr);
return res;
}
// "unary" version
gen step_derive(const gen & args,GIAC_CONTEXT){
if (step_infolevel(contextptr))
++step_infolevel(contextptr);
gen res;
#ifndef NO_STDEXCEPT
try {
res=_derive(args,contextptr);
} catch (std::runtime_error & e){
res=string2gen(e.what(),false);
res.subtype=-1;
}
#else
res=_derive(args,contextptr);
#endif
if (step_infolevel(contextptr))
--step_infolevel(contextptr);
return res;
}
gen _diff(const gen & g,GIAC_CONTEXT){
return _derive(g,contextptr);
}
static const char _derive_s []="diff";
static string printasderive(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){
if (feuille.type!=_VECT){
if (feuille.type>=_POLY && feuille.type!=_IDNT)
return "("+feuille.print()+")'";
return feuille.print()+"'";
}
return sommetstr+("("+feuille.print(contextptr)+")");
}
static string texprintasderive(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){
if (feuille.type!=_VECT)
return gen2tex(feuille,contextptr)+"'";
return "\\frac{\\partial \\left("+gen2tex(feuille._VECTptr->front(),contextptr)+"\\right)}{\\partial "+gen2tex(feuille._VECTptr->back(),contextptr)+"}";
}
static define_unary_function_eval4_quoted (__derive,&step_derive,_derive_s,printasderive,texprintasderive);
define_unary_function_ptr5( at_derive ,alias_at_derive,&__derive,_QUOTE_ARGUMENTS,true);
gen _grad(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type!=_VECT)
return gensizeerr(contextptr);
if (args._VECTptr->size()==3){
gen opt=args._VECTptr->back();
if (opt.is_symb_of_sommet(at_equal) && (opt._SYMBptr->feuille[0]==at_coordonnees || (opt._SYMBptr->feuille[0].type==_INT_ && opt._SYMBptr->feuille[0].val==_COORDS))){
gen coord=(*args._VECTptr)[1];
gen res=_derive(makesequence(args._VECTptr->front(),coord),contextptr);
if (res.type==_VECT){
vecteur resv=*res._VECTptr;
if (opt._SYMBptr->feuille[1]==at_sphere && resv.size()==3){
resv[1]=resv[1]/coord[0];
resv[2]=resv[2]/(coord[0]*sin(coord[1],contextptr));
return resv;
}
if (opt._SYMBptr->feuille[1]==at_cylindre && resv.size()>=2){
resv[1]=resv[1]/coord[0];
return resv;
}
}
}
}
if (args._VECTptr->size()!=2)
return gensizeerr(contextptr);
return _derive(args,contextptr);
}
static const char _grad_s []="grad";
static define_unary_function_eval_quoted (__grad,&_grad,_grad_s);
define_unary_function_ptr5( at_grad ,alias_at_grad,&__grad,_QUOTE_ARGUMENTS,true);
gen critical(const gen & g,bool extrema_only,GIAC_CONTEXT){
gen arg,var;
if (g.type!=_VECT){
arg=g;
var=ggb_var(arg);
}
else {
if (g.subtype!=_SEQ__VECT || g._VECTptr->size()<2)
return gensizeerr(contextptr);
arg=g._VECTptr->front();
var=(*g._VECTptr)[1];
}
int savestep=step_infolevel(contextptr);
gprintf(gettext("===== Critical points for %gen ====="),makevecteur(arg),contextptr);
step_infolevel(contextptr)=0;
gen d=_derive(makesequence(arg,var),contextptr);
gen deq=_equal(makesequence(d,0*var),contextptr);
// *logptr(contextptr) << "Critical points for "<< arg <<": solving " << deq << " with respect to " << var << endl;
int c=calc_mode(contextptr);
calc_mode(0,contextptr);
gen s=_solve(makesequence(deq,var),contextptr);
step_infolevel(contextptr)=savestep;
gprintf(step_extrema1,gettext("Derivative of %gen with respect to %gen is %gen\nSolving %gen with respect to %gen answer %gen"),makevecteur(arg,var,d,deq,var,s.type==_VECT?change_subtype(s,_SEQ__VECT):s),contextptr);
calc_mode(c,contextptr);
vecteur ls=lidnt(s);
for (int i=0;ifeuille;
return symbolic(at_of,makesequence(gen(symbolic(at_composepow,makesequence(at_function_diff,2))),f));
}
if (g.is_symb_of_sommet(at_of)){
gen & f = g._SYMBptr->feuille;
if (f.type==_VECT && f._VECTptr->size()==2){
gen & f1=f._VECTptr->front();
gen & f2=f._VECTptr->back();
if (f1.is_symb_of_sommet(at_composepow)){
gen & f1f=f1._SYMBptr->feuille;
if (f1f.type==_VECT && f1f._VECTptr->size()==2 && f1f._VECTptr->front()==at_function_diff){
return symbolic(at_of,makesequence(gen(symbolic(at_composepow,makesequence(at_function_diff,f1f._VECTptr->back()+1))),f2));
}
}
}
}
identificateur _tmpi(" _x");
gen _tmp(_tmpi);
gen dg(derive(g(_tmp,contextptr),_tmp,contextptr));
if (lop(dg,at_derive).empty()){
identificateur tmpi(" x");
gen tmp(tmpi);
gen res=symb_program(tmp,zero,quotesubst(dg,_tmp,tmp,contextptr),contextptr);
return res;
}
return symbolic(at_function_diff,g);
}
static const char _function_diff_s []="function_diff";
static define_unary_function_eval (__function_diff,&_function_diff,_function_diff_s);
define_unary_function_ptr5( at_function_diff ,alias_at_function_diff,&__function_diff,0,true);
static const char _fonction_derivee_s []="fonction_derivee";
static define_unary_function_eval (__fonction_derivee,&_function_diff,_fonction_derivee_s);
define_unary_function_ptr5( at_fonction_derivee ,alias_at_fonction_derivee,&__fonction_derivee,0,true);
gen _implicit_diff(const gen & args,GIAC_CONTEXT){
if (is_undef(args)) return args;
if (args.type!=_VECT || (args._VECTptr->size()!=3 && args._VECTptr->size()!=4))
return gensizeerr(contextptr);
int ndiff=1;
if (args._VECTptr->size()==4){
gen g=args._VECTptr->back();
if (!is_integral(g) || g.type!=_INT_ || g.val<1)
return gensizeerr(contextptr);
ndiff=g.val;
}
gen eq(remove_equal(args._VECTptr->front())),x((*args._VECTptr)[1]),y((*args._VECTptr)[2]);
gen yprime=-derive(eq,x,contextptr)/derive(eq,y,contextptr);
if (ndiff==1)
return yprime;
gen yn=yprime;
for (int n=2;n<=ndiff;++n){
yn=ratnormal(derive(yn,x,contextptr)+derive(yn,y,contextptr)*yprime,contextptr);
}
return yn;
}
static const char _implicit_diff_s []="implicit_diff";
static define_unary_function_eval (__implicit_diff,&_implicit_diff,_implicit_diff_s);
define_unary_function_ptr5( at_implicit_diff ,alias_at_implicit_diff,&__implicit_diff,0,true);
// mode==0 for domain, ==1 for singular values
void domain(const gen & f,const gen & x,vecteur & eqs,vecteur &excluded,int mode,GIAC_CONTEXT){
vecteur v=lvarxwithinv(f,x,contextptr);
lvar(f,v);
for (int i=0;ifeuille;
if (is_constant_wrt(g,x,contextptr))
continue;
if (g.type!=_SYMB)
continue;
gen gf=g._SYMBptr->feuille;
domain(gf,x,eqs,excluded,mode,contextptr);
unary_function_ptr & u=g._SYMBptr->sommet;
if (u==at_inv || u==at_Ei || (mode==1 && (u==at_ln || u==at_log10 || u==at_Ci))){
excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf,0),x),contextptr)));
continue;
}
if (u==at_pow){
if (mode==1){
excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf[0],0),x),contextptr)));
continue;
}
if (is_greater(gf[1],0,contextptr))
eqs.push_back(symb_superieur_egal(gf[0],0));
else
eqs.push_back(symb_superieur_strict(gf[0],0));
continue;
}
if (u==at_ln || u==at_log10 || u==at_Ci){
eqs.push_back(symb_superieur_strict(gf,0));
continue;
}
if (u==at_acosh){
if (mode==1)
excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(gf,0),x),contextptr)));
else
eqs.push_back(symb_superieur_egal(gf,1));
continue;
}
if (u==at_asin || u==at_acos || u==at_atanh){
if (mode==1)
excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(pow(gf,2,contextptr),0),x),contextptr)));
else
eqs.push_back(symb_inferieur_egal(pow(gf,2,contextptr),1));
continue;
}
if (u==at_tan){
excluded=mergevecteur(excluded,gen2vecteur(_solve(makesequence(symb_equal(symb_cos(gf),0),x),contextptr)));
continue;
}
if (u==at_sin || u==at_cos || u==at_exp || u==at_atan)
continue;
if (u==at_sinh || u==at_cosh || u==at_tanh)
continue;
if (u==at_floor || u==at_ceil || u==at_round || u==at_abs || u==at_sign || u==at_max || u==at_min)
continue;
*logptr(contextptr) << g << " function not supported, doing like if it was defined" << endl;
}
}
gen domain(const gen & f,const gen & x,int mode,GIAC_CONTEXT){
// domain of expression f with respect to variable x
if (x.type!=_IDNT){
gen domainx(identificateur("domainx"));
return domain(subst(f,x,domainx,false,contextptr),domainx,mode,contextptr);
}
vecteur eqs,excluded,res;
bool b=complex_mode(contextptr);
complex_mode(false,contextptr);
#ifndef NO_STDEXCEPT
try {
#endif
domain(f,x,eqs,excluded,mode,contextptr);
res=gen2vecteur(_solve(makesequence(eqs,x),contextptr));
#ifndef NO_STDEXCEPT
} catch (std::runtime_error & e ) { *logptr(contextptr) << e.what() << endl;}
#endif
complex_mode(b,contextptr);
comprim(excluded);
if (mode==1)
return excluded;
if (excluded.empty())
return res.size()==1?res.front():res;
vecteur tmp;
for (int i=0;ifeuille);
v.push_back(tmp[j]);
res[i]=symbolic(at_and,gen(v,_SEQ__VECT));
}
}
return res;
}
// not reached
if (res.size()==1){
tmp.insert(tmp.begin(),res.front());
return symbolic(at_and,gen(tmp,_SEQ__VECT));
}
tmp.insert(tmp.begin(),symbolic(at_ou,gen(res,_SEQ__VECT)));
return symbolic(at_and,gen(tmp,_SEQ__VECT));
}
gen _domain(const gen & args,GIAC_CONTEXT){
if (is_undef(args)) return args;
if (args.type!=_VECT || args.subtype!=_SEQ__VECT)
return domain(args,vx_var,0,contextptr);
vecteur v=*args._VECTptr;
if (v.size()<2)
return gensizeerr(contextptr);
if (is_integral(v[1]))
v.insert(v.begin()+1,vx_var);
if (v.size()==2)
v.push_back(0);
if (v[2].type!=_INT_)
return gensizeerr(contextptr);
return domain(v[0],v[1],v[2].val,contextptr);
}
static const char _domain_s []="domain";
static define_unary_function_eval (__domain,&_domain,_domain_s);
define_unary_function_ptr5( at_domain ,alias_at_domain,&__domain,0,true);
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC