def _set_function(f, x):
    from sympy.sets.sets import is_function_invertible_in_set
    # If the function is invertible, intersect the maps of the sets.
    if is_function_invertible_in_set(f, x):
        return Intersection(imageset(f, arg) for arg in x.args)
    else:
        return ImageSet(Lambda(_x, f(_x)), x)
Ejemplo n.º 2
0
def _set_function(f, x):
    from sympy.sets.sets import is_function_invertible_in_set
    # If the function is invertible, intersect the maps of the sets.
    if is_function_invertible_in_set(f, x):
        return Intersection(*(imageset(f, arg) for arg in x.args))
    else:
        return ImageSet(Lambda(_x, f(_x)), x)
Ejemplo n.º 3
0
def _solve_as_poly(f, symbol, solveset_solver, invert_func):
    """
    Solve the equation using polynomial techniques if it already is a
    polynomial equation or, with a change of variables, can be made so.
    """
    result = None
    if f.is_polynomial(symbol):

        solns = roots(f, symbol, cubics=True, quartics=True,
                      quintics=True, domain='EX')
        num_roots = sum(solns.values())
        if degree(f, symbol) <= num_roots:
            result = FiniteSet(*solns.keys())
        else:
            poly = Poly(f, symbol)
            solns = poly.all_roots()
            if poly.degree() <= len(solns):
                result = FiniteSet(*solns)
            else:
                result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
    else:
        poly = Poly(f)
        if poly is None:
            result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
        gens = [g for g in poly.gens if g.has(symbol)]

        if len(gens) == 1:
            poly = Poly(poly, gens[0])
            gen = poly.gen
            deg = poly.degree()
            poly = Poly(poly.as_expr(), poly.gen, composite=True)
            poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True,
                                          quintics=True).keys())

            if len(poly_solns) < deg:
                result = ConditionSet(symbol, Eq(f, 0), S.Complexes)

            if gen != symbol:
                y = Dummy('y')
                lhs, rhs_s = invert_func(gen, y, symbol)
                if lhs is symbol:
                    result = Union(*[rhs_s.subs(y, s) for s in poly_solns])
                else:
                    result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
        else:
            result = ConditionSet(symbol, Eq(f, 0), S.Complexes)

    if result is not None:
        if isinstance(result, FiniteSet):
            # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2
            # - sqrt(2)*I/2. We are not expanding for solution with free
            # variables because that makes the solution more complicated. For
            # example expand_complex(a) returns re(a) + I*im(a)
            if all([s.free_symbols == set() and not isinstance(s, RootOf)
                    for s in result]):
                s = Dummy('s')
                result = imageset(Lambda(s, expand_complex(s)), result)
        return result
    else:
        return ConditionSet(symbol, Eq(f, 0), S.Complexes)
Ejemplo n.º 4
0
def _solve_as_poly(f, symbol, solveset_solver, invert_func):
    """
    Solve the equation using polynomial techniques if it already is a
    polynomial equation or, with a change of variables, can be made so.
    """
    result = None
    if f.is_polynomial(symbol):

        solns = roots(f, symbol, cubics=True, quartics=True,
                      quintics=True, domain='EX')
        num_roots = sum(solns.values())
        if degree(f, symbol) <= num_roots:
            result = FiniteSet(*solns.keys())
        else:
            poly = Poly(f, symbol)
            solns = poly.all_roots()
            if poly.degree() <= len(solns):
                result = FiniteSet(*solns)
            else:
                result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
    else:
        poly = Poly(f)
        if poly is None:
            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
        gens = [g for g in poly.gens if g.has(symbol)]

        if len(gens) == 1:
            poly = Poly(poly, gens[0])
            gen = poly.gen
            deg = poly.degree()
            poly = Poly(poly.as_expr(), poly.gen, composite=True)
            poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True,
                                          quintics=True).keys())

            if len(poly_solns) < deg:
                result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)

            if gen != symbol:
                y = Dummy('y')
                lhs, rhs_s = invert_func(gen, y, symbol)
                if lhs is symbol:
                    result = Union(*[rhs_s.subs(y, s) for s in poly_solns])
                else:
                    result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
        else:
            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)

    if result is not None:
        if isinstance(result, FiniteSet):
            # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2
            # - sqrt(2)*I/2. We are not expanding for solution with free
            # variables because that makes the solution more complicated. For
            # example expand_complex(a) returns re(a) + I*im(a)
            if all([s.free_symbols == set() and not isinstance(s, RootOf)
                    for s in result]):
                s = Dummy('s')
                result = imageset(Lambda(s, expand_complex(s)), result)
        return result
    else:
        return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
