bool Expr::tryMultiplyComplex(const Expr& L, const Expr& R, Expr& rtn) const { TimeMonitor t(tryMultiplyComplexTimer()); TEUCHOS_TEST_FOR_EXCEPTION(L.size() != 1 || R.size() != 1, std::logic_error, "non-scalar exprs should have been reduced before " "call to tryMultiplyComplex(). Left=" << L << " right=" << R); if (L.isComplex() || R.isComplex()) { if (Re(L).sameAs(Re(R)) && Im(L).sameAs(-Im(R))) { rtn = Re(R)*Re(R) + Im(R)*Im(R); } else { Expr re = Re(L)*Re(R) - Im(L)*Im(R); Expr im = Re(L)*Im(R) + Im(L)*Re(R); rtn = new ComplexExpr(re, im); } return true; } else { return false; } }
bool Expr::tryAddComplex(const Expr& L, const Expr& R, int sign, Expr& rtn) const { TimeMonitor t(trySumComplexTimer()); TEUCHOS_TEST_FOR_EXCEPTION(L.size() != 1 || R.size() != 1, std::logic_error, "non-scalar exprs should have been reduced before " "call to tryAddComplex(). Left=" << L << " right=" << R); if (L.isComplex() || R.isComplex()) { if (sign > 0) { rtn = new ComplexExpr(L.real() + R.real(), L.imag() + R.imag()); } else { rtn = new ComplexExpr(L.real() - R.real(), L.imag() - R.imag()); } return true; } else { return false; } }
Expr Expr::operator/(const Expr& other) const { TimeMonitor t(opTimer()); /* if the right operand is a list, this operation * makes no sense */ TEUCHOS_TEST_FOR_EXCEPTION(other.size() != 1, std::runtime_error, "Expr::operator/ detected division by a non-scalar " "expression " << toString()); TEUCHOS_TEST_FOR_EXCEPTION(other.isSpectral(), std::logic_error, "Division by a Spectral Expr is not yet defined"); /* If other is complex, transform to make the denominator real */ if (other.isComplex()) { Expr magSq = other.real()*other.real() + other.imag()*other.imag(); return (*this) * other.conj() / magSq; } /* If I'm complex and the other is not, distribute division over re and im */ if (isComplex() && !other.isComplex()) { return new ComplexExpr(real()/other, imag()/other); } /* If I'm spectral and the other is not, distribute division over coefficients */ if (isSpectral() && !other.isSpectral() && !other.isComplex()) { const SpectralExpr* se = dynamic_cast<const SpectralExpr*>((*this)[0].ptr().get()); SpectralBasis basis = se->getSpectralBasis(); Array<Expr> coeff(basis.nterms()); for(int i=0; i<basis.nterms(); i++) { coeff[i] = se->getCoeff(i)/ other[0]; } Expr rtn = new SpectralExpr( basis, coeff); return rtn; } /* if we are a scalar, do simple scalar division */ if (this->size()==1) { return (*this)[0].divide(other[0]); } /* otherwise, divide each element of the left by the right operand */ Array<Expr> rtn(this->size()); for (int i=0; i<this->size(); i++) { rtn[i] = (*this)[i] / other; } return new ListExpr(rtn); }
Expr Complex(const Expr& re, const Expr& im) { TEUCHOS_TEST_FOR_EXCEPTION(re.size() != im.size(), std::runtime_error, "arguments mismatched in Complex(). Real part=" << re << ", imaginary part=" << im); TEUCHOS_TEST_FOR_EXCEPTION(re.isComplex() || im.isComplex(), std::runtime_error, "recursively defined complex number. Real part=" << re << ", imaginary part=" << im); if (re.totalSize() > 1) { Array<Expr> rtn(re.size()); for (int i=0; i<re.size(); i++) { rtn[i] = Complex(re[i], im[i]); } return new ListExpr(rtn); } const ZeroExpr* zr = dynamic_cast<const ZeroExpr*>(re[0].ptr().get()); const ZeroExpr* zi = dynamic_cast<const ZeroExpr*>(im[0].ptr().get()); if (zr == 0) /* nonzero real part */ { if (zi==0) /* nonzero imag part */ { return new ComplexExpr(re, im); } else /* zero imag part */ { return re; } } else /* zero real part */ { if (zi != 0) /* both are zero */ { return Expr(0.0); } else /* pure imaginary */ { return new ComplexExpr(0.0, im); } } return new ComplexExpr(re, im); }