SundanceExpr.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 "SundanceExpr.hpp"
00043 #include "SundanceListExpr.hpp"
00044 #include "SundanceSumExpr.hpp"
00045 #include "SundanceProductExpr.hpp"
00046 #include "SundanceConstantExpr.hpp"
00047 #include "SundanceCoordExpr.hpp"
00048 #include "SundanceDerivative.hpp"
00049 #include "SundanceDiffOp.hpp"
00050 
00051 
00052 #include "SundanceUnaryMinus.hpp"
00053 #include "SundanceZeroExpr.hpp"
00054 #include "SundanceComplexExpr.hpp"
00055 #include "SundanceOut.hpp"
00056 #include "PlayaTabs.hpp"
00057 #include "SundanceStdSumTransformations.hpp"
00058 #include "SundanceStdProductTransformations.hpp"
00059 #include "SundanceNonlinearUnaryOp.hpp"
00060 #include "SundanceStdMathOps.hpp"
00061 #include "SundanceParameter.hpp"
00062 #include "SundanceSpectralBasis.hpp"
00063 #include "SundanceSpectralExpr.hpp"
00064 #include "SundanceUnknownFuncElement.hpp"
00065 #include "SundanceTestFuncElement.hpp"
00066 #include "Teuchos_TimeMonitor.hpp"
00067 
00068 using namespace Sundance;
00069 using namespace Sundance;
00070 
00071 using namespace Teuchos;
00072 using namespace Sundance;
00073 
00074 static Time& sumTimer() 
00075 {
00076   static RCP<Time> rtn 
00077     = TimeMonitor::getNewTimer("symbolic sum"); 
00078   return *rtn;
00079 }
00080 
00081 static Time& unaryMinusTimer() 
00082 {
00083   static RCP<Time> rtn 
00084     = TimeMonitor::getNewTimer("symbolic unary minus"); 
00085   return *rtn;
00086 }
00087 
00088 
00089 static Time& trySumComplexTimer() 
00090 {
00091   static RCP<Time> rtn 
00092     = TimeMonitor::getNewTimer("test for complex sum"); 
00093   return *rtn;
00094 }
00095 
00096 static Time& tryMultiplyComplexTimer() 
00097 {
00098   static RCP<Time> rtn 
00099     = TimeMonitor::getNewTimer("test for complex product"); 
00100   return *rtn;
00101 }
00102 
00103 
00104 
00105 static Time& prodTimer() 
00106 {
00107   static RCP<Time> rtn 
00108     = TimeMonitor::getNewTimer("symbolic product"); 
00109   return *rtn;
00110 }
00111 
00112 
00113 Expr::Expr(const double& c)
00114   : Playa::Handle<ExprBase>(new ConstantExpr(c))
00115 {}
00116 
00117 Expr::Expr(const std::complex<double>& c)
00118   : Playa::Handle<ExprBase>(new ComplexExpr(new ConstantExpr(c.real()),
00119       new ConstantExpr(c.imag())))
00120 {}
00121 
00122 bool Expr::isComplex() const
00123 {
00124   return dynamic_cast<const ComplexExpr*>(ptr().get()) != 0;
00125 }
00126 
00127 /*****************************************************************************************************************************************/
00128 
00129 bool Expr::isSpectral() const
00130 {
00131   return dynamic_cast<const SpectralExpr*>(ptr().get()) != 0;
00132 }
00133 /****************************************************************************************************************************************/
00134 
00135 
00136 
00137 XMLObject Expr::toXML() const
00138 {
00139   TimeMonitor t(outputTimer());
00140 
00141   return ptr()->toXML();
00142 }
00143 
00144 string Expr::toString() const 
00145 {
00146   TimeMonitor t(outputTimer());
00147 
00148   TeuchosOStringStream ss;
00149   ptr()->toText(ss, false);
00150   return TEUCHOS_OSTRINGSTREAM_GET_C_STR(ss);
00151 }
00152 
00153 
00154 bool Expr::sameAs(const Expr& other) const 
00155 {
00156   if (this->lessThan(other)) return false;
00157   if (other.lessThan(*this)) return false;
00158   return true;
00159 }
00160 
00161 bool Expr::operator<(const Expr& other) const 
00162 {
00163   return this->lessThan(other);
00164 }
00165 
00166 bool Expr::lessThan(const Expr& other) const
00167 {
00168   RCP<ScalarExpr> sThis = rcp_dynamic_cast<ScalarExpr>(ptr());
00169   RCP<ScalarExpr> sOther = rcp_dynamic_cast<ScalarExpr>(other.ptr());
00170 
00171   TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==0, std::logic_error,
00172     "ordering not defined for non-scalar expression "
00173     << toString());
00174 
00175   TEUCHOS_TEST_FOR_EXCEPTION(sOther.get()==0, std::logic_error,
00176     "ordering not defined for non-scalar expressions"
00177     << other.toString());
00178 
00179   
00180   const ConstantExpr* cMe = dynamic_cast<const ConstantExpr*>(sThis.get());
00181   const ConstantExpr* cOther = dynamic_cast<const ConstantExpr*>(sOther.get());
00182 
00183   /* constants are placed before any other expr type */
00184   if (cMe != 0 && cOther==0) return true;
00185   if (cOther != 0 && cMe==0) return false;
00186   if (cOther != 0 && cMe != 0) return cMe->lessThan(cOther);
00187 
00188   /* Move generic spatial constants, e.g., parameters to the left.
00189    * Because the values might change with time, we can't order on values.  */
00190   const SpatiallyConstantExpr* scMe 
00191     = dynamic_cast<const SpatiallyConstantExpr*>(sThis.get());
00192   const SpatiallyConstantExpr* scOther 
00193     = dynamic_cast<const SpatiallyConstantExpr*>(sOther.get());
00194   if (scMe != 0 && scOther==0) return true;
00195   if (scOther != 0 && scMe==0) return false;
00196 
00197 
00198   /* try ordering non-constant exprs by type name */
00199   if (sThis->typeName() < sOther->typeName()) return true;
00200   if (sThis->typeName() > sOther->typeName()) return false;
00201 
00202   /* if type names are the same, go to base class to do comparison */
00203   return sThis->lessThan(sOther.get());
00204 }
00205 
00206 Sundance::Map<Expr, int> Expr::getSumTree() const
00207 {
00208   RCP<ScalarExpr> sThis = rcp_dynamic_cast<ScalarExpr>(ptr());
00209 
00210   TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==0, std::logic_error,
00211     "etSumTree() not defined for non-scalar expression "
00212     << toString());
00213   
00214   const SumExpr* s = dynamic_cast<const SumExpr*>(sThis.get());
00215   const UnaryMinus* u = dynamic_cast<const UnaryMinus*>(sThis.get());
00216   if (s != 0)
00217   {
00218     return s->getSumTree();
00219   }
00220   else if (u != 0)
00221   {
00222     Sundance::Map<Expr, int> rtn;
00223     rtn.put(u->arg(), -1);
00224     return rtn;
00225   }
00226   else
00227   {
00228     Sundance::Map<Expr, int> rtn;
00229     rtn.put(*this, 1);
00230     return rtn;
00231   }
00232   
00233 }
00234 
00235 bool Expr::tryAddComplex(const Expr& L, const Expr& R, int sign,
00236   Expr& rtn) const
00237 {
00238   TimeMonitor t(trySumComplexTimer());
00239   TEUCHOS_TEST_FOR_EXCEPTION(L.size() != 1 || R.size() != 1, std::logic_error, 
00240     "non-scalar exprs should have been reduced before "
00241     "call to tryAddComplex(). Left=" << L << " right="
00242     << R);
00243   if (L.isComplex() || R.isComplex())
00244   {
00245     if (sign > 0) 
00246     {
00247       rtn = new ComplexExpr(L.real() + R.real(), 
00248         L.imag() + R.imag());
00249     }
00250     else
00251     {
00252       rtn = new ComplexExpr(L.real() - R.real(), 
00253         L.imag() - R.imag());
00254     }
00255     return true;
00256   }
00257   else
00258   {
00259     return false;
00260   }
00261 }
00262 
00263 
00264 
00265 bool Expr::tryMultiplyComplex(const Expr& L, const Expr& R,
00266   Expr& rtn) const
00267 {
00268   TimeMonitor t(tryMultiplyComplexTimer());
00269   TEUCHOS_TEST_FOR_EXCEPTION(L.size() != 1 || R.size() != 1, std::logic_error, 
00270     "non-scalar exprs should have been reduced before "
00271     "call to tryMultiplyComplex(). Left=" << L << " right="
00272     << R);
00273 
00274   if (L.isComplex() || R.isComplex())
00275   {
00276     if (Re(L).sameAs(Re(R)) && Im(L).sameAs(-Im(R)))
00277     {
00278       rtn = Re(R)*Re(R) + Im(R)*Im(R);
00279     }
00280     else
00281     {
00282       Expr re = Re(L)*Re(R) - Im(L)*Im(R);
00283       Expr im = Re(L)*Im(R) + Im(L)*Re(R);
00284       rtn = new ComplexExpr(re, im);
00285     }
00286     return true;
00287   }
00288   else
00289   {
00290     return false;
00291   }
00292 }
00293 
00294 
00295 
00296 
00297 Expr Expr::operator+(const Expr& other) const 
00298 {
00299   TimeMonitor t(opTimer());
00300   TimeMonitor ts(sumTimer());
00301 
00302   /* Thread addition over list elements */
00303   if (this->size()!=1 || other.size()!=1)
00304   {
00305     TEUCHOS_FUNC_TIME_MONITOR("plus branch 1");
00306     Array<Expr> rtn(this->size());
00307     TEUCHOS_TEST_FOR_EXCEPTION(this->size() != other.size(), std::runtime_error,
00308       "mismatched list structures in operands L="
00309       << *this << ", R=" << other);
00310     for (int i=0; i<this->size(); i++)
00311     {
00312       rtn[i] = (*this)[i] + other[i];
00313     }
00314     return new ListExpr(rtn);
00315   }
00316   else
00317   {
00318     TEUCHOS_FUNC_TIME_MONITOR("plus branch 2");
00319     Expr rtn;
00320     /* Try to thread addition over real and imaginary parts */
00321     if (tryAddComplex((*this)[0], other[0], 1, rtn)) return rtn;
00322     /* Otherwise, do a simple scalar-scalar sum */
00323     return (*this)[0].sum(other[0], 1);
00324   }
00325 }
00326 
00327 Expr Expr::operator-(const Expr& other) const 
00328 {
00329   TimeMonitor t(opTimer());
00330   TimeMonitor ts(sumTimer());
00331 
00332   /* Thread subtraction over list elements */
00333   if (this->size()!=1 || other.size()!=1)
00334   {
00335     TEUCHOS_FUNC_TIME_MONITOR("minus branch 1");
00336     Array<Expr> rtn(this->size());
00337     TEUCHOS_TEST_FOR_EXCEPTION(this->size() != other.size(), std::runtime_error,
00338       "mismatched list structures in operands L="
00339       << *this << ", R=" << other);
00340     for (int i=0; i<this->size(); i++)
00341     {
00342       rtn[i] = (*this)[i] - other[i];
00343     }
00344     return new ListExpr(rtn);
00345   }
00346   else
00347   {
00348     TEUCHOS_FUNC_TIME_MONITOR("minus branch 2");
00349     Expr rtn;
00350     /* Try to thread subtraction over real and imaginary parts */
00351     if (tryAddComplex((*this)[0], other[0], -1, rtn)) return rtn;
00352     /* Otherwise, do a simple scalar-scalar sum */
00353     return (*this)[0].sum(other[0], -1);
00354   }
00355 }
00356 
00357 
00358 Expr Expr::sum(const Expr& other, int sign) const 
00359 {
00360   TEUCHOS_FUNC_TIME_MONITOR("Expr::sum()");
00361   RCP<ScalarExpr> rtn;
00362   RCP<ScalarExpr> sThis = rcp_dynamic_cast<ScalarExpr>(ptr());
00363   RCP<ScalarExpr> sOther = rcp_dynamic_cast<ScalarExpr>(other.ptr());
00364 
00365   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==NULL, std::logic_error,
00366     "Expr::sum() detected null this pointer");
00367 
00368   TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==NULL, std::logic_error,
00369     "Expr::sum(): Left operand " << toString() 
00370     << " is a non-scalar expression. All list structure "
00371     "should have been handled before this point");
00372 
00373   TEUCHOS_TEST_FOR_EXCEPTION(sOther.get()==NULL, std::logic_error,
00374     "Expr::sum(): Right operand " << other.toString() 
00375     << " is a non-scalar expression. All list structure "
00376     "should have been handled before this point");
00377 
00378   static StdSumTransformations trans;
00379 
00380   if (trans.doTransform(sThis, sOther, sign, rtn)) 
00381   {
00382     if (SymbolicTransformation::classVerbosity() > 0)
00383     {
00384       Out::println("Expr::sum() transformed sum\n[" 
00385         + toString() + "+"
00386         + other.toString() + "]\n to\n ["
00387         + rtn->toString() + "]");
00388     }
00389     return handle(rtn);
00390   }
00391 
00392   else return new SumExpr(sThis, sOther, sign);
00393 }
00394 
00395 
00396 Expr Expr::operator*(const Expr& other) const 
00397 {
00398   TimeMonitor t(opTimer());
00399   TimeMonitor tp(prodTimer());
00400   Tabs tab1;
00401 
00402   /* if both operands are simple scalars, multiply them */
00403   if (this->size() == 1 && other.size()==1)
00404   {
00405     Expr rtn;
00406     /* Try to do complex multiplication */
00407     if (tryMultiplyComplex((*this)[0], other[0], rtn)) 
00408     {
00409       return rtn;
00410     }
00411     /* Otherwise, do a simple scalar-scalar product */
00412     rtn = (*this)[0].multiply(other[0]);
00413     return rtn;
00414   }
00415 
00416   /* if the left operand is a scalar, multiply it through */
00417   if (this->size()==1)
00418   {
00419     Array<Expr> rtn(other.size());
00420     for (int i=0; i<other.size(); i++)
00421     {
00422       rtn[i] = (*this)[0] * other[i];
00423     }
00424     return new ListExpr(rtn);
00425   }
00426 
00427   /* if the right operand is a scalar, multiply it through */
00428   if (other.size()==1)
00429   {
00430     Array<Expr> rtn(this->size());
00431     for (int i=0; i<this->size(); i++)
00432     {
00433       rtn[i] = (*this)[i] * other[0];
00434     }
00435     return new ListExpr(rtn);
00436   }
00437 
00438   /* if both operands are flat vectors, take their dot product */
00439   if (this->size() == totalSize() && other.size()==other.totalSize() 
00440     && this->size() == other.size())
00441   {
00442     Expr rtn = new ZeroExpr();
00443 
00444     for (int i=0; i<this->size(); i++)
00445     {
00446       rtn = rtn + (*this)[i]*other[i];
00447     }
00448     return rtn;
00449   }
00450 
00451   /* if the left operand is a rectangular matrix and the 
00452    * right operand is a vector */
00453   int cols = (*this)[0].size();
00454   bool rectangular = true;
00455   for (int i=0; i<this->size(); i++)
00456   {
00457     if ((*this)[i].size() != cols) rectangular = false;
00458   }
00459   TEUCHOS_TEST_FOR_EXCEPTION(!rectangular, std::runtime_error,
00460     "Expr::operator* detected list-list multiplication "
00461     "with a non-rectangular left operator " 
00462     << toString());
00463   
00464   TEUCHOS_TEST_FOR_EXCEPTION(cols != other.size(), std::runtime_error,
00465     "Expr::operator* detected mismatched dimensions in "
00466     "list-list multiplication. Left operator is "
00467     << toString() << ", right operator is "
00468     << other.toString());
00469   
00470   Array<Expr> rtn(this->size());
00471   for (int i=0; i<this->size(); i++)
00472   {
00473     rtn[i] = (*this)[i] * other;
00474   }
00475 
00476   return new ListExpr(rtn);
00477 }
00478 
00479 Expr Expr::divide(const Expr& other) const 
00480 {
00481   RCP<ScalarExpr> sOther = rcp_dynamic_cast<ScalarExpr>(other.ptr());
00482   Expr recip = new NonlinearUnaryOp(sOther, rcp(new StdReciprocal()));
00483   return (*this)[0].multiply(recip);
00484 }
00485 
00486 Expr Expr::multiply(const Expr& other) const 
00487 {
00488   RCP<ScalarExpr> rtn;
00489   RCP<ScalarExpr> sThis = rcp_dynamic_cast<ScalarExpr>(ptr());
00490   RCP<ScalarExpr> sOther = rcp_dynamic_cast<ScalarExpr>(other.ptr());
00491 
00492   TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==NULL, std::logic_error,
00493     "Expr::multiply(): Left operand " << toString() 
00494     << " is a non-scalar expression. All list structure "
00495     "should have been handled before this point");
00496 
00497   TEUCHOS_TEST_FOR_EXCEPTION(sOther.get()==NULL, std::logic_error,
00498     "Expr::multiply(): Right operand " << other.toString() 
00499     << " is a non-scalar expression. All list structure "
00500     "should have been handled before this point");
00501 
00502   static StdProductTransformations trans;
00503 
00504   if (trans.doTransform(sThis, sOther, rtn)) 
00505   {
00506     if (SymbolicTransformation::classVerbosity() > 0)
00507     {
00508       Out::println("Expr::operator*() transformed product\n[" 
00509         + toString() + "*"
00510         + other.toString() + "]\n to\n ["
00511         + rtn->toString() + "]");
00512     }
00513     return handle(rtn);
00514   }
00515 
00516   return new ProductExpr(sThis, sOther);
00517 }
00518 
00519 Expr Expr::operator-() const 
00520 {
00521   TimeMonitor t(opTimer());
00522   TimeMonitor t1(unaryMinusTimer());
00523   Tabs tabs;
00524 
00525   if (this->isComplex())
00526   {
00527     return new ComplexExpr(-real(), -imag());
00528   }
00529 
00530   /* if we are a real scalar, process the unary minus here */
00531   if (this->size()==1)
00532   {
00533     /* if we are spectral, thread unary minus over coeffs */
00534     const SpectralExpr* se 
00535       = dynamic_cast<const SpectralExpr*>((*this)[0].ptr().get());
00536     if (se != 0)
00537     {
00538       SpectralBasis basis = se->getSpectralBasis();
00539       Array<Expr> coeff(basis.nterms());
00540   
00541       for(int i=0; i<basis.nterms(); i++)
00542       {
00543         coeff[i] = - se->getCoeff(i);
00544       }
00545       Expr rtn = new SpectralExpr( basis, coeff);
00546       return rtn;
00547     }
00548 
00549     /* Test for some special cases that can be dealt with efficiently */
00550     const ConstantExpr* c 
00551       = dynamic_cast<const ConstantExpr*>((*this)[0].ptr().get());
00552     const UnaryMinus* u 
00553       = dynamic_cast<const UnaryMinus*>((*this)[0].ptr().get());
00554     /* if we are a constant, just modify the constant */
00555     if (c != 0)
00556     {
00557       if (c->value()==0.0)
00558       {
00559         return new ZeroExpr();
00560       }
00561       else
00562       {
00563         return new ConstantExpr(-1.0 * c->value());
00564       }
00565     }
00566     else if (u != 0) /* if we are already a unary minus, apply -(-x) --> x */
00567     {
00568       return u->arg();
00569     }
00570     else /* no special structure, so return a UnaryMinusExpr */
00571     {
00572       RCP<ScalarExpr> sThis 
00573         = rcp_dynamic_cast<ScalarExpr>((*this)[0].ptr());
00574       TEUCHOS_TEST_FOR_EXCEPTION(sThis.get()==NULL, std::logic_error,
00575         "Expr::operator-(): Operand " << (*this)[0].toString() 
00576         << " is a non-scalar expression. All list structure "
00577         "should have been handled before this point");
00578       return new UnaryMinus(sThis);
00579     }
00580   }
00581 
00582   /* otherwise, distribute the sign change over the list */
00583   Array<Expr> rtn(this->size());
00584   for (int i=0; i<this->size(); i++)
00585   {
00586     rtn[i] = -((*this)[i]);
00587   }
00588   return new ListExpr(rtn);
00589 }
00590 
00591 
00592 Expr Expr::operator/(const Expr& other) const 
00593 {
00594   TimeMonitor t(opTimer());
00595 
00596   /* if the right operand is a list, this operation
00597    * makes no sense */
00598   TEUCHOS_TEST_FOR_EXCEPTION(other.size() != 1,
00599     std::runtime_error, 
00600     "Expr::operator/ detected division by a non-scalar "
00601     "expression " << toString());
00602 
00603   TEUCHOS_TEST_FOR_EXCEPTION(other.isSpectral(), std::logic_error, 
00604     "Division by a Spectral Expr is not yet defined");
00605 
00606   /* If other is complex, transform to make the denominator real */
00607   if (other.isComplex())
00608   {
00609     Expr magSq = other.real()*other.real() + other.imag()*other.imag();
00610     return (*this) * other.conj() / magSq;
00611   }
00612 
00613   /* If I'm complex and the other is not, distribute division over re and im */
00614   if (isComplex() && !other.isComplex())
00615   {
00616     return new ComplexExpr(real()/other, imag()/other);
00617   }
00618 
00619   /* If I'm spectral and the other is not, distribute division over coefficients */
00620   if (isSpectral() && !other.isSpectral()  && !other.isComplex())
00621   {
00622     const SpectralExpr* se 
00623       = dynamic_cast<const SpectralExpr*>((*this)[0].ptr().get());
00624 
00625     SpectralBasis basis = se->getSpectralBasis();
00626     Array<Expr> coeff(basis.nterms());
00627     
00628     for(int i=0; i<basis.nterms(); i++)
00629     {
00630       coeff[i] = se->getCoeff(i)/ other[0];
00631     }
00632     Expr rtn = new SpectralExpr( basis, coeff);
00633     return rtn;
00634   }
00635 
00636   /* if we are a scalar, do simple scalar division */
00637   if (this->size()==1)
00638   {
00639     return (*this)[0].divide(other[0]);
00640   }
00641 
00642   /* otherwise, divide each element of the left by the right operand */
00643   Array<Expr> rtn(this->size());
00644   for (int i=0; i<this->size(); i++)
00645   {
00646     rtn[i] = (*this)[i] / other;
00647   }
00648   return new ListExpr(rtn);
00649 }
00650 
00651 const Expr& Expr::operator[](int i) const
00652 {
00653   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==NULL, std::logic_error,
00654     "null this detected in Expr::operator[].");
00655 
00656   TEUCHOS_TEST_FOR_EXCEPTION(i<0 || i>=(int) this->size(), std::runtime_error,
00657     "Expr::operator[]() index i=" << i << " out of range [0, "
00658     << this->size() << " in expr " << toString());
00659 
00660   const ListExpr* le = dynamic_cast<const ListExpr*>(ptr().get());
00661 
00662   if (le != 0)
00663   {
00664     const Expr& rtn = le->element(i);
00665     TEUCHOS_TEST_FOR_EXCEPTION(rtn.size() == 0, std::logic_error,
00666       "attempt to access an empty list; this should "
00667       "never happen because the case should have been "
00668       "dealt with earlier");
00669     if (rtn.size()==1) 
00670     {
00671       TEUCHOS_TEST_FOR_EXCEPTION(rtn[0].ptr().get()==NULL, std::logic_error,
00672         "null return detected in Expr::operator[]. This="
00673         << toString() << ", i=" << i);
00674       return rtn[0];
00675     }
00676     TEUCHOS_TEST_FOR_EXCEPTION(rtn.ptr().get()==NULL, std::logic_error,
00677       "null return detected in Expr::operator[]. This="
00678       << toString() << ", i=" << i);
00679     return rtn;
00680   }
00681 
00682   return *this;
00683 }
00684 
00685 void Expr::append(const Expr& expr)
00686 {
00687   ListExpr* le = dynamic_cast<ListExpr*>(ptr().get());
00688 
00689   if (le != 0)
00690   {
00691     le->append(expr);
00692     return;
00693   }
00694   else
00695   {
00696     if (ptr().get()==0)
00697     {
00698       Array<Expr> e(1);
00699       e[0] = expr;
00700       ptr() = rcp(new ListExpr(e));
00701     }
00702     else
00703     {
00704       Array<Expr> e(2);
00705       e[0] = *this;
00706       e[1] = expr;
00707       ptr() = rcp(new ListExpr(e));
00708     }
00709   }
00710 }
00711 
00712 Expr Expr::flatten() const
00713 {
00714   const ListExpr* le = dynamic_cast<const ListExpr*>(ptr().get());
00715 
00716   if (le != 0)
00717   {
00718     return le->flatten();
00719   }
00720   return *this;
00721 }
00722 
00723 Expr Expr::flattenSpectral() const
00724 {
00725   Array<Expr> rtn(size());
00726   for (int i=0; i<size(); i++)
00727   {
00728     if ((*this)[i].size() == 1)
00729     {
00730       const SpectralExpr* se 
00731         = dynamic_cast<const SpectralExpr*>((*this)[i][0].ptr().get());
00732       if (se != 0)
00733       {
00734         int nt = se->getSpectralBasis().nterms();
00735         Array<Expr> e(nt);
00736         for (int j=0; j<nt; j++)
00737         {
00738           e[j] = se->getCoeff(j);
00739         }
00740         rtn[i] = new ListExpr(e);
00741       }
00742       else
00743       {
00744         rtn[i] = (*this)[i];
00745       }
00746     }
00747     else
00748     {
00749       rtn[i] = (*this)[i].flattenSpectral();
00750     }
00751   }
00752   Expr r = new ListExpr(rtn);
00753   return r.flatten();
00754 }
00755 
00756 int Expr::size() const
00757 {
00758   if (ptr().get()==0) return 0;
00759 
00760   const ListExpr* le = dynamic_cast<const ListExpr*>(ptr().get());
00761 
00762   if (le != 0)
00763   {
00764     return le->size();
00765   }
00766   return 1;
00767 }
00768 
00769 int Expr::totalSize() const
00770 {
00771   if (ptr().get()==0) return 0;
00772 
00773   const ListExpr* le = dynamic_cast<const ListExpr*>(ptr().get());
00774 
00775   if (le != 0)
00776   {
00777     return le->totalSize();
00778   }
00779   return 1;
00780 }
00781 
00782 Expr Expr::real() const
00783 {
00784   if (isComplex()) 
00785   {
00786     const ComplexExpr* cx = dynamic_cast<const ComplexExpr*>(ptr().get());
00787     return cx->real();
00788   }
00789   else if (size() > 1)
00790   {
00791     Array<Expr> rtn(size());
00792     for (int i=0; i<size(); i++)
00793     {
00794       rtn[i] = (*this)[i].real();
00795     }
00796     return new ListExpr(rtn);
00797   }
00798   else 
00799   {
00800     return *this;
00801   }
00802 }
00803 
00804 Expr Expr::imag() const
00805 {
00806   if (isComplex()) 
00807   {
00808     const ComplexExpr* cx = dynamic_cast<const ComplexExpr*>(ptr().get());
00809     return cx->imag();
00810   }
00811   else if (size() > 1)
00812   {
00813     Array<Expr> rtn(size());
00814     for (int i=0; i<size(); i++)
00815     {
00816       rtn[i] = (*this)[i].imag();
00817     }
00818     return new ListExpr(rtn);
00819   }
00820   else
00821   {
00822     return 0.0;
00823   }
00824   
00825 }
00826 
00827 Expr Expr::conj() const
00828 {
00829   if (size()==1)
00830   {
00831     if (isComplex()) 
00832     {
00833       return new ComplexExpr(real(), -imag());
00834     }
00835     else return real();
00836   }
00837   else
00838   {
00839     Array<Expr> rtn(size());
00840     for (int i=0; i<size(); i++)
00841     {
00842       rtn[i] = (*this)[i].conj();
00843     }
00844     return new ListExpr(rtn);
00845   }
00846 }
00847 
00848 void Expr::setParameterValue(const double& value)
00849 {
00850   Parameter* pe = dynamic_cast<Parameter*>(ptr().get());
00851   TEUCHOS_TEST_FOR_EXCEPTION(pe==0, std::runtime_error, 
00852     "Expr " << *this << " is not a Parameter expr, and "
00853     "so setParameterValue() should not be called");
00854   pe->setValue(value);
00855 }
00856 
00857 double Expr::getParameterValue() const 
00858 {
00859   const Parameter* pe = dynamic_cast<const Parameter*>(ptr().get());
00860   TEUCHOS_TEST_FOR_EXCEPTION(pe==0, std::runtime_error, 
00861     "Expr " << *this << " is not a Parameter expr, and "
00862     "so getParameterValue() should not be called");
00863   return pe->value();
00864 }
00865 
00866 
00867 bool Expr::isIndependentOf(const Expr& u) const
00868 {
00869   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00870     "function called on null expression");
00871   
00872   return scalarExpr()->isIndependentOf(u);
00873 }
00874 
00875 
00876 bool Expr::isLinearForm(const Expr& u) const
00877 {
00878   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00879     "function called on null expression");
00880 
00881   return scalarExpr()->isLinearForm(u);
00882 }
00883 
00884 
00885 
00886 bool Expr::isQuadraticForm(const Expr& u) const
00887 {
00888   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00889     "function called on null expression");
00890 
00891   return scalarExpr()->isQuadraticForm(u);
00892 }
00893 
00894 
00895 
00896 bool Expr::isLinearInTests() const
00897 {
00898   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00899     "function called on null expression");
00900 
00901   return scalarExpr()->isLinearInTests();
00902 }
00903 
00904 
00905 bool Expr::hasTestFunctions() const
00906 {
00907   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00908     "function called on null expression");
00909 
00910   return scalarExpr()->hasTestFunctions();
00911 }
00912 
00913 
00914 bool Expr::everyTermHasTestFunctions() const
00915 {
00916   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00917     "function called on null expression");
00918 
00919   return scalarExpr()->everyTermHasTestFunctions();
00920 }
00921 
00922 bool Expr::isTestElement() const
00923 {
00924   const TestFuncElement* uPtr
00925     = dynamic_cast<const TestFuncElement*>(ptr().get());
00926   return uPtr != 0;
00927 }
00928 
00929 
00930 bool Expr::isUnknownElement() const
00931 {
00932   const UnknownFuncElement* uPtr
00933     = dynamic_cast<const UnknownFuncElement*>(ptr().get());
00934   return uPtr != 0;
00935 }
00936 
00937 
00938 void Expr::getUnknowns(Set<int>& unkID, 
00939   Array<Expr>& unks) const
00940 {
00941   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00942     "function called on null expression");
00943 
00944   const UnknownFuncElement* u 
00945     = dynamic_cast<const UnknownFuncElement*>(ptr().get());
00946 
00947   if (u != 0) 
00948   {
00949     if (!unkID.contains(u->fid().dofID())) 
00950     {
00951       unks.append(*this);
00952       unkID.put(u->fid().dofID());
00953     }
00954   }
00955   else
00956   {
00957     scalarExpr()->getUnknowns(unkID, unks);
00958   }
00959 }
00960 
00961 
00962 void Expr::getTests(Set<int>& varID, Array<Expr>& vars) const
00963 {
00964   TEUCHOS_TEST_FOR_EXCEPTION(ptr().get()==0, std::runtime_error, 
00965     "function called on null expression");
00966 
00967   const TestFuncElement* u 
00968     = dynamic_cast<const TestFuncElement*>(ptr().get());
00969 
00970   if (u != 0) 
00971   {
00972     if (!varID.contains(u->fid().dofID())) 
00973     {
00974       vars.append(*this);
00975       varID.put(u->fid().dofID());
00976     }
00977   }
00978   else
00979   {
00980     scalarExpr()->getTests(varID, vars);
00981   }
00982 }
00983 
00984 
00985 const ScalarExpr* Expr::scalarExpr() const 
00986 {
00987   const ScalarExpr* se = dynamic_cast<const ScalarExpr*>(ptr().get());
00988   TEUCHOS_TEST_FOR_EXCEPTION(se==0, std::logic_error, "ScalarExpr expected here");
00989   return se;
00990 }
00991 
00992 const FuncElementBase* Expr::funcElement() const 
00993 {
00994   const FuncElementBase* fe 
00995     = dynamic_cast<const FuncElementBase*>(ptr().get());
00996   return fe;
00997 }
00998 
00999 
01000 
01001 
01002 namespace Sundance
01003 {
01004 using namespace Sundance;
01005 
01006 Expr Complex(const Expr& re, const Expr& im)
01007 {
01008   TEUCHOS_TEST_FOR_EXCEPTION(re.size() != im.size(), std::runtime_error,
01009     "arguments mismatched in Complex(). Real part="
01010     << re << ", imaginary part=" << im);
01011 
01012   TEUCHOS_TEST_FOR_EXCEPTION(re.isComplex() || im.isComplex(), std::runtime_error,
01013     "recursively defined complex number. Real part="
01014     << re << ", imaginary part=" << im);
01015 
01016   if (re.totalSize() > 1)
01017   {
01018     Array<Expr> rtn(re.size());
01019     for (int i=0; i<re.size(); i++)
01020     {
01021       rtn[i] = Complex(re[i], im[i]);
01022     }
01023     return new ListExpr(rtn);
01024   }
01025 
01026   const ZeroExpr* zr = dynamic_cast<const ZeroExpr*>(re[0].ptr().get());
01027   const ZeroExpr* zi = dynamic_cast<const ZeroExpr*>(im[0].ptr().get());
01028 
01029   if (zr == 0) /* nonzero real part */
01030   {
01031     if (zi==0) /* nonzero imag part */
01032     {
01033       return new ComplexExpr(re, im);
01034     }
01035     else /* zero imag part */
01036     {
01037       return re;
01038     }
01039   }
01040   else /* zero real part */
01041   {
01042     if (zi != 0) /* both are zero */
01043     {
01044       return Expr(0.0);
01045     }
01046     else /* pure imaginary */
01047     {
01048       return new ComplexExpr(0.0, im);
01049     }
01050   }
01051   return new ComplexExpr(re, im);
01052 }
01053 
01054 Expr List(const Expr& a)
01055 {
01056   return new ListExpr(tuple(a));
01057 }
01058 
01059 Expr List(const Expr& a, const Expr& b)
01060 {
01061   return new ListExpr(tuple(a,b));
01062 }
01063 
01064 Expr List(const Expr& a, const Expr& b, const Expr& c)
01065 {
01066   return new ListExpr(tuple(a,b,c));
01067 }
01068 
01069 Expr List(const Expr& a, const Expr& b, const Expr& c,
01070   const Expr& d)
01071 {
01072   return new ListExpr(tuple(a,b,c,d));
01073 }
01074 
01075 Expr List(const Expr& a, const Expr& b, const Expr& c,
01076   const Expr& d, const Expr& e)
01077 {
01078   return new ListExpr(tuple(a,b,c,d,e));
01079 }
01080 
01081 Expr List(const Expr& a, const Expr& b, const Expr& c,
01082   const Expr& d, const Expr& e, const Expr& f)
01083 {
01084   return new ListExpr(tuple(a,b,c,d,e,f));
01085 }
01086 
01087 Expr List(const Expr& a, const Expr& b, const Expr& c,
01088   const Expr& d, const Expr& e, const Expr& f,
01089   const Expr& g)
01090 {
01091   return new ListExpr(tuple(a,b,c,d,e,f,g));
01092 }
01093 
01094 Expr List(const Expr& a, const Expr& b, const Expr& c,
01095   const Expr& d, const Expr& e, const Expr& f,
01096   const Expr& g, const Expr& h)
01097 {
01098   return new ListExpr(tuple(a,b,c,d,e,f,g,h));
01099 }
01100 
01101 
01102 }
01103 

Site Contact