Ejemplo n.º 5
0
def _invert_complex(f, g_ys, symbol):
    """ Helper function for invert_complex """

    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 f.is_Add:
        # f = g + h
        g, h = f.as_independent(symbol)
        if g != S.Zero:
            return _invert_complex(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_complex(h, imageset(Lambda(n, n / g), g_ys), symbol)

    if hasattr(f, 'inverse') and \
       not isinstance(f, TrigonometricFunction) and \
       not isinstance(f, exp):
        if len(f.args) > 1:
            raise ValueError("Only functions with one argument are supported.")
        return _invert_complex(f.args[0],
                               imageset(Lambda(n,
                                               f.inverse()(n)), g_ys), symbol)

    if isinstance(f, exp):
        if isinstance(g_ys, FiniteSet):
            exp_invs = Union(*[
                imageset(
                    Lambda(n,
                           I * (2 * n * pi + arg(g_y)) +
                           log(Abs(g_y))), S.Integers) for g_y in g_ys
                if g_y != 0
            ])
            return _invert_complex(f.args[0], exp_invs, symbol)
    return (f, g_ys)
Ejemplo n.º 6
0
def _invert_complex(f, g_ys, symbol):
    """Helper function for _invert."""

    if f == symbol:
        return (f, g_ys)

    n = Dummy("n")

    if f.is_Add:
        # f = g + h
        g, h = f.as_independent(symbol)
        if g is not S.Zero:
            return _invert_complex(h, imageset(Lambda(n, n - g), g_ys), symbol)

    if f.is_Mul:
        # f = g*h
        g, h = f.as_independent(symbol)

        if g is not S.One:
            return _invert_complex(h, imageset(Lambda(n, n / g), g_ys), symbol)

    if hasattr(f, "inverse") and not isinstance(f, TrigonometricFunction) and not isinstance(f, exp):
        if len(f.args) > 1:
            raise ValueError("Only functions with one argument are supported.")
        return _invert_complex(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol)

    if isinstance(f, exp):
        if isinstance(g_ys, FiniteSet):
            exp_invs = Union(
                *[
                    imageset(Lambda(n, I * (2 * n * pi + arg(g_y)) + log(Abs(g_y))), S.Integers)
                    for g_y in g_ys
                    if g_y != 0
                ]
            )
            return _invert_complex(f.args[0], exp_invs, symbol)

    return (f, g_ys)
Ejemplo n.º 7
0
def _invert_complex(f, g_ys, symbol):
    """ Helper function for invert_complex """

    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 f.is_Add:
        # f = g + h
        g, h = f.as_independent(symbol)
        if g != S.Zero:
            return _invert_complex(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_complex(h, imageset(Lambda(n, n/g), g_ys), symbol)

    if hasattr(f, 'inverse') and \
       not isinstance(f, C.TrigonometricFunction) and \
       not isinstance(f, exp):
        if len(f.args) > 1:
            raise ValueError("Only functions with one argument are supported.")
        return _invert_complex(f.args[0],
                               imageset(Lambda(n, f.inverse()(n)), g_ys), symbol)

    if isinstance(f, exp):
        if isinstance(g_ys, FiniteSet):
            exp_invs = Union(*[imageset(Lambda(n, I*(2*n*pi + arg(g_y)) +
                                               log(Abs(g_y))), S.Integers)
                               for g_y in g_ys])
            return _invert_complex(f.args[0], exp_invs, symbol)
    return (f, g_ys)
Ejemplo n.º 8
0
def _solve_radical(f, symbol, solveset_solver):
    """ Helper function to solve equations with radicals """
    eq, cov = unrad(f)
    if not cov:
        result = solveset_solver(eq, symbol) - Union(*[solveset_solver(g, symbol) for g in denoms(f, [symbol])])
    else:
        y, yeq = cov
        if not solveset_solver(y - I, y):
            yreal = Dummy("yreal", real=True)
            yeq = yeq.xreplace({y: yreal})
            eq = eq.xreplace({y: yreal})
            y = yreal
        g_y_s = solveset_solver(yeq, symbol)
        f_y_sols = solveset_solver(eq, y)
        result = Union(*[imageset(Lambda(y, g_y), f_y_sols) for g_y in g_y_s])

    return FiniteSet(*[s for s in result if checksol(f, symbol, s) is True])
Ejemplo n.º 9
0
def _solve_radical(f, symbol, solveset_solver):
    """ Helper function to solve equations with radicals """
    eq, cov = unrad(f)
    if not cov:
        result = solveset_solver(eq, symbol) - \
            Union(*[solveset_solver(g, symbol) for g in denoms(f, [symbol])])
    else:
        y, yeq = cov
        if not solveset_solver(y - I, y):
            yreal = Dummy('yreal', real=True)
            yeq = yeq.xreplace({y: yreal})
            eq = eq.xreplace({y: yreal})
            y = yreal
        g_y_s = solveset_solver(yeq, symbol)
        f_y_sols = solveset_solver(eq, y)
        result = Union(*[imageset(Lambda(y, g_y), f_y_sols) for g_y in g_y_s])

    return FiniteSet(*[s for s in result if checksol(f, symbol, s) is True])
Ejemplo n.º 10
0
def _solve_radical(f, symbol, solveset_solver):
    """ Helper function to solve equations with radicals """
    from sympy.solvers.solvers import unrad
    try:
        eq, cov, dens = unrad(f)
        if cov == []:
            result = solveset_solver(eq, symbol) - \
                Union(*[solveset_solver(g, symbol) for g in dens])
        else:
            if len(cov) > 1:
                raise NotImplementedError("Multivariate solver is "
                                          "not implemented.")
            else:
                y = cov[0][0]
                g_y_s = solveset_solver(cov[0][1], symbol)
                f_y_sols = solveset_solver(eq, y)
                result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
                                 for g_y in g_y_s])

        return FiniteSet(*[s for s in result if checksol(f, symbol, s) is True])
    except ValueError:
        raise NotImplementedError
