00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
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
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
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
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
00222
00223
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
00247
00248
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
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
00336
00337
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
00368
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
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
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
00436
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
00489
00490 const ProductExpr* pRight
00491 = dynamic_cast<const ProductExpr*>(right.get());
00492
00493
00494
00495
00496
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
00511
00512
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
00528
00529
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
00552
00553
00554
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
00563
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
00573
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
00589
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 }