SundanceFunctionalPolynomial.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                             Sundance
00005 //                 Copyright 2011 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 #include "SundanceFunctionalPolynomial.hpp"
00043 #include "PlayaTabs.hpp"
00044 #include "SundanceOut.hpp"
00045 #include "SundanceExpr.hpp"
00046 #include "SundanceEvaluatorFactory.hpp"
00047 #include "SundanceEvaluator.hpp"
00048 #include "SundanceSymbolicFuncElement.hpp"
00049 #include "SundanceDerivOfSymbFunc.hpp"
00050 #include "SundanceUnaryExpr.hpp"
00051 
00052 
00053 using namespace Sundance;
00054 using namespace Sundance;
00055 
00056 using namespace Sundance;
00057 using namespace Teuchos;
00058 
00059 
00060 
00061 FunctionalPolynomial::FunctionalPolynomial(const RCP<ScalarExpr>& expr)
00062   : funcs_(),
00063     funcMultiIndices_(),
00064     coeffs_(),
00065     keys_()
00066 {
00067   TEUCHOS_TEST_FOR_EXCEPTION(!isConvertibleToPoly(expr.get()), std::logic_error, 
00068                      "FunctionalPolynomial ctor called with an argument that "
00069                      "cannot be converted to a polynomial");
00070   int funcID;
00071   MultiIndex mi;
00072   Deriv deriv;
00073 
00074   const SymbolicFuncElement* s 
00075     = dynamic_cast<const SymbolicFuncElement*>(expr.get());
00076   if (s != 0)
00077     {
00078       mi = MultiIndex();
00079       deriv = funcDeriv(s);
00080     }
00081   
00082   const DerivOfSymbFunc* d
00083     = dynamic_cast<const DerivOfSymbFunc*>(expr.get());
00084   if (d != 0)
00085     {
00086       deriv = d->representMeAsFunctionalDeriv();
00087     }
00088 
00089   MultipleDeriv mu;
00090   mu.put(deriv);
00091 
00092 
00093   if (d != 0 || s != 0)
00094     {
00095       funcs_.put(funcID, expr);
00096       Set<MultiIndex> miSet;
00097       miSet.put(mi);
00098       funcMultiIndices_.put(funcID, miSet);
00099 
00100       Expr coeff = 1.0;
00101       RCP<ScalarExpr> cPtr = rcp_dynamic_cast<ScalarExpr>(coeff.ptr());
00102 
00103       coeffs_.resize(2);
00104       keys_.resize(2);
00105       coeffs_[1].put(mu, cPtr);
00106       keys_[1].put(mu);
00107     }
00108   else
00109     {
00110       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 
00111                          "impossible case in FunctionalPolynomial ctor");
00112     }
00113 }
00114 
00115 
00116 FunctionalPolynomial::FunctionalPolynomial(const Map<int, RCP<ScalarExpr> >& funcs,
00117                                            const Map<int, Set<MultiIndex> >& funcMultiIndices,
00118                                            const Array<Map<MultipleDeriv, RCP<ScalarExpr> > > & coeffs)
00119   : funcs_(funcs),
00120     funcMultiIndices_(funcMultiIndices),
00121     coeffs_(coeffs),
00122     keys_(coeffs.size())
00123 {
00124   typedef Map<MultipleDeriv, RCP<ScalarExpr> > termMap;
00125 
00126   for (int i=0; i < coeffs_.size(); i++)
00127     {
00128       for (termMap::const_iterator 
00129              j = coeffs_[i].begin(); j != coeffs_[i].end(); j++)
00130         {
00131           const MultipleDeriv& key = j->first;
00132           keys_[i].put(key);
00133         }
00134     }
00135 }
00136 
00137 
00138 Set<MultipleDeriv> 
00139 FunctionalPolynomial::internalFindW(int order, const EvalContext& context) const
00140 {
00141   TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 
00142                      "FunctionalPolynomial not implemented");
00143   return Set<MultipleDeriv> ();
00144 }
00145 
00146 
00147 RCP<FunctionalPolynomial> FunctionalPolynomial::
00148 addPoly(const FunctionalPolynomial* other, int sign) const 
00149 {
00150   typedef Map<MultipleDeriv, RCP<ScalarExpr> > termMap;
00151   Map<int, RCP<ScalarExpr> > newFuncs = funcs_;
00152   Map<int, Set<MultiIndex> > newFuncMultiIndices = funcMultiIndices_;
00153   Array<Map<MultipleDeriv, RCP<ScalarExpr> > > newCoeffs = coeffs_;
00154 
00155   if (other->coeffs_.size() > coeffs_.size()) 
00156     newCoeffs.resize(other->coeffs_.size());
00157 
00158 
00159   for (int i=0; i < other->coeffs_.size(); i++)
00160     {
00161       
00162       for (termMap::const_iterator 
00163              j = other->coeffs_[i].begin(); j != other->coeffs_[i].end(); j++)
00164         {
00165           const MultipleDeriv& key = j->first;
00166           Expr right = Expr::handle(j->second);
00167           Expr sum;
00168       
00169           if (newCoeffs[i].containsKey(key))
00170             {
00171               Expr left = Expr::handle(newCoeffs[i].get(key));
00172 
00173               if (sign > 0) sum = left + right;
00174               else sum = left - right;
00175             }
00176           else
00177             {
00178               if (sign > 0) sum = right;
00179               else sum = -right;
00180             }
00181       
00182           const ScalarExpr* se = dynamic_cast<const ScalarExpr*>(sum.ptr().get());
00183           TEUCHOS_TEST_FOR_EXCEPTION(se==0, std::logic_error,
00184                              "Sum could not be cast to scalar expression");
00185           newCoeffs[i].put(key, rcp_dynamic_cast<ScalarExpr>(sum.ptr()));
00186         }
00187     }
00188   
00189   for (Map<int, RCP<ScalarExpr> >::const_iterator 
00190          i = other->funcs_.begin(); i != other->funcs_.end(); i++)
00191     {
00192       newFuncs.put(i->first, i->second);
00193     }
00194 
00195   for (Map<int, Set<MultiIndex> >::const_iterator 
00196          i = other->funcMultiIndices_.begin(); 
00197        i != other->funcMultiIndices_.end(); i++)
00198     {
00199       newFuncMultiIndices.put(i->first, i->second);
00200     }
00201 
00202   
00203 
00204   return rcp(new FunctionalPolynomial(newFuncs, newFuncMultiIndices, newCoeffs));
00205 }
00206 
00207 RCP<FunctionalPolynomial> FunctionalPolynomial::
00208 multiplyPoly(const FunctionalPolynomial* other) const 
00209 {
00210   typedef Map<MultipleDeriv, RCP<ScalarExpr> > termMap;
00211   Map<int, RCP<ScalarExpr> > newFuncs;
00212   Map<int, Set<MultiIndex> > newFuncMultiIndices;
00213   Array<Map<MultipleDeriv, RCP<ScalarExpr> > > newCoeffs;
00214 
00215   newCoeffs.resize(coeffs_.size() + other->coeffs_.size() - 1);
00216 
00217   for (int i=0; i < coeffs_.size(); i++)
00218     {
00219       for (int j = 0; j<other->coeffs_.size(); j++)
00220         {
00221           for (termMap::const_iterator 
00222                  me = coeffs_[i].begin(); me != coeffs_[i].end(); me++)
00223             {
00224               const MultipleDeriv& myKey = me->first;
00225               Expr myExpr = Expr::handle(me->second);
00226               for (termMap::const_iterator 
00227                      you = other->coeffs_[j].begin(); 
00228                    you != other->coeffs_[j].end(); you++)
00229                 {
00230                   const MultipleDeriv& yourKey = you->first;
00231                   Expr yourExpr = Expr::handle(you->second);
00232                   MultipleDeriv newKey = myKey.product(yourKey);
00233                   int order = i+j;
00234                   Expr newTerm = myExpr*yourExpr;
00235                   if (newCoeffs[order].containsKey(newKey))
00236                     {
00237                       Expr old = Expr::handle(newCoeffs[i].get(newKey));
00238                       newTerm = newTerm + old;
00239                     }
00240                   const ScalarExpr* se 
00241                     = dynamic_cast<const ScalarExpr*>(newTerm.ptr().get());
00242                   TEUCHOS_TEST_FOR_EXCEPTION(se==0, std::logic_error,
00243                                      "New coeff could not be cast to scalar expression");
00244                   newCoeffs[order].put(newKey, 
00245                                        rcp_dynamic_cast<ScalarExpr>(newTerm.ptr()));
00246                 }
00247             }
00248         }
00249     }
00250   
00251   for (Map<int, RCP<ScalarExpr> >::const_iterator 
00252          i = funcs_.begin(); i != funcs_.end(); i++)
00253     {
00254       newFuncs.put(i->first, i->second);
00255     }
00256   for (Map<int, RCP<ScalarExpr> >::const_iterator 
00257          i = other->funcs_.begin(); i != other->funcs_.end(); i++)
00258     {
00259       newFuncs.put(i->first, i->second);
00260     }
00261 
00262   for (Map<int, Set<MultiIndex> >::const_iterator 
00263          i = funcMultiIndices_.begin(); 
00264        i != funcMultiIndices_.end(); i++)
00265     {
00266       newFuncMultiIndices.put(i->first, i->second);
00267     }
00268   for (Map<int, Set<MultiIndex> >::const_iterator 
00269          i = other->funcMultiIndices_.begin(); 
00270        i != other->funcMultiIndices_.end(); i++)
00271     {
00272       Set<MultiIndex> miSet = i->second;
00273       if (newFuncMultiIndices.containsKey(i->first))
00274         {
00275           miSet.merge(newFuncMultiIndices.get(i->first));
00276         }
00277       newFuncMultiIndices.put(i->first, miSet);
00278     }
00279 
00280   return rcp(new FunctionalPolynomial(newFuncs, newFuncMultiIndices, newCoeffs));
00281 }
00282 
00283 RCP<FunctionalPolynomial> FunctionalPolynomial::
00284 addFunction(const RCP<ScalarExpr>& u, int sign) const 
00285 {
00286   RCP<FunctionalPolynomial> other = rcp(new FunctionalPolynomial(u));
00287   return addPoly(other.get(), sign);
00288 }
00289 
00290 RCP<FunctionalPolynomial> FunctionalPolynomial::
00291 multiplyScalar(const RCP<ScalarExpr>& alpha) const 
00292 {
00293   typedef Map<MultipleDeriv, RCP<ScalarExpr> > termMap;
00294 
00295   Array<Map<MultipleDeriv, RCP<ScalarExpr> > > newCoeffs = coeffs_;
00296 
00297   Expr alphaExpr = Expr::handle(alpha);
00298 
00299   for (int i=0; i < coeffs_.size(); i++)
00300     {
00301       for (termMap::const_iterator 
00302              j = coeffs_[i].begin(); j != coeffs_[i].end(); j++)
00303         {
00304           const MultipleDeriv& key = j->first;
00305           Expr oldCoeff = Expr::handle(j->second);
00306           Expr newCoeff = alphaExpr*oldCoeff;
00307 
00308           const ScalarExpr* se 
00309             = dynamic_cast<const ScalarExpr*>(newCoeff.ptr().get());
00310           TEUCHOS_TEST_FOR_EXCEPTION(se==0, std::logic_error,
00311                              "Coefficient could not be cast to "
00312                              "scalar expression");
00313       
00314           newCoeffs[i].put(key, rcp_dynamic_cast<ScalarExpr>(newCoeff.ptr()));
00315         }
00316     }
00317   
00318   return rcp(new FunctionalPolynomial(funcs_, funcMultiIndices_, newCoeffs));
00319 }
00320 
00321 
00322 Evaluator* FunctionalPolynomial::createEvaluator(const EvaluatableExpr* expr,
00323                                                  const EvalContext& context) const
00324 {
00325   TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "poly eval not ready");
00326   return (Evaluator*) 0;
00327 }
00328 
00329 
00330 
00331 bool FunctionalPolynomial::isConvertibleToPoly(const ScalarExpr* expr)
00332 {
00333   const SymbolicFuncElement* s 
00334     = dynamic_cast<const SymbolicFuncElement*>(expr);
00335   
00336   const DerivOfSymbFunc* d
00337     = dynamic_cast<const DerivOfSymbFunc*>(expr);
00338 
00339   const FunctionalPolynomial* p
00340     = dynamic_cast<const FunctionalPolynomial*>(expr);
00341 
00342   return (s != 0 || d != 0 || p != 0);
00343 }
00344 
00345 
00346 RCP<FunctionalPolynomial> FunctionalPolynomial::toPoly(const RCP<ScalarExpr>& expr)
00347 {
00348   const FunctionalPolynomial* p
00349     = dynamic_cast<const FunctionalPolynomial*>(expr.get());
00350 
00351   if (p != 0) return rcp_dynamic_cast<FunctionalPolynomial>(expr);
00352 
00353   Expr rtn = new FunctionalPolynomial(expr);
00354   return rcp_dynamic_cast<FunctionalPolynomial>(rtn.ptr());
00355 }
00356 
00357 
00358 std::ostream& FunctionalPolynomial::toText(std::ostream& os, bool paren) const
00359 {
00360   os << evalString();
00361   return os;
00362 }
00363 
00364 
00365 XMLObject FunctionalPolynomial::toXML() const
00366 {
00367   XMLObject rtn("Polynomial");
00368   for (int order=0; order<coeffs_.size(); order++)
00369     {
00370       for (Map<MultipleDeriv, RCP<ScalarExpr> >::const_iterator
00371              i = coeffs_[order].begin(); i != coeffs_[order].end(); i++)
00372         {
00373           const MultipleDeriv& key = i->first;
00374           Expr e = Expr::handle(i->second);
00375           XMLObject term("Term");
00376           XMLObject coeff("Coeff");
00377           coeff.addChild(e.toXML());
00378           term.addChild(coeff);
00379           for (MultipleDeriv::const_iterator
00380                  j = key.begin(); j != key.end(); j++)
00381             {
00382               XMLObject f("FunctionalDeriv");
00383               f.addAttribute("mu", j->toString());
00384               term.addChild(f);
00385             }
00386           rtn.addChild(term);
00387         }
00388     }
00389   return rtn;
00390 }
00391 
00392 Set<Deriv> FunctionalPolynomial
00393 ::findFuncsForSummation(const Set<MultipleDeriv>& prevSet,
00394                         const MultipleDeriv& currentDeriv) const
00395 {
00396   Set<Deriv> rtn;
00397 
00398   for (Set<MultipleDeriv>::const_iterator
00399          i = prevSet.begin(); i != prevSet.end(); i++)
00400     {
00401       const MultipleDeriv& mdPrev = *i;
00402       TEUCHOS_TEST_FOR_EXCEPTION(currentDeriv.size()+1 != mdPrev.size(),
00403                          std::logic_error,
00404                          "deriv orders must differ by 1. Found "
00405                          "currentDeriv.size()=" << currentDeriv.size()
00406                          << " while mdPrev.size()=" << mdPrev.size());
00407 
00408       /* We are looking for cases where the previous multiple derivative
00409        * is equal to the current plus one *greater* element. In such cases, the
00410        * set difference will contain exactly one element, and that element
00411        * will be greater than or equal to the the upper bound of the current 
00412        * set */
00413       Set<Deriv> tmp;
00414       set_difference(mdPrev.begin(), mdPrev.end(),
00415                      currentDeriv.begin(), currentDeriv.end(),
00416                      inserter(tmp, tmp.begin()));
00417       if (tmp.size()==1)
00418         {
00419           const Deriv& d = *(tmp.begin());
00420           if (currentDeriv.upper_bound(d) == currentDeriv.end()) rtn.put(d);
00421         }
00422     }
00423   return rtn;
00424 }
00425 
00426 
00427 MultipleDeriv FunctionalPolynomial::successorTerm(const MultipleDeriv& md) const
00428 {
00429   MultipleDeriv rtn;
00430 
00431   unsigned int k = 0;
00432   for (MultipleDeriv::const_iterator i=md.begin(); i!=md.end(); i++, k++)
00433     {
00434       if (k < md.size()-1) rtn.put(*i);
00435     }
00436   return rtn;
00437 }
00438 
00439 void FunctionalPolynomial
00440 ::stepRecurrence(int level, const Map<MultipleDeriv, std::string>& sPrev,
00441                  Map<MultipleDeriv, std::string>& sCurr) const 
00442 {
00443   Set<MultipleDeriv> allKeys;
00444   Set<MultipleDeriv> inducedKeys;
00445   Set<MultipleDeriv> prevKeys;
00446   for (Map<MultipleDeriv, std::string>::const_iterator 
00447          i = sPrev.begin(); i != sPrev.end(); i++)
00448     {
00449       inducedKeys.put(successorTerm(i->first));
00450     }
00451   for (Map<MultipleDeriv, std::string>::const_iterator 
00452          i = sPrev.begin(); i != sPrev.end(); i++)
00453     {
00454       prevKeys.put(i->first);
00455     }
00456 
00457   Out::os() << "keys from prev level are " << prevKeys << std::endl;
00458   Out::os() << "induced keys are " << inducedKeys << std::endl;
00459   Out::os() << "natural keys are " << keys_[level] << std::endl;
00460 
00461   allKeys.merge(inducedKeys);
00462   allKeys.merge(keys_[level]);
00463 
00464   Out::os() << "keys active at this level are " << allKeys << std::endl;
00465 
00466   for (Set<MultipleDeriv>::const_iterator 
00467          i = allKeys.begin(); i != allKeys.end(); i++)
00468     {
00469       const MultipleDeriv& key = *i;
00470       Out::os() << "working on key " << key << std::endl;
00471       std::string str;
00472       if (coeffs_[level].containsKey(key))
00473         {
00474           str = coeffs_[level].get(key)->toString();
00475         }
00476 
00477       Set<Deriv> funcs = findFuncsForSummation(prevKeys, key);
00478       Out::os() << "funcs to sum are " << funcs << std::endl;
00479       for (Set<Deriv>::const_iterator 
00480              j = funcs.begin(); j != funcs.end(); j++)
00481         {
00482           MultipleDeriv prevKey = key;
00483           Out::os() << "prev key = " << prevKey << std::endl;
00484           Out::os() << "func = " << *j << std::endl;
00485           // if (key.size() > 0 && key.upper_bound(*j) == key.end()) 
00486           //  {
00487           //    Out::os() << "skipping" << std::endl;
00488           //    continue;
00489           // }
00490           prevKey.put(*j);
00491           TEUCHOS_TEST_FOR_EXCEPTION(!sPrev.containsKey(prevKey), std::logic_error,
00492                              "inconsisent key lookup");
00493           const std::string& prevStr = sPrev.get(prevKey);
00494           std::string funcStr = (*j).toString();
00495           if (str.length() > 0) str += " + ";
00496           str += funcStr + "*(" + prevStr + ")";
00497         }
00498       if (str.length() > 0) sCurr.put(key, str);
00499     }
00500 }
00501 
00502 string FunctionalPolynomial::evalString() const
00503 {
00504   int maxLevel = coeffs_.size()-1;
00505 
00506   Map<MultipleDeriv, std::string> sPrev;
00507   Map<MultipleDeriv, std::string> sCurr;
00508 
00509   for (int level=maxLevel; level>=0; level--)
00510     {
00511       Out::os() << "********* Recurrence level = " << level << " ***************"
00512            << std::endl;      
00513       sCurr = Map<MultipleDeriv, std::string>();
00514       stepRecurrence(level, sPrev, sCurr);
00515       sPrev = sCurr;
00516 
00517       for (Map<MultipleDeriv, std::string>::const_iterator 
00518              j = sCurr.begin(); j != sCurr.end(); j++)
00519         {
00520           Out::os() << "key=" << j->first << std::endl;
00521           Out::os() << "value=" << j->second << std::endl;
00522         }
00523     }
00524 
00525   //  TEUCHOS_TEST_FOR_EXCEPTION(sCurr.size() != 1, std::logic_error,
00526   //                     "final value should have only one element");
00527 
00528   return sCurr.begin()->second;
00529 }
00530 
00531 
00532 
00533 bool FunctionalPolynomial::lessThan(const ScalarExpr* other) const
00534 {
00535   const FunctionalPolynomial* f = dynamic_cast<const FunctionalPolynomial*>(other);
00536   TEUCHOS_TEST_FOR_EXCEPTION(f==0, std::logic_error, "cast should never fail at this point");
00537   
00538   TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "FunctionalPolynomial::lessThan() not "
00539                      "implemented");
00540 }
00541 
00542   

Site Contact