Ejemplo n.º 11
0
def _set_function(f, self):  # noqa:F811
    if not self:
        return S.EmptySet
    if not isinstance(f.expr, Expr):
        return
    if self.size == 1:
        return FiniteSet(f(self[0]))
    if f is S.IdentityFunction:
        return self

    x = f.variables[0]
    expr = f.expr
    # handle f that is linear in f's variable
    if x not in expr.free_symbols or x in expr.diff(x).free_symbols:
        return
    if self.start.is_finite:
        F = f(self.step * x + self.start)  # for i in range(len(self))
    else:
        F = f(-self.step * x + self[-1])
    F = expand_mul(F)
    if F != expr:
        return imageset(x, F, Range(self.size))
Ejemplo n.º 12
0
def _set_function(f, self):
    from sympy.core.function import expand_mul
    if not self:
        return S.EmptySet
    if not isinstance(f.expr, Expr):
        return
    if self.size == 1:
        return FiniteSet(f(self[0]))
    if f is S.IdentityFunction:
        return self

    x = f.variables[0]
    expr = f.expr
    # handle f that is linear in f's variable
    if x not in expr.free_symbols or x in expr.diff(x).free_symbols:
        return
    if self.start.is_finite:
        F = f(self.step*x + self.start)  # for i in range(len(self))
    else:
        F = f(-self.step*x + self[-1])
    F = expand_mul(F)
    if F != expr:
        return imageset(x, F, Range(self.size))
Ejemplo n.º 13
0
def _solve_radical(f, symbol, solveset_solver):
    """ Helper function to solve equations with radicals """
    from sympy.solvers.solvers import unrad
    try:
        eq, cov, dens = unrad(f)
        if cov == []:
            result = solveset_solver(eq, symbol) - \
                Union(*[solveset_solver(g, symbol) for g in dens])
        else:
            if len(cov) > 1:
                raise NotImplementedError("Multivariate solver is "
                                          "not implemented.")
            else:
                y = cov[0][0]
                g_y_s = solveset_solver(cov[0][1], symbol)
                f_y_sols = solveset_solver(eq, y)
                result = Union(
                    *[imageset(Lambda(y, g_y), f_y_sols) for g_y in g_y_s])

        return FiniteSet(
            *[s for s in result if checksol(f, symbol, s) is True])
    except ValueError:
        raise NotImplementedError
