def test_Function(): assert mcode(f(x, y, z)) == "f[x, y, z]" assert mcode(sin(x)**cos(x)) == "Sin[x]^Cos[x]" assert mcode(sec(x) * acsc(x)) == "ArcCsc[x]*Sec[x]" assert mcode(atan2(x, y)) == "ArcTan[x, y]" assert mcode(conjugate(x)) == "Conjugate[x]" assert mcode(Max(x, y, z) * Min(y, z)) == "Max[x, y, z]*Min[y, z]" assert mcode(fresnelc(x)) == "FresnelC[x]" assert mcode(fresnels(x)) == "FresnelS[x]" assert mcode(gamma(x)) == "Gamma[x]" assert mcode(uppergamma(x, y)) == "Gamma[x, y]" assert mcode(polygamma(x, y)) == "PolyGamma[x, y]" assert mcode(loggamma(x)) == "LogGamma[x]" assert mcode(erf(x)) == "Erf[x]" assert mcode(erfc(x)) == "Erfc[x]" assert mcode(erfi(x)) == "Erfi[x]" assert mcode(erf2(x, y)) == "Erf[x, y]" assert mcode(expint(x, y)) == "ExpIntegralE[x, y]" assert mcode(erfcinv(x)) == "InverseErfc[x]" assert mcode(erfinv(x)) == "InverseErf[x]" assert mcode(erf2inv(x, y)) == "InverseErf[x, y]" assert mcode(Ei(x)) == "ExpIntegralEi[x]" assert mcode(Ci(x)) == "CosIntegral[x]" assert mcode(li(x)) == "LogIntegral[x]" assert mcode(Si(x)) == "SinIntegral[x]" assert mcode(Shi(x)) == "SinhIntegral[x]" assert mcode(Chi(x)) == "CoshIntegral[x]" assert mcode(beta(x, y)) == "Beta[x, y]" assert mcode(factorial(x)) == "Factorial[x]" assert mcode(factorial2(x)) == "Factorial2[x]" assert mcode(subfactorial(x)) == "Subfactorial[x]" assert mcode(FallingFactorial(x, y)) == "FactorialPower[x, y]" assert mcode(RisingFactorial(x, y)) == "Pochhammer[x, y]" assert mcode(catalan(x)) == "CatalanNumber[x]" assert mcode(harmonic(x)) == "HarmonicNumber[x]" assert mcode(harmonic(x, y)) == "HarmonicNumber[x, y]" assert mcode(Li(x)) == "LogIntegral[x] - LogIntegral[2]" assert mcode(LambertW(x)) == "ProductLog[x]" assert mcode(LambertW(x, -1)) == "ProductLog[-1, x]" assert mcode(LambertW(x, y)) == "ProductLog[y, x]"
def _invert_real(f, g_ys, symbol): """ Helper function for invert_real """ if not f.has(symbol): raise ValueError("Inverse of constant function doesn't exist") if f is symbol: return (f, g_ys) n = Dummy('n') if hasattr(f, 'inverse') and not isinstance(f, TrigonometricFunction) and \ not isinstance(f, HyperbolicFunction): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): return _invert_real( f.args[0], Union( imageset(Lambda(n, n), g_ys).intersect(Interval(0, oo)), imageset(Lambda(n, -n), g_ys).intersect(Interval(-oo, 0))), symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g != S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g != S.One: return _invert_real(h, imageset(Lambda(n, n / g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: res = imageset(Lambda(n, real_root(n, expo)), g_ys) if expo.is_rational: numer, denom = expo.as_numer_denom() if numer == S.One or numer == -S.One: return _invert_real(base, res, symbol) else: if numer % 2 == 0: n = Dummy('n') neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) else: return _invert_real(base, res, symbol) else: if not base.is_positive: raise ValueError("x**w where w is irrational is not " "defined for negative x") return _invert_real(base, res, symbol) if not base_has_sym: return _invert_real(expo, imageset(Lambda(n, log(n) / log(base)), g_ys), symbol) if isinstance(f, sin): n = Dummy('n') if isinstance(g_ys, FiniteSet): sin_invs = Union(*[imageset(Lambda(n, n*pi + (-1)**n*asin(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], sin_invs, symbol) if isinstance(f, csc): n = Dummy('n') if isinstance(g_ys, FiniteSet): csc_invs = Union(*[imageset(Lambda(n, n*pi + (-1)**n*acsc(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], csc_invs, symbol) if isinstance(f, cos): n = Dummy('n') if isinstance(g_ys, FiniteSet): cos_invs_f1 = Union(*[imageset(Lambda(n, 2*n*pi + acos(g_y)), \ S.Integers) for g_y in g_ys]) cos_invs_f2 = Union(*[imageset(Lambda(n, 2*n*pi - acos(g_y)), \ S.Integers) for g_y in g_ys]) cos_invs = Union(cos_invs_f1, cos_invs_f2) return _invert_real(f.args[0], cos_invs, symbol) if isinstance(f, sec): n = Dummy('n') if isinstance(g_ys, FiniteSet): sec_invs_f1 = Union(*[imageset(Lambda(n, 2*n*pi + asec(g_y)), \ S.Integers) for g_y in g_ys]) sec_invs_f2 = Union(*[imageset(Lambda(n, 2*n*pi - asec(g_y)), \ S.Integers) for g_y in g_ys]) sec_invs = Union(sec_invs_f1, sec_invs_f2) return _invert_real(f.args[0], sec_invs, symbol) if isinstance(f, tan) or isinstance(f, cot): n = Dummy('n') if isinstance(g_ys, FiniteSet): tan_cot_invs = Union(*[imageset(Lambda(n, n*pi + f.inverse()(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], tan_cot_invs, symbol) return (f, g_ys)
def _invert_real(f, g_ys, symbol): """ Helper function for invert_real """ if not f.has(symbol): raise ValueError("Inverse of constant function doesn't exist") if f is symbol: return (f, g_ys) n = Dummy('n') if hasattr(f, 'inverse') and not isinstance(f, TrigonometricFunction) and \ not isinstance(f, HyperbolicFunction): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): return _invert_real(f.args[0], Union(imageset(Lambda(n, n), g_ys).intersect(Interval(0, oo)), imageset(Lambda(n, -n), g_ys).intersect(Interval(-oo, 0))), symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g != S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g != S.One: return _invert_real(h, imageset(Lambda(n, n/g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: res = imageset(Lambda(n, real_root(n, expo)), g_ys) if expo.is_rational: numer, denom = expo.as_numer_denom() if numer == S.One or numer == - S.One: return _invert_real(base, res, symbol) else: if numer % 2 == 0: n = Dummy('n') neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) else: return _invert_real(base, res, symbol) else: if not base.is_positive: raise ValueError("x**w where w is irrational is not " "defined for negative x") return _invert_real(base, res, symbol) if not base_has_sym: return _invert_real(expo, imageset(Lambda(n, log(n)/log(base)), g_ys), symbol) if isinstance(f, sin): n = Dummy('n') if isinstance(g_ys, FiniteSet): sin_invs = Union(*[imageset(Lambda(n, n*pi + (-1)**n*asin(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], sin_invs, symbol) if isinstance(f, csc): n = Dummy('n') if isinstance(g_ys, FiniteSet): csc_invs = Union(*[imageset(Lambda(n, n*pi + (-1)**n*acsc(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], csc_invs, symbol) if isinstance(f, cos): n = Dummy('n') if isinstance(g_ys, FiniteSet): cos_invs_f1 = Union(*[imageset(Lambda(n, 2*n*pi + acos(g_y)), \ S.Integers) for g_y in g_ys]) cos_invs_f2 = Union(*[imageset(Lambda(n, 2*n*pi - acos(g_y)), \ S.Integers) for g_y in g_ys]) cos_invs = Union(cos_invs_f1, cos_invs_f2) return _invert_real(f.args[0], cos_invs, symbol) if isinstance(f, sec): n = Dummy('n') if isinstance(g_ys, FiniteSet): sec_invs_f1 = Union(*[imageset(Lambda(n, 2*n*pi + asec(g_y)), \ S.Integers) for g_y in g_ys]) sec_invs_f2 = Union(*[imageset(Lambda(n, 2*n*pi - asec(g_y)), \ S.Integers) for g_y in g_ys]) sec_invs = Union(sec_invs_f1, sec_invs_f2) return _invert_real(f.args[0], sec_invs, symbol) if isinstance(f, tan) or isinstance(f, cot): n = Dummy('n') if isinstance(g_ys, FiniteSet): tan_cot_invs = Union(*[imageset(Lambda(n, n*pi + f.inverse()(g_y)), \ S.Integers) for g_y in g_ys]) return _invert_real(f.args[0], tan_cot_invs, symbol) return (f, g_ys)