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 }