Ejemplo n.º 14
0
def _set_function(f, x):
    return Union(*(imageset(f, arg) for arg in x.args))
Ejemplo n.º 15
0
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)
Ejemplo n.º 16
0
def _(f, x):
    return Union(*(imageset(f, arg) for arg in x.args))
def _set_function(f, x):
    from sympy.functions.elementary.miscellaneous import Min, Max
    from sympy.solvers.solveset import solveset
    from sympy.core.function import diff, Lambda
    from sympy.series import limit
    from sympy.calculus.singularities import singularities
    from sympy.sets import Complement
    # TODO: handle functions with infinitely many solutions (eg, sin, tan)
    # TODO: handle multivariate functions

    expr = f.expr
    if len(expr.free_symbols) > 1 or len(f.variables) != 1:
        return
    var = f.variables[0]

    if expr.is_Piecewise:
        result = S.EmptySet
        domain_set = x
        for (p_expr, p_cond) in expr.args:
            if p_cond is true:
                intrvl = domain_set
            else:
                intrvl = p_cond.as_set()
                intrvl = Intersection(domain_set, intrvl)

            if p_expr.is_Number:
                image = FiniteSet(p_expr)
            else:
                image = imageset(Lambda(var, p_expr), intrvl)
            result = Union(result, image)

            # remove the part which has been `imaged`
            domain_set = Complement(domain_set, intrvl)
            if domain_set.is_EmptySet:
                break
        return result

    if not x.start.is_comparable or not x.end.is_comparable:
        return

    try:
        sing = [i for i in singularities(expr, var)
            if i.is_real and i in x]
    except NotImplementedError:
        return

    if x.left_open:
        _start = limit(expr, var, x.start, dir="+")
    elif x.start not in sing:
        _start = f(x.start)
    if x.right_open:
        _end = limit(expr, var, x.end, dir="-")
    elif x.end not in sing:
        _end = f(x.end)

    if len(sing) == 0:
        solns = list(solveset(diff(expr, var), var))

        extr = [_start, _end] + [f(i) for i in solns
                                 if i.is_real and i in x]
        start, end = Min(*extr), Max(*extr)

        left_open, right_open = False, False
        if _start <= _end:
            # the minimum or maximum value can occur simultaneously
            # on both the edge of the interval and in some interior
            # point
            if start == _start and start not in solns:
                left_open = x.left_open
            if end == _end and end not in solns:
                right_open = x.right_open
        else:
            if start == _end and start not in solns:
                left_open = x.right_open
            if end == _start and end not in solns:
                right_open = x.left_open

        return Interval(start, end, left_open, right_open)
    else:
        return imageset(f, Interval(x.start, sing[0],
                                    x.left_open, True)) + \
            Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True))
                    for i in range(0, len(sing) - 1)]) + \
            imageset(f, Interval(sing[-1], x.end, True, x.right_open))
def _set_function(f, x):
    return Union(imageset(f, arg) for arg in x.args)
Ejemplo n.º 19
0
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, C.TrigonometricFunction):
        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(g_ys, imageset(Lambda(n, -n), g_ys)), 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, Pow(n, 1/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, 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)
