SundanceStdProductTransformations.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 "SundanceIntegral.hpp"
00044 #include "SundanceStdProductTransformations.hpp"
00045 
00046 #include "SundanceSumExpr.hpp"
00047 #include "SundanceProductExpr.hpp"
00048 #include "SundanceConstantExpr.hpp"
00049 #include "SundanceCoordExpr.hpp"
00050 #include "SundanceDerivative.hpp"
00051 #include "SundanceDiffOp.hpp"
00052 
00053 
00054 #include "SundanceUnaryMinus.hpp"
00055 #include "SundanceZeroExpr.hpp"
00056 #include "SundanceSumOfIntegrals.hpp"
00057 #include "SundanceSymbolicFuncElement.hpp"
00058 #include "SundanceDerivOfSymbFunc.hpp"
00059 #include "SundanceOut.hpp"
00060 
00061 using namespace Sundance;
00062 using namespace Sundance;
00063 
00064 using namespace Teuchos;
00065 using namespace Sundance;
00066 
00067 
00068 StdProductTransformations::StdProductTransformations()
00069   : ProductTransformationSequence()
00070 {
00071   append(rcp(new RemoveZeroFromProduct()));
00072   append(rcp(new RemoveOneFromProduct()));
00073   append(rcp(new RemoveMinusOneFromProduct()));
00074   append(rcp(new KillDiffOpOnConstant()));
00075   append(rcp(new BringConstantOutsideDiffOp()));
00076   append(rcp(new MoveUnaryMinusOutsideProduct()));
00077   append(rcp(new AssociateHungryDiffOpWithOperand()));
00078   append(rcp(new DistributeSumOfDiffOps()));
00079   append(rcp(new ApplySimpleDiffOp()));
00080   append(rcp(new TakeConstantUnderIntegralSign()));
00081   append(rcp(new MultiplyConstants()));
00082   append(rcp(new MoveConstantsToLeftOfProduct()));
00083   append(rcp(new RearrangeRightProductWithConstant()));
00084   append(rcp(new RearrangeLeftProductWithConstant()));
00085 }
00086 
00087 bool RemoveZeroFromProduct::doTransform(const RCP<ScalarExpr>& left, 
00088                                         const RCP<ScalarExpr>& right,
00089                                         RCP<ScalarExpr>& rtn) const
00090 {
00091   SUNDANCE_OUT(this->verb() > 1, 
00092                "trying RemoveZerofromProduct");
00093   
00094   /* Check for the trivial case of multiplication by zero */
00095   const ConstantExpr* cl = dynamic_cast<const ConstantExpr*>(left.get());
00096   const ConstantExpr* cr = dynamic_cast<const ConstantExpr*>(right.get());
00097 
00098   if (cl != 0)
00099     {
00100       if (cl->value()==0.0 || cl->value()==-0.0)
00101         {
00102           if (verb() > 1)
00103             {
00104               Out::println("RemoveOneFromProduct::doTransform "
00105                            "identified multiplication "
00106                            "by zero. Applying transformation 0*u --> 0");
00107             }
00108           rtn = rcp(new ZeroExpr());
00109           return true;
00110         }
00111     }
00112   if (cr != 0)
00113     {
00114       if (cr->value()==0.0 || cr->value()==-0.0)
00115         {
00116           if (verb() > 1)
00117             {
00118               Out::println("RemoveOneFromProduct::doTransform "
00119                            "identified multiplication "
00120                            "by zero. Applying transformation u*0 --> u");
00121             }
00122           rtn = rcp(new ZeroExpr());
00123           return true;
00124         }
00125     }
00126   return false;
00127 }
00128 
00129 bool RemoveOneFromProduct::doTransform(const RCP<ScalarExpr>& left, 
00130                                        const RCP<ScalarExpr>& right,
00131                                        RCP<ScalarExpr>& rtn) const
00132 {
00133   SUNDANCE_OUT(this->verb() > 1, 
00134                "trying RemoveOnefromProduct");
00135 
00136   /* Check for the trivial case of multiplication by one */
00137   const ConstantExpr* cl = dynamic_cast<const ConstantExpr*>(left.get());
00138   const ConstantExpr* cr = dynamic_cast<const ConstantExpr*>(right.get());
00139 
00140   if (cl != 0)
00141     {
00142       if (cl->value()==1.0)
00143         {
00144           if (verb() > 1)
00145             {
00146               Out::println("RemoveOneFromProduct::doTransform "
00147                            "identified multiplication "
00148                            "by one. Applying transformation 1*u --> u");
00149             }
00150           rtn = getScalar(Expr::handle(right));
00151           return true;
00152         }
00153     }
00154   if (cr != 0)
00155     {
00156       if (cr->value()==1.0)
00157         {
00158           if (verb() > 1)
00159             {
00160               Out::println("RemoveOneFromProduct::doTransform "
00161                            "identified multiplication "
00162                            "by one. Applying transformation u*1 --> u");
00163             }
00164           rtn = getScalar(Expr::handle(left));
00165           return true;
00166         }
00167     }
00168   return false;
00169 }
00170 
00171 
00172 bool RemoveMinusOneFromProduct::doTransform(const RCP<ScalarExpr>& left, 
00173                                             const RCP<ScalarExpr>& right,
00174                                             RCP<ScalarExpr>& rtn) const
00175 {
00176   SUNDANCE_OUT(this->verb() > 1, 
00177                "trying RemoveOnefromProduct");
00178 
00179   /* Check for the trivial case of multiplication by minus one */
00180   const ConstantExpr* cl = dynamic_cast<const ConstantExpr*>(left.get());
00181   const ConstantExpr* cr = dynamic_cast<const ConstantExpr*>(right.get());
00182 
00183   if (cl != 0)
00184     {
00185       if (cl->value()==-1.0)
00186         {
00187           if (verb() > 1)
00188             {
00189               Out::println("RemoveMinusOneFromProduct::doTransform "
00190                            "identified multiplication "
00191                            "by one. Applying transformation -1*u --> -u");
00192             }
00193           rtn = getScalar(-Expr::handle(right));
00194           return true;
00195         }
00196     }
00197   if (cr != 0)
00198     {
00199       if (cr->value()==-1.0)
00200         {
00201           if (verb() > 1)
00202             {
00203               Out::println("RemoveMinusOneFromProduct::doTransform "
00204                            "identified multiplication "
00205                            "by one. Applying transformation u*(-1) --> -u");
00206             }
00207           rtn = getScalar(-Expr::handle(left));
00208           return true;
00209         }
00210     }
00211   return false;
00212 }
00213 
00214 bool MoveConstantsToLeftOfProduct::doTransform(const RCP<ScalarExpr>& left, 
00215                                                const RCP<ScalarExpr>& right,
00216                                                RCP<ScalarExpr>& rtn) const
00217 {
00218   SUNDANCE_OUT(this->verb() > 1, 
00219                "trying MoveConstantsToLeftOfProduct");
00220 
00221   /* If the left operand is non-constant and
00222    * the right operand is a constant, 
00223    * transform u*constant --> constant*u */
00224   if (!left->isConstant() && right->isConstant())
00225     {
00226       if (verb() > 1)
00227         {
00228           Out::println("MoveConstantsToLeftOfProduct::doTransform "
00229                        "identified right operand "
00230                        "as a constant. Applying transformation u*alpha "
00231                        "--> alpha*u.");
00232         }
00233       rtn = getScalar(Expr::handle(right) * Expr::handle(left));
00234       return true;
00235     }
00236   return false;
00237 }
00238 
00239 bool MoveUnaryMinusOutsideProduct::doTransform(const RCP<ScalarExpr>& left, 
00240                                                const RCP<ScalarExpr>& right,
00241                                                RCP<ScalarExpr>& rtn) const
00242 {
00243   SUNDANCE_OUT(this->verb() > 1, 
00244                "trying MoveUnaryMinusOutsideProduct");
00245 
00246   /* If one of the operands is a unary minus, apply it to the whole
00247    * product. If both are unary minuses, multiply the operands, removing
00248    * the unary minuses. */
00249   const UnaryMinus* ul = dynamic_cast<const UnaryMinus*>(left.get());
00250   const UnaryMinus* ur = dynamic_cast<const UnaryMinus*>(right.get());
00251   if (ur != 0 && ul != 0)
00252     {
00253       if (verb() > 1)
00254         {
00255           Out::println("MoveUnaryMinusOutsideProduct::doTransform "
00256                        "identified both operands "
00257                        "as unary minuses. Applying transformation (-x)*(-y) "
00258                        "--> x*y.");
00259         }
00260       rtn = getScalar(ul->arg() * ur->arg());
00261       return true;
00262     }
00263   else if (ur != 0)
00264     {
00265       if (verb() > 1)
00266         {
00267           Out::println("MoveUnaryMinusOutsideProduct::doTransform "
00268                        "identified right operand "
00269                        "as a unary minus. Applying transformation x*(-y) "
00270                        "--> -(x*y).");
00271         }
00272       Expr prod = Expr::handle(left) * ur->arg();
00273       rtn = rcp(new UnaryMinus(getScalar(prod)));
00274       return true;
00275     }
00276   else if (ul != 0)
00277     {
00278       if (verb() > 1)
00279         {
00280           Out::println("MoveUnaryMinusOutsideProduct::doTransform "
00281                        "identified left operand "
00282                        "as a unary minus. Applying transformation (-x)*y "
00283                        "--> -(x*y).");
00284         }
00285       Expr prod = ul->arg() * Expr::handle(right);
00286       rtn = rcp(new UnaryMinus(getScalar(prod)));
00287       return true;
00288     }
00289   return false;
00290 }
00291 
00292 bool MultiplyConstants::doTransform(const RCP<ScalarExpr>& left, 
00293   const RCP<ScalarExpr>& right,
00294   RCP<ScalarExpr>& rtn) const
00295 {
00296   SUNDANCE_OUT(this->verb() > 1, 
00297                "trying MultiplyConstants");
00298 
00299   /* If both operands are constant, just multiply them */
00300   if (left->isConstant() && right->isConstant())
00301     {
00302       if (left->isImmutable() && right->isImmutable())
00303         {
00304           const ConstantExpr* cl = dynamic_cast<const ConstantExpr*>(left.get());
00305           const ConstantExpr* cr = dynamic_cast<const ConstantExpr*>(right.get());
00306           TEUCHOS_TEST_FOR_EXCEPTION(cl==0 || cr==0, std::logic_error,
00307                              "MultiplyConstants::doTransform() logic error: "
00308                              "L and R identified as immutable, but could "
00309                              "not be cast to ConstantExprs");
00310           rtn = rcp(new ConstantExpr(cl->value() * cr->value()));
00311           return true;
00312         }
00313       if (verb() > 1)
00314         {
00315           Out::println("MultiplyConstants::doTransform "
00316                        "identified both operands "
00317                        "as constants. Forming the product without any "
00318                        "transformation");
00319         }
00320       rtn = rcp(new ProductExpr(left, right));
00321       return true;
00322     }
00323   return false;
00324 }
00325 
00326 bool AssociateHungryDiffOpWithOperand::doTransform(const RCP<ScalarExpr>& left, 
00327   const RCP<ScalarExpr>& right,
00328   RCP<ScalarExpr>& rtn) const
00329 {
00330   SUNDANCE_OUT(this->verb() > 1, 
00331                "trying AssociateHungryDiffOpWithOperand");
00332 
00333   if (left->isHungryDiffOp())
00334     {
00335       /* if the left operand is a product including 
00336        * a hungry diff op, rotate the
00337        * tree such that the diff op associates with the right operand */
00338       const ProductExpr* pLeft 
00339         = dynamic_cast<const ProductExpr*>(left.get());
00340       if (pLeft != 0)
00341         {
00342           Expr ll = pLeft->left();
00343           Expr lr = pLeft->right();
00344           if (verb() > 1)
00345             {
00346               Out::println("AssociateHungryDiffOpWithOperand::doTransform "
00347                            "identified left "
00348                            "operand as a product with a hungry diff op "
00349                            "as the last factor. "
00350                            "Applying (u*D)*v --> u*(D*v).");
00351             }
00352           rtn = getScalar(ll*(lr*Expr::handle(right)));
00353           return true;
00354         }
00355     }
00356   return false;
00357 }
00358 
00359 bool KillDiffOpOnConstant::doTransform(const RCP<ScalarExpr>& left, 
00360                                        const RCP<ScalarExpr>& right,
00361                                        RCP<ScalarExpr>& rtn) const
00362 {
00363   SUNDANCE_OUT(this->verb() > 1, "trying KillDiffOpOnConstant");
00364 
00365   if (left->isHungryDiffOp())
00366     {
00367       /* first check that the operand is not a constant, in case someone
00368        * differentiated a constant for some unimaginable reason */
00369       if (right->isConstant())
00370         {
00371           rtn = rcp(new ZeroExpr());
00372           if (verb() > 1)
00373             {
00374               Out::println("KillDiffOpOnConstant::doTransform "
00375                            "identified constant "
00376                            "as operand of diff op. Applying D*alpha --> 0");
00377             }
00378           return true;
00379         }
00380       
00381       /* transform op*(constant + u) --> op*u */
00382       const SumExpr* sRight = dynamic_cast<const SumExpr*>(right.get());
00383       if (sRight != 0 && sRight->leftScalar()->isConstant())
00384         {
00385           if (verb() > 1)
00386             {
00387               Out::println("KillDiffOpOnConstant::doTransform "
00388                            "identified constant "
00389                            "term in operand of diff op. "
00390                            "Applying D*(alpha+u) --> D*u");
00391             }
00392           rtn = getScalar(chooseSign(sRight->sign(), Expr::handle(left)) * sRight->right());
00393           return true;
00394         }
00395     }
00396   return false;
00397 }
00398 
00399 bool BringConstantOutsideDiffOp::doTransform(const RCP<ScalarExpr>& left, 
00400                                              const RCP<ScalarExpr>& right,
00401                                              RCP<ScalarExpr>& rtn) const
00402 {
00403   
00404   SUNDANCE_OUT(this->verb() > 1,  "trying BringConstantOutsideDiffOp");
00405 
00406   if (left->isHungryDiffOp())
00407     {
00408       /* transform op*(constant*u) --> constant*op*u */
00409       const ProductExpr* pRight 
00410         = dynamic_cast<const ProductExpr*>(right.get());
00411       if (pRight != 0 && pRight->leftScalar()->isConstant())
00412         {
00413           if (verb() > 1)
00414             {
00415               Out::println("BringConstantOutsideDiffOp::doTransform "
00416                            "identified constant "
00417                            "coefficient in operand of diff op. "
00418                            "Applying D*(alpha*u) --> alpha*D*u");
00419             }
00420           rtn = getScalar(pRight->left() * (Expr::handle(left) * pRight->right()));
00421           return true;
00422         }
00423     }
00424   return false;
00425 }
00426 
00427 bool DistributeSumOfDiffOps::doTransform(const RCP<ScalarExpr>& left, 
00428                                          const RCP<ScalarExpr>& right,
00429                                          RCP<ScalarExpr>& rtn) const
00430 {
00431   SUNDANCE_OUT(this->verb() > 1,"trying DistributeSumOfDiffOps");
00432 
00433   if (left->isHungryDiffOp())
00434     {
00435       /* if the left operand is a sum of hungry diff ops, distribute this
00436        * multiplication over the sum */
00437       const SumExpr* sLeft = dynamic_cast<const SumExpr*>(left.get());
00438       if (sLeft != 0)
00439         {
00440           Expr ll = sLeft->left();
00441           Expr lr = sLeft->right();
00442           if (verb() > 1)
00443             {
00444               Out::println("DistributeSumOfDiffOps::doTransform "
00445                            "identified left "
00446                            "operand as a sum of hungry diff ops. "
00447                            "Applying (D1 + D2)*u --> D1*u + D2*u");
00448             }
00449           rtn = getScalar(ll*Expr::handle(right) + chooseSign(sLeft->sign(), lr)*Expr::handle(right));
00450           return true;
00451         }
00452     }
00453   return false;
00454 }
00455 
00456 bool ApplySimpleDiffOp::doTransform(const RCP<ScalarExpr>& left, 
00457                                     const RCP<ScalarExpr>& right,
00458                                     RCP<ScalarExpr>& rtn) const
00459 {
00460   SUNDANCE_OUT(this->verb() > 1, "trying ApplySimpleDiffOp");
00461 
00462   if (left->isHungryDiffOp())
00463     {
00464       const Derivative* dLeft 
00465         = dynamic_cast<const Derivative*>(left.get());
00466       if (dLeft != 0)
00467         {
00468           const SymbolicFuncElement* sf 
00469             = dynamic_cast<const SymbolicFuncElement*>(right.get());
00470           if (sf != 0 && optimizeFunctionDiffOps())
00471             {
00472               rtn = rcp(new DerivOfSymbFunc(dLeft->multiIndex(), right));
00473             }
00474           else
00475             {
00476               rtn = rcp(new DiffOp(dLeft->multiIndex(), right));
00477             }
00478           return true;
00479         }
00480     }
00481   return false;
00482 }
00483 
00484 bool RearrangeRightProductWithConstant::doTransform(const RCP<ScalarExpr>& left, 
00485                                                     const RCP<ScalarExpr>& right,
00486                                                     RCP<ScalarExpr>& rtn) const
00487 {
00488   /* Transform several cases in which the right operand is a product
00489    * involving a constant. */
00490   const ProductExpr* pRight 
00491     = dynamic_cast<const ProductExpr*>(right.get());
00492 
00493   /* By this point, we should have already transformed out any cases
00494    * in which the right operand is a product having a constant as a
00495    * right operand, because its constants should have been rotated
00496    * left. Do a paranoia check to be safe */
00497   TEUCHOS_TEST_FOR_EXCEPTION(pRight != 0 && pRight->rightScalar()->isConstant(),
00498                      std::logic_error,
00499                      "unexpected case in "
00500                      "RearrangeRightProductWithConstant::doTransform: "
00501                      "the right operand "
00502                      << pRight->right() 
00503                      << "of the right operand " << right->toString()
00504                      << " is a constant. That case should have been "
00505                      "transformed out by now.");
00506 
00507   if (pRight != 0 && !pRight->isConstant() 
00508       && pRight->leftScalar()->isConstant())
00509     {
00510       /* if left operand is a constant, and the right operand is a 
00511        * product involving a constant,
00512        * transform alpha*(beta*u) --> (alpha*beta)*u */
00513       if (left->isConstant())
00514         {
00515           if (verb() > 1)
00516             {
00517               Out::println("RearrangeRightProductWithConstant::doTransform: "
00518                            "identified left operand "
00519                            "as a constant, and right operand as a product "
00520                            "involving a constant. Applying transformation "
00521                            "alpha*(beta*u) --> (alpha*beta)*u");
00522             }
00523           rtn = getScalar((Expr::handle(left) * pRight->left()) * pRight->right());
00524           return true;
00525         }
00526       else
00527         /* if the left operand is non-constant and the right operand
00528          * is a product involving a constant,
00529          * transform u * (alpha*v) --> alpha*(u*v) */
00530         {
00531           if (verb() > 1)
00532             {
00533               Out::println("RearrangeRightProductWithConstant::doTransform: "
00534                            "identified left operand "
00535                            "as non-constant, and right operand as a product "
00536                            "involving a constant. Applying transformation "
00537                            "u * (alpha*v) --> alpha*(u*v)");
00538             }
00539           rtn = getScalar(pRight->left() * (Expr::handle(left) * pRight->right()));
00540           return true;
00541         }
00542     }
00543   return false;
00544 }
00545 
00546 
00547 bool RearrangeLeftProductWithConstant::doTransform(const RCP<ScalarExpr>& left, 
00548                                                    const RCP<ScalarExpr>& right,
00549                                                    RCP<ScalarExpr>& rtn) const
00550 {
00551   /* transform cases in which the left operand is a product, exactly
00552    * one of whose operands is a constant. Because of the preceding 
00553    * transformation rules,
00554    * the constant should be on the left */
00555   const ProductExpr* pLeft 
00556     = dynamic_cast<const ProductExpr*>(left.get());
00557 
00558   if (pLeft != 0 && !pLeft->isConstant() 
00559       && pLeft->leftScalar()->isConstant())
00560     {
00561 
00562       /* Paranoid check to make sure we don't have the case
00563        * (u*alpha)*right */
00564       TEUCHOS_TEST_FOR_EXCEPTION(pLeft != 0 && pLeft->rightScalar()->isConstant(),
00565                          std::logic_error,
00566                          "RearrangeLeftProductWithConstant::doTransform: "
00567                          "the right operand "
00568                          << pLeft->right() 
00569                          << "of the left operand " << left->toString()
00570                          << " is a constant. That case should have been "
00571                          "transformed out by now.");
00572       /* if the right operand is a constant, 
00573        * transform (alpha*u)*beta --> (alpha*beta)*u */
00574       if (right->isConstant())
00575         {
00576           if (verb() > 1)
00577             {
00578               Out::println("RearrangeLeftProductWithConstant::doTransform: "
00579                            "identified right operand "
00580                            "as a constant, and left operand as a product "
00581                            "involving a constant. Applying transformation "
00582                            "(alpha*u)*beta --> (alpha*beta)*u");
00583             }
00584           rtn =  getScalar((pLeft->left() * Expr::handle(right)) * pLeft->right());
00585           return true;
00586         }
00587       else
00588         /* if the right operand is non-constant, 
00589          * transform (alpha*u)*v --> alpha*(u*v) */
00590         {
00591           if (verb() > 1)
00592             {
00593               Out::println("RearrangeLeftProductWithConstant::doTransform: "
00594                            "identified right operand "
00595                            "as non-constant, and left operand as a product "
00596                            "involving a constant. Applying transformation "
00597                            "(alpha*u)*v --> alpha*(u*v)");
00598             }
00599           rtn = getScalar(pLeft->left() * (pLeft->right() * Expr::handle(right)));
00600           return true;
00601         }
00602     }
00603   return false;
00604 }
00605 
00606 
00607 bool TakeConstantUnderIntegralSign::doTransform(const RCP<ScalarExpr>& left, 
00608                                          const RCP<ScalarExpr>& right,
00609                                          RCP<ScalarExpr>& rtn) const
00610 {
00611   const SumOfIntegrals* sLeft 
00612     = dynamic_cast<const SumOfIntegrals*>(left.get());
00613   const SumOfIntegrals* sRight 
00614     = dynamic_cast<const SumOfIntegrals*>(right.get());
00615 
00616   TEUCHOS_TEST_FOR_EXCEPTION(sLeft != 0 && sRight != 0, std::logic_error,
00617                      "Product of integrals detected: left=" 
00618                      << left->toString() << " right=" << right->toString());
00619 
00620   if (sLeft != 0 || sRight != 0)
00621     {
00622       if (sLeft != 0)
00623         {
00624           SumOfIntegrals* l = new SumOfIntegrals(*sLeft);
00625           const SpatiallyConstantExpr* cRight 
00626             = dynamic_cast<const SpatiallyConstantExpr*>(right.get());
00627           TEUCHOS_TEST_FOR_EXCEPTION(cRight == 0, std::logic_error,
00628                              "Attempting to multiply non-constant expression "
00629                              << right->toString() << " with an integral");
00630           l->multiplyByConstant(cRight);
00631           
00632           rtn = rcp(l);
00633           return true;
00634         }
00635 
00636       if (sRight != 0)
00637         {
00638           SumOfIntegrals* r = new SumOfIntegrals(*sRight);
00639           const SpatiallyConstantExpr* cLeft
00640             = dynamic_cast<const SpatiallyConstantExpr*>(left.get());
00641           TEUCHOS_TEST_FOR_EXCEPTION(cLeft == 0, std::logic_error,
00642                              "Attempting to multiply non-constant expression "
00643                              << left->toString() << " with an integral");
00644           r->multiplyByConstant(cLeft);
00645           
00646           rtn = rcp(r);
00647           return true;
00648         }
00649     }
00650   else
00651     {
00652       return false;
00653     }
00654   return false;
00655 }

Site Contact