File indexing completed on 2024-04-28 03:40:46

0001 /*************************************************************************************
0002  *  Copyright (C) 2007 by Aleix Pol <aleixpol@kde.org>                               *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "providederivative.h"
0020 #include "apply.h"
0021 #include "expression.h"
0022 #include "analitzautils.h"
0023 #include "value.h"
0024 #include "container.h"
0025 #include "variable.h"
0026 
0027 #include "list.h"
0028 #include "vector.h"
0029 #include "transformation.h"
0030 #include <QCoreApplication>
0031 
0032 using namespace Analitza;
0033 using namespace AnalitzaUtils;
0034 
0035 QList<Transformation> s_transformations;
0036 
0037 bool independentTree(const Object* o)
0038 {
0039     return !hasVars(o);
0040 }
0041 
0042 ProvideDerivative::ProvideDerivative(const QString& var) : var(var)
0043 {
0044     if(s_transformations.isEmpty()) {
0045         QMap<QString, Transformation::treeCheck> nat;
0046         nat.insert(QStringLiteral("Real"), independentTree);
0047         
0048         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(x:x)")), Transformation::parse(QStringLiteral("1")));
0049         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(sin(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)*cos(p)")));
0050         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(cos(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)*(-sin p)")));
0051         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(tan(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)/(cos(p)**2)")));
0052         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(f/g:x)")), Transformation::parse(QStringLiteral("(diff(f:x)*g-f*diff(g:x))/g**2")));
0053         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(ln(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)/p")));
0054         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(log(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)/(ln(10)*p)")));
0055         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(f**Real:x)")), Transformation::parse(QStringLiteral("Real*diff(f:x)*f**(Real-1)")), nat); //this is just a simplification, should be deprecated
0056         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(f**g:x)")), Transformation::parse(QStringLiteral("f**g*(diff(g:x)*ln f+g/f*diff(f:x))")));
0057         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(abs(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)*p/abs(p)")));
0058         s_transformations += Transformation(Transformation::parse(QStringLiteral("diff(exp(p):x)")), Transformation::parse(QStringLiteral("diff(p:x)*exp(p)")));
0059     }
0060 }
0061 
0062 Object* ProvideDerivative::run(const Object* o)
0063 {
0064     Apply* a=makeDiff(const_cast<Object*>(o));
0065     Object* ret = walk(a);
0066     clearDiff(a);
0067     return ret;
0068 }
0069 
0070 Object* ProvideDerivative::walkApply(const Apply* a)
0071 {
0072     if(a->firstOperator().operatorType()==Operator::diff) {
0073         Object* val = *a->firstValue();
0074         if(!hasTheVar(QSet<QString>() << var, val))
0075             return new Cn(0.);
0076         
0077         foreach(const Transformation& t, s_transformations) {
0078             Object* newTree = t.applyTransformation(a);
0079             if(newTree) {
0080                 Object* ret=walk(newTree);
0081                 delete newTree;
0082                 return ret;
0083             }
0084         }
0085         Object* ret = nullptr;
0086         if(val->isApply()) ret=derivativeApply(static_cast<Apply*>(val));
0087         else if(val->isContainer()) ret=derivativeContainer(static_cast<Container*>(val));
0088         else if(val->type()==Object::list) ret=derivateContentList(static_cast<const List*>(val));
0089         else if(val->type()==Object::vector) ret=derivateContentVector(static_cast<const Vector*>(val));
0090         
0091         if(!ret) {
0092             ret = a->copy();
0093             m_errors += QCoreApplication::tr("Could not calculate the derivative for '%1'").arg(ret->toString());
0094         }
0095         return ret;
0096     } else
0097         return AbstractExpressionTransformer::walkApply(a);
0098 }
0099 
0100 #define ITERATE(T, ...)\
0101 Object* ProvideDerivative::derivateContent##T(const T * v)\
0102 {\
0103     T* ret = new T(__VA_ARGS__);\
0104     T::const_iterator it=v->constBegin(), itEnd=v->constEnd();\
0105     for(; it!=itEnd; ++it) {\
0106         Apply* a=makeDiff(*it);\
0107         ret->appendBranch(walk(a));\
0108         clearDiff(a);\
0109     }\
0110     return ret;\
0111 }
0112 
0113 ITERATE(List, {})
0114 ITERATE(Vector, v->size())
0115 
0116 Object* ProvideDerivative::derivativeApply(const Apply* c)
0117 {
0118     Operator op = c->firstOperator();
0119     switch(op.operatorType()) {
0120         case Operator::minus:
0121         case Operator::plus: {
0122             Apply *r= new Apply;
0123             r->appendBranch(new Operator(op));
0124             
0125             Apply::const_iterator it(c->firstValue());
0126             for(; it!=c->constEnd(); ++it) {
0127                 Apply* a=makeDiff(*it);
0128                 r->appendBranch(walk(a));
0129                 clearDiff(a);
0130             }
0131             return r;
0132         } break;
0133         case Operator::times: {
0134             Apply *nx = new Apply;
0135             nx->appendBranch(new Operator(Operator::plus));
0136             
0137             Apply::const_iterator it(c->firstValue());
0138             for(; it!=c->constEnd(); ++it) {
0139                 Apply *neach = new Apply;
0140                 neach->appendBranch(new Operator(Operator::times));
0141                 
0142                 Apply::const_iterator iobj(c->firstValue());
0143                 for(; iobj!=c->constEnd(); ++iobj) {
0144                     Object* o;
0145                     if(iobj==it) {
0146                         Apply* a=makeDiff(*iobj);
0147                         o=walk(a);
0148                         clearDiff(a);
0149                     } else
0150                         o=(*iobj)->copy();
0151                     
0152                     neach->appendBranch(o);
0153                 }
0154                 nx->appendBranch(neach);
0155             }
0156             return nx;
0157         } break;
0158         default:
0159             break;
0160     }
0161     return nullptr;
0162 }
0163 
0164 Object* ProvideDerivative::derivativeContainer(const Container *c)
0165 {
0166     if(c->containerType()==Container::lambda) {
0167         //TODO REVIEW
0168         return walk(makeDiff(c->m_params.last()));
0169     } else if(c->containerType()==Container::piecewise) {
0170         Container *newPw = new Container(Container::piecewise);
0171         
0172         foreach(Object* o, c->m_params) {
0173             Q_ASSERT(o->isContainer());
0174             Container *p = (Container *) o;
0175             Container *np = new Container(p->containerType());
0176             
0177             Apply* a=makeDiff(p->m_params[0]);
0178             np->m_params += walk(a);
0179             clearDiff(a);
0180             if(p->m_params.size()>1)
0181                 np->m_params += p->m_params[1]->copy();
0182             newPw->appendBranch(np);
0183         }
0184         return newPw;
0185     } else if(c->containerType()==Container::declare) {
0186         Q_ASSERT(false);
0187         return c->copy();
0188     } else {
0189         Container *cret = new Container(c->containerType());
0190         foreach(Object* o, c->m_params) {
0191             Apply* a=makeDiff(o);
0192             cret->appendBranch(walk(a));
0193             clearDiff(a);
0194         }
0195         
0196         return cret;
0197     }
0198     return nullptr;
0199 }
0200 
0201 Apply* ProvideDerivative::makeDiff(Object* o) const
0202 {
0203     Apply* a = new Apply;
0204     a->appendBranch(new Operator(Operator::diff));
0205     a->appendBranch(o);
0206     a->addBVar(new Ci(var));
0207     
0208     return a;
0209 }
0210 
0211 void ProvideDerivative::clearDiff(Apply* a)
0212 {
0213     *a->firstValue()=nullptr;
0214     delete a;
0215 }