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

0001 /*************************************************************************************
0002  *  Copyright (C) 2011 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 "polynomial.h"
0020 #include "apply.h"
0021 #include "value.h"
0022 #include "analitzautils.h"
0023 #include "operations.h"
0024 #include "analyzer.h"
0025 
0026 using namespace Analitza;
0027 
0028 // static QDebug operator<<(QDebug dbg, const Object* c)
0029 // {
0030 //     dbg.nospace() << (c ? c->toString() : "<null>");
0031 //
0032 //     return dbg.space();
0033 // }
0034 //
0035 // static QDebug operator<<(QDebug dbg, const Monomial &c)
0036 // {
0037 //     dbg.nospace() << "(" << c.first << ", " << c.second << ")";
0038 //
0039 //     return dbg.space();
0040 // }
0041 
0042 static Object* negateObject(Object* o)
0043 {
0044     if(o->type()==Operator::value) {
0045         Cn* v = static_cast<Cn*>(o);
0046         v->rvalue() *= -1;
0047         return v;
0048     } else {
0049         Apply* a = new Apply;
0050         a->appendBranch(new Operator(Operator::minus));
0051         a->appendBranch(o);
0052         return a;
0053     }
0054 }
0055 
0056 static Object* simpExpression(Object* o)
0057 {
0058     Analyzer a;
0059     a.setExpression(Expression(o));
0060     a.simplify();
0061     Expression ret = a.expression();
0062     return ret.takeTree();
0063 }
0064 
0065 bool Monomial::isScalar(const Object* o)
0066 {
0067     return o->type()==Object::value || (o->type()==Object::vector && !AnalitzaUtils::hasVars(o));
0068 }
0069 
0070 Object* Monomial::createMono(const Operator& o) const
0071 {
0072     Operator::OperatorType mult = o.multiplicityOperator();
0073     
0074     Object* toAdd=nullptr;
0075     if(first==0.)
0076         delete second;
0077     else if(first==1.)
0078         toAdd=second;
0079     else if(first==-1. && mult==Operator::times)
0080         toAdd=negateObject(second);
0081     else if(mult==Operator::times && second->isApply() && static_cast<Apply*>(second)->firstOperator()==Operator::times) {
0082         Apply* res = static_cast<Apply*>(second);
0083         res->prependBranch(new Cn(first));
0084         toAdd=res;
0085     } else {
0086         Apply *cint = new Apply;
0087         cint->appendBranch(new Operator(mult));
0088         if(mult==Operator::times) {
0089             cint->appendBranch(new Cn(first));
0090             cint->appendBranch(second);
0091         } else {
0092             cint->appendBranch(second);
0093             cint->appendBranch(new Cn(first));
0094         }
0095         toAdd=cint;
0096     }
0097     return toAdd;
0098 }
0099 
0100 Monomial::Monomial(const Operator& o, Object* o2, bool& sign)
0101 {
0102     bool ismono=false;
0103     Operator::OperatorType mult = o.multiplicityOperator();
0104     
0105     if(o2->isApply()) {
0106         Apply *cx = (Apply*) o2;
0107         if(cx->firstOperator()==mult) {
0108             if(cx->countValues()==2) {
0109                 bool valid=false;
0110                 int scalar, var;
0111                 
0112                 if(mult!=Operator::power && cx->m_params[0]->type()==Object::value) {
0113                     scalar=0;
0114                     var=1;
0115                     valid=true;
0116                 } else if(cx->m_params[1]->type()==Object::value) {
0117                     scalar=1;
0118                     var=0;
0119                     valid=true;
0120                 }
0121                 
0122                 if(valid) {
0123 //                     qDebug() << ";;;;;;;" << o2->toString();
0124                     Cn* sc= (Cn*) cx->m_params[scalar];
0125                     first = sc->value();
0126                     second = cx->m_params[var];
0127                     
0128                     cx->m_params[var]=nullptr;
0129                     delete cx;
0130                     
0131                     ismono=true;
0132 //                     qDebug() << ":::::::" << *this;
0133                 }
0134             } else if(mult==Operator::times) {
0135                 first=1;
0136                 Apply::iterator it=cx->firstValue(), itEnd=cx->end();
0137                 QVector<Object*> vars;
0138                 QVector<Object*> values;
0139                 
0140                 for(; it!=itEnd; ++it) {
0141                     if((*it)->type()==Object::value) {
0142                         first *= static_cast<Cn*>(*it)->value();
0143                         values += *it;
0144                         ismono=true;
0145                     } else {
0146                         vars += *it;
0147                     }
0148                 }
0149                 
0150                 if(ismono) {
0151                     cx->m_params = vars;
0152                     second = cx;
0153                     qDeleteAll(values);
0154                 }
0155             }
0156         } else if(cx->firstOperator()==Operator::minus && cx->isUnary()) {
0157             *this = Monomial(o, *cx->firstValue(), sign);
0158             *cx->firstValue()=nullptr;
0159             delete cx;
0160             ismono=true;
0161                 
0162             if(o==Operator::times)
0163                 sign = !sign;
0164             else if(o==Operator::plus || o==Operator::minus)
0165                 first *= -1;
0166         }
0167     } else if(o2->type()==Object::value && (o==Operator::plus || o==Operator::minus)) {
0168         Cn* v=static_cast<Cn*>(o2);
0169         if(v->value()<0) {
0170             v->rvalue()*=-1;
0171             first = -1;
0172             second = o2;
0173             ismono = true;
0174         }
0175     }
0176     
0177     if(!ismono) {
0178         first = 1.;
0179         second = o2;
0180     }
0181 }
0182 
0183 bool Monomial::isValue() const
0184 {
0185     return isScalar(second);
0186 }
0187 
0188 Polynomial::Polynomial(Apply* c)
0189     : m_operator(c->firstOperator())
0190     , m_sign(true)
0191 {
0192     bool first = true, firstValue = false;
0193     QList<Monomial> monos;
0194 //     qDebug() << "1.........." << c->toString();
0195     for(Apply::const_iterator it=c->constBegin(), itEnd=c->constEnd(); it!=itEnd; ++it, first=false) {
0196         Monomial imono(m_operator, *it, m_sign);
0197         
0198         bool added=false;
0199         if(imono.second->isApply() && imono.first == 1) {
0200             Apply* a = static_cast<Apply*>(imono.second);
0201             Operator op=a->firstOperator();
0202             if(a->firstOperator()==m_operator
0203                 || (m_operator==Operator::minus && op==Operator::plus)
0204                 || (m_operator==Operator::plus && op==Operator::minus)
0205             ) {
0206                 Polynomial p(a);
0207                 
0208                 a->m_params.clear();
0209                 delete a;
0210                 
0211                 if((!first && m_operator==Operator::plus && op==Operator::minus)
0212                     || (first && m_operator==Operator::minus && op==Operator::plus)
0213                     || (first && m_operator==Operator::minus && op==Operator::minus)
0214                 )
0215                 {
0216                     //if it's a minus, the first is already positive
0217                     p.negate(1);
0218                 }
0219                 
0220                 monos.append(p);
0221                 added=true;
0222             }
0223         }
0224         
0225         if(!added)
0226             monos.append(imono);
0227     }
0228     
0229     first = true;
0230     for(auto it=monos.begin(), itEnd=monos.end(); it!=itEnd; ++it, first=false) {
0231         if(m_operator==Operator::minus && !first)
0232             it->first*=-1;
0233     }
0234     
0235     for(auto it=monos.begin(), itEnd=monos.end(); it!=itEnd; ++it, first=false)
0236         addMonomial(*it);
0237     
0238     simpScalars(firstValue);
0239 }
0240 
0241 void Polynomial::addMonomial(const Monomial& m)
0242 {
0243     if(m.isValue()) {
0244         m_scalars += m.createMono(m_operator);
0245         return;
0246     }
0247     
0248     bool found = false;
0249     auto it1(begin());
0250     for(; it1!=end(); ++it1) {
0251         Object *o1=it1->second, *o2=m.second;
0252         found = AnalitzaUtils::equalTree(o1, o2);
0253         if(found)
0254             break;
0255     }
0256     
0257     if(found) {
0258         it1->first += m.first;
0259         delete m.second;
0260         
0261         if(it1->first==0.) {
0262             delete it1->second;
0263             erase(it1);
0264         }
0265     } else {
0266         append(m);
0267     }
0268 }
0269 
0270 void Polynomial::simpScalars(bool firstValue)
0271 {
0272     Object *value=nullptr;
0273     if(!firstValue && m_operator==Operator::minus && !m_scalars.isEmpty())
0274         m_scalars.first() = negateObject(m_scalars.first());
0275 
0276     for(auto i=m_scalars.constBegin(); i!=m_scalars.constEnd(); ++i) {
0277         bool d=false;
0278         
0279         Object* aux = simpExpression(*i);
0280         if(value) {
0281             QString* err=nullptr;
0282             value=Operations::reduce(m_operator.operatorType(), value, aux, &err);
0283             d=err;
0284             delete err;
0285         } else
0286             value=aux;
0287         
0288         if(d) {
0289             addValue(aux);
0290             value=nullptr;
0291         }
0292     }
0293     
0294     addValue(value);
0295     m_scalars.clear();
0296 }
0297 
0298 void Polynomial::addValue(Object* value)
0299 {
0300     bool sign=false;
0301     if(!value)
0302         return;
0303     
0304     if(value->isZero())
0305         delete value;
0306     else {
0307         Monomial imono(m_operator, value, sign);
0308         
0309         if(m_operator==Operator::plus)
0310             append(imono);
0311         else if(m_operator==Operator::minus) {
0312             imono.first *= -1;
0313             append(imono);
0314         } else
0315             prepend(imono);
0316     }
0317 }
0318 
0319 Object* Polynomial::toObject()
0320 {
0321     Object* root = nullptr;
0322     if(count()==1) {
0323         root = first().createMono(m_operator);
0324     } else if(count()>1) {
0325         Apply* c = new Apply;
0326         c->appendBranch(new Operator(m_operator));
0327         
0328         auto i=begin();
0329         bool first=true;
0330         for(; i!=end(); ++i, first=false) {
0331             if(!first && m_operator==Operator::minus)
0332                 i->first *= -1;
0333             
0334             Object* toAdd=i->createMono(m_operator);
0335             if(toAdd)
0336                 c->appendBranch(toAdd);
0337         }
0338         root=c;
0339     }
0340     
0341     if(!root) {
0342         root=new Cn(0.);
0343     } else if(!m_sign) {
0344         root = negateObject(root);
0345     }
0346     
0347     return root;
0348 }
0349 
0350 void Polynomial::negate(int i)
0351 {
0352     for(iterator it=begin(); it!=end(); ++it, --i) {
0353         if(i<=0)
0354             it->first *= -1;
0355     }
0356 }