Ejemplo n.º 20
0
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):
        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):
        g_ys = g_ys - FiniteSet(*[g_y for g_y in g_ys if g_y.is_negative])
        return _invert_real(f.args[0],
                            Union(g_ys, imageset(Lambda(n, -n), g_ys)), 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, Pow(n, 1 / 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, 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)
Ejemplo n.º 21
0
def _set_function(f, x):  # noqa:F811
    return Union(*(imageset(f, arg) for arg in x.args))
Ejemplo n.º 22
0
def _set_function(f, x):
    from sympy.functions.elementary.miscellaneous import Min, Max
    from sympy.solvers.solveset import solveset
    from sympy.core.function import diff, Lambda
    from sympy.series import limit
    from sympy.calculus.singularities import singularities
    from sympy.sets import Complement
    # TODO: handle functions with infinitely many solutions (eg, sin, tan)
    # TODO: handle multivariate functions

    expr = f.expr
    if len(expr.free_symbols) > 1 or len(f.variables) != 1:
        return
    var = f.variables[0]

    if expr.is_Piecewise:
        result = S.EmptySet
        domain_set = x
        for (p_expr, p_cond) in expr.args:
            if p_cond is true:
                intrvl = domain_set
            else:
                intrvl = p_cond.as_set()
                intrvl = Intersection(domain_set, intrvl)

            if p_expr.is_Number:
                image = FiniteSet(p_expr)
            else:
                image = imageset(Lambda(var, p_expr), intrvl)
            result = Union(result, image)

            # remove the part which has been `imaged`
            domain_set = Complement(domain_set, intrvl)
            if domain_set.is_EmptySet:
                break
        return result

    if not x.start.is_comparable or not x.end.is_comparable:
        return

    try:
        sing = [i for i in singularities(expr, var)
            if i.is_real and i in x]
    except NotImplementedError:
        return

    if x.left_open:
        _start = limit(expr, var, x.start, dir="+")
    elif x.start not in sing:
        _start = f(x.start)
    if x.right_open:
        _end = limit(expr, var, x.end, dir="-")
    elif x.end not in sing:
        _end = f(x.end)

    if len(sing) == 0:
        solns = list(solveset(diff(expr, var), var))

        extr = [_start, _end] + [f(i) for i in solns
                                 if i.is_real and i in x]
        start, end = Min(*extr), Max(*extr)

        left_open, right_open = False, False
        if _start <= _end:
            # the minimum or maximum value can occur simultaneously
            # on both the edge of the interval and in some interior
            # point
            if start == _start and start not in solns:
                left_open = x.left_open
            if end == _end and end not in solns:
                right_open = x.right_open
        else:
            if start == _end and start not in solns:
                left_open = x.right_open
            if end == _start and end not in solns:
                right_open = x.left_open

        return Interval(start, end, left_open, right_open)
    else:
        return imageset(f, Interval(x.start, sing[0],
                                    x.left_open, True)) + \
            Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True))
                    for i in range(0, len(sing) - 1)]) + \
            imageset(f, Interval(sing[-1], x.end, True, x.right_open))
Ejemplo n.º 23
0
def _set_function(f, x):  # noqa:F811
    # If the function is invertible, intersect the maps of the sets.
    if is_function_invertible_in_set(f, x):
        return Intersection(*(imageset(f, arg) for arg in x.args))
    else:
        return ImageSet(Lambda(_x, f(_x)), x)
Ejemplo n.º 24
0
def _invert_real(f, g_ys, symbol):
    """Helper function for _invert."""

    if f == symbol:
        return (f, g_ys)

    n = Dummy('n', real=True)

    if hasattr(f, 'inverse') and not isinstance(f, (
            TrigonometricFunction,
            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):
        pos = Interval(0, S.Infinity)
        neg = Interval(S.NegativeInfinity, 0)
        return _invert_real(f.args[0],
                    Union(imageset(Lambda(n, n), g_ys).intersect(pos),
                          imageset(Lambda(n, -n), g_ys).intersect(neg)), symbol)

    if f.is_Add:
        # f = g + h
        g, h = f.as_independent(symbol)
        if g is not 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 is not 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, TrigonometricFunction):
        if isinstance(g_ys, FiniteSet):
            def inv(trig):
                if isinstance(f, (sin, csc)):
                    F = asin if isinstance(f, sin) else acsc
                    return (lambda a: n*pi + (-1)**n*F(a),)
                if isinstance(f, (cos, sec)):
                    F = acos if isinstance(f, cos) else asec
                    return (
                        lambda a: 2*n*pi + F(a),
                        lambda a: 2*n*pi - F(a),)
                if isinstance(f, (tan, cot)):
                    return (lambda a: n*pi + f.inverse()(a),)

            n = Dummy('n', integer=True)
            invs = S.EmptySet
            for L in inv(f):
                invs += Union(*[imageset(Lambda(n, L(g)), S.Integers) for g in g_ys])
            return _invert_real(f.args[0], invs, symbol)

    return (f, g_ys)
Ejemplo n.º 25
0
def function_sets(f, x):
    return Union(imageset(f, arg) for arg in x.args)