def __new__(cls, name, objects=EmptySet(), commutative_diagrams=EmptySet()): if not name: raise ValueError("A Category cannot have an empty name.") new_category = Basic.__new__(cls, Symbol(name), Class(objects), FiniteSet(*commutative_diagrams)) return new_category
def hom(self, A, B): """ Returns a 2-tuple of sets of morphisms between objects A and B: one set of morphisms listed as premises, and the other set of morphisms listed as conclusions. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy import pretty >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g], {g * f: "unique"}) >>> print(pretty(d.hom(A, C), use_unicode=False)) ({g*f:A-->C}, {g*f:A-->C}) See Also ======== Object, Morphism """ premises = EmptySet() conclusions = EmptySet() for morphism in self.premises.keys(): if (morphism.domain == A) and (morphism.codomain == B): premises |= FiniteSet(morphism) for morphism in self.conclusions.keys(): if (morphism.domain == A) and (morphism.codomain == B): conclusions |= FiniteSet(morphism) return (premises, conclusions)
def test_simplified_FiniteSet_in_CondSet(): assert ConditionSet(x, And(x < 1, x > -3), FiniteSet(0, 1, 2)) == FiniteSet(0) assert ConditionSet(x, x < 0, FiniteSet(0, 1, 2)) == EmptySet() assert ConditionSet(x, And(x < -3), EmptySet()) == EmptySet() y = Symbol('y') assert (ConditionSet(x, And(x > 0), FiniteSet(-1, 0, 1, y)) == Union(FiniteSet(1), ConditionSet(x, And(x > 0), FiniteSet(y)))) assert (ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(1, 4, 2, y)) == Union(FiniteSet(1, 4), ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(y))))
def _add_morphism_closure(morphisms, morphism, props, add_identities=True, recurse_composites=True): """ Adds a morphism and its attributes to the supplied dictionary ``morphisms``. If ``add_identities`` is True, also adds the identity morphisms for the domain and the codomain of ``morphism``. """ if not Diagram._set_dict_union(morphisms, morphism, props): # We have just added a new morphism. if isinstance(morphism, IdentityMorphism): if props: # Properties for identity morphisms don't really # make sense, because very much is known about # identity morphisms already, so much that they # are trivial. Having properties for identity # morphisms would only be confusing. raise ValueError( "Instances of IdentityMorphism cannot have properties." ) return if add_identities: empty = EmptySet() id_dom = IdentityMorphism(morphism.domain) id_cod = IdentityMorphism(morphism.codomain) Diagram._set_dict_union(morphisms, id_dom, empty) Diagram._set_dict_union(morphisms, id_cod, empty) for existing_morphism, existing_props in list(morphisms.items()): new_props = existing_props & props if morphism.domain == existing_morphism.codomain: left = morphism * existing_morphism Diagram._set_dict_union(morphisms, left, new_props) if morphism.codomain == existing_morphism.domain: right = existing_morphism * morphism Diagram._set_dict_union(morphisms, right, new_props) if isinstance(morphism, CompositeMorphism) and recurse_composites: # This is a composite morphism, add its components as # well. empty = EmptySet() for component in morphism.components: Diagram._add_morphism_closure(morphisms, component, empty, add_identities)
def constraint_to_matrix(self, constraint): """ Generates the corresponding block in the lp matrix from a given constraint and adds the result to the block dictionary. :param constraint: The constraint the corresponding block is generated from. """ constr_name = constraint_str(constraint) self.row_dicts[constr_name] = OrderedSet() row_dict = self.row_dicts[constr_name] if isinstance(constraint, Rel): lhs = constraint.lhs - constraint.rhs constr_query = True constr_query_symbols = EmptySet() if isinstance(constraint, GreaterThan): lhs *= -1 elif isinstance(constraint, ForAll): lhs = constraint.relation.lhs - constraint.relation.rhs if isinstance(constraint.relation, GreaterThan): lhs *= -1 constr_query = constraint.query constr_query_symbols = constraint.query_symbols else: raise Exception("Impossible-to-happen Exception!") var_blocks = self.expr_to_matrix(lhs, row_dict, constr_query, constr_query_symbols) self.blocks[constr_name] = var_blocks
def test_booleans(): """ test basic unions and intersections """ assert Union(l1, l2).equals(l1) assert Intersection(l1, l2).equals(l1) assert Intersection(l1, l4) == FiniteSet(Point(1, 1)) assert Intersection(Union(l1, l4), l3) == FiniteSet(Point(-1 / 3, -1 / 3), Point(5, 1)) assert Intersection(l1, FiniteSet(Point(7, -7))) == EmptySet() assert Intersection(Circle(Point(0, 0), 3), Line(p1, p2)) == FiniteSet(Point(-3, 0), Point(3, 0)) fs = FiniteSet(Point(1 / 3, 1), Point(2 / 3, 0), Point(9 / 5, 1 / 5), Point(7 / 3, 1)) # test the intersection of polygons assert Intersection(poly1, poly2) == fs # make sure if we union polygons with subsets, the subsets go away assert Union(poly1, poly2, fs) == Union(poly1, poly2) # make sure that if we union with a FiniteSet that isn't a subset, # that the points in the intersection stop being listed assert Union(poly1, FiniteSet(Point(0, 0), Point(3, 5))) == Union(poly1, FiniteSet(Point(3, 5))) # intersect two polygons that share an edge assert Intersection(poly1, poly3) == Union( FiniteSet(Point(3 / 2, 1), Point(2, 1)), Segment(Point(0, 0), Point(1, 0)))
def objective_to_matrix(self, objective): """ Grounds the objective of the given rlp into the matrix :param objective: The objective of the LP from which the corresponding block is generated from. """ var_blocks = self.expr_to_matrix(objective, OrderedSet(), True, EmptySet()) return var_blocks
def test_booleans(): """ test basic unions and intersections """ half = Rational(1, 2) p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) p5, p6, p7 = map(Point, [(3, 2), (1, -1), (0, 2)]) l1 = Line(Point(0, 0), Point(1, 1)) l2 = Line(Point(half, half), Point(5, 5)) l3 = Line(p2, p3) l4 = Line(p3, p4) poly1 = Polygon(p1, p2, p3, p4) poly2 = Polygon(p5, p6, p7) poly3 = Polygon(p1, p2, p5) assert Union(l1, l2).equals(l1) assert Intersection(l1, l2).equals(l1) assert Intersection(l1, l4) == FiniteSet(Point(1, 1)) assert Intersection(Union(l1, l4), l3) == FiniteSet(Point(-S(1) / 3, -S(1) / 3), Point(5, 1)) assert Intersection(l1, FiniteSet(Point(7, -7))) == EmptySet() assert Intersection(Circle(Point(0, 0), 3), Line(p1, p2)) == FiniteSet(Point(-3, 0), Point(3, 0)) assert Intersection(l1, FiniteSet(p1)) == FiniteSet(p1) assert Union(l1, FiniteSet(p1)) == l1 fs = FiniteSet(Point(S(1) / 3, 1), Point(S(2) / 3, 0), Point(S(9) / 5, S(1) / 5), Point(S(7) / 3, 1)) # test the intersection of polygons assert Intersection(poly1, poly2) == fs # make sure if we union polygons with subsets, the subsets go away assert Union(poly1, poly2, fs) == Union(poly1, poly2) # make sure that if we union with a FiniteSet that isn't a subset, # that the points in the intersection stop being listed assert Union(poly1, FiniteSet(Point(0, 0), Point(3, 5))) == Union(poly1, FiniteSet(Point(3, 5))) # intersect two polygons that share an edge assert Intersection(poly1, poly3) == Union( FiniteSet(Point(S(3) / 2, 1), Point(2, 1)), Segment(Point(0, 0), Point(1, 0)))
def solveset_complex(f, symbol): """ Solve a complex valued equation. Parameters ========== f : Expr The target equation symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as an unsolved object if algorithms to evaluate complete solutions are not yet implemented. `solveset_complex` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. See Also ======== solveset_real: solver for real domain Examples ======== >>> from sympy import Symbol, exp >>> from sympy.solvers.solveset import solveset_complex >>> from sympy.abc import x, a, b, c >>> solveset_complex(a*x**2 + b*x +c, x) {-b/(2*a) - sqrt(-4*a*c + b**2)/(2*a), -b/(2*a) + sqrt(-4*a*c + b**2)/(2*a)} * Due to the fact that complex extension of my real valued functions are multivariate even some simple equations can have infinitely many solution. >>> solveset_complex(exp(x) - 1, x) ImageSet(Lambda(_n, 2*_n*I*pi), Integers()) """ if not symbol.is_Symbol: raise ValueError(" %s is not a symbol" % (symbol)) f = sympify(f) original_eq = f if not isinstance(f, (Expr, Number)): raise ValueError(" %s is not a valid sympy expression" % (f)) f = together(f) # Without this equations like a + 4*x**2 - E keep oscillating # into form a/4 + x**2 - E/4 and (a + 4*x**2 - E)/4 if not fraction(f)[1].has(symbol): f = expand(f) if f.is_zero: return S.Complexes elif not f.has(symbol): result = EmptySet() elif f.is_Mul and all([_is_finite_with_finite_vars(m) for m in f.args]): result = Union(*[solveset_complex(m, symbol) for m in f.args]) else: lhs, rhs_s = invert_complex(f, 0, symbol) if lhs == symbol: result = rhs_s elif isinstance(rhs_s, FiniteSet): equations = [lhs - rhs for rhs in rhs_s] result = EmptySet() for equation in equations: if equation == f: if any( _has_rational_power(g, symbol)[0] for g in equation.args): result += _solve_radical(equation, symbol, solveset_complex) else: result += _solve_as_rational( equation, symbol, solveset_solver=solveset_complex, as_poly_solver=_solve_as_poly_complex) else: result += solveset_complex(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), S.Complexes) if isinstance(result, FiniteSet): result = [ s for s in result if isinstance(s, RootOf) or domain_check(original_eq, symbol, s) ] return FiniteSet(*result) else: return result
def solveset_real(f, symbol): """ Solves a real valued equation. Parameters ========== f : Expr The target equation symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as unsolved object if algorithms to evaluate complete solutions are not yet implemented. `solveset_real` claims to be complete in the set of the solution it returns. Raises ====== NotImplementedError Algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. See Also ======= solveset_complex : solver for complex domain Examples ======== >>> from sympy import Symbol, exp, sin, sqrt, I >>> from sympy.solvers.solveset import solveset_real >>> x = Symbol('x', real=True) >>> a = Symbol('a', real=True, finite=True, positive=True) >>> solveset_real(x**2 - 1, x) {-1, 1} >>> solveset_real(sqrt(5*x + 6) - 2 - x, x) {-1, 2} >>> solveset_real(x - I, x) EmptySet() >>> solveset_real(x - a, x) {a} >>> solveset_real(exp(x) - a, x) {log(a)} * In case the equation has infinitely many solutions an infinitely indexed `ImageSet` is returned. >>> solveset_real(sin(x) - 1, x) ImageSet(Lambda(_n, 2*_n*pi + pi/2), Integers()) * If the equation is true for any arbitrary value of the symbol a `S.Reals` set is returned. >>> solveset_real(x - x, x) (-oo, oo) """ if not symbol.is_Symbol: raise ValueError(" %s is not a symbol" % (symbol)) f = sympify(f) if not isinstance(f, (Expr, Number)): raise ValueError(" %s is not a valid sympy expression" % (f)) original_eq = f f = together(f) # In this, unlike in solveset_complex, expression should only # be expanded when fraction(f)[1] does not contain the symbol # for which we are solving if not symbol in fraction(f)[1].free_symbols and f.is_rational_function(): f = expand(f) if f.has(Piecewise): f = piecewise_fold(f) result = EmptySet() if f.expand().is_zero: return S.Reals elif not f.has(symbol): return EmptySet() elif f.is_Mul and all([_is_finite_with_finite_vars(m) for m in f.args]): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we are not silently allowing any # wrong solutions we are using this technique only if both f and g are # finite for a finite input. result = Union(*[solveset_real(m, symbol) for m in f.args]) elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \ _is_function_class_equation(HyperbolicFunction, f, symbol): result = _solve_real_trig(f, symbol) elif f.is_Piecewise: result = EmptySet() expr_set_pairs = f.as_expr_set_pairs() for (expr, in_set) in expr_set_pairs: solns = solveset_real(expr, symbol).intersect(in_set) result = result + solns else: lhs, rhs_s = invert_real(f, 0, symbol) if lhs == symbol: result = rhs_s elif isinstance(rhs_s, FiniteSet): equations = [lhs - rhs for rhs in rhs_s] for equation in equations: if equation == f: if any( _has_rational_power(g, symbol)[0] for g in equation.args): result += _solve_radical(equation, symbol, solveset_real) elif equation.has(Abs): result += _solve_abs(f, symbol) else: result += _solve_as_rational( equation, symbol, solveset_solver=solveset_real, as_poly_solver=_solve_as_poly_real) else: result += solveset_real(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), S.Reals) if isinstance(result, FiniteSet): result = [ s for s in result if isinstance(s, RootOf) or domain_check(original_eq, symbol, s) ] return FiniteSet(*result).intersect(S.Reals) else: return result.intersect(S.Reals)
def test_sympify_set(): n = Symbol('n') assert sympify({n}) == FiniteSet(n) assert sympify(set()) == EmptySet()
def __new__(cls, *args): """ Construct a new instance of Diagram. If no arguments are supplied, an empty diagram is created. If at least an argument is supplied, ``args[0]`` is interpreted as the premises of the diagram. If ``args[0]`` is a list, it is interpreted as a list of :class:`Morphism`'s, in which each :class:`Morphism` has an empty set of properties. If ``args[0]`` is a Python dictionary or a :class:`Dict`, it is interpreted as a dictionary associating to some :class:`Morphism`'s some properties. If at least two arguments are supplied ``args[1]`` is interpreted as the conclusions of the diagram. The type of ``args[1]`` is interpreted in exactly the same way as the type of ``args[0]``. If only one argument is supplied, the diagram has no conclusions. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import IdentityMorphism, Diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> IdentityMorphism(A) in d.premises.keys() True >>> g * f in d.premises.keys() True >>> d = Diagram([f, g], {g * f: "unique"}) >>> d.conclusions[g * f] {unique} """ premises = {} conclusions = {} # Here we will keep track of the objects which appear in the # premises. objects = EmptySet() if len(args) >= 1: # We've got some premises in the arguments. premises_arg = args[0] if isinstance(premises_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet() for morphism in premises_arg: objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure(premises, morphism, empty) elif isinstance(premises_arg, dict) or isinstance( premises_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in premises_arg.items(): objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure( premises, morphism, FiniteSet( *props) if iterable(props) else FiniteSet(props)) if len(args) >= 2: # We also have some conclusions. conclusions_arg = args[1] if isinstance(conclusions_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet() for morphism in conclusions_arg: # Check that no new objects appear in conclusions. if (morphism.domain in objects) and \ (morphism.codomain in objects): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure(conclusions, morphism, empty, add_identities=False, recurse_composites=False) elif isinstance(conclusions_arg, dict) or \ isinstance(conclusions_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in conclusions_arg.items(): # Check that no new objects appear in conclusions. if (morphism.domain in objects) and \ (morphism.codomain in objects): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure( conclusions, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props), add_identities=False, recurse_composites=False) return Basic.__new__(cls, Dict(premises), Dict(conclusions), objects)
def linsolve(system, *symbols): r""" Solve system of N linear equations with M variables, which means both under - and overdetermined systems are supported. The possible number of solutions is zero, one or infinite. Zero solutions throws a ValueError, where as infinite solutions are represented parametrically in terms of given symbols. For unique solution a FiniteSet of ordered tuple is returned. All Standard input formats are supported: For the given set of Equations, the respective input types are given below: .. math:: 3x + 2y - z = 1 .. math:: 2x - 2y + 4z = -2 .. math:: 2x - y + 2z = 0 * Augmented Matrix Form, `system` given below: :: [3 2 -1 1] system = [2 -2 4 -2] [2 -1 2 0] * List Of Equations Form `system = [3x + 2y - z - 1, 2x - 2y + 4z + 2, 2x - y + 2z]` * Input A & b Matrix Form (from Ax = b) are given as below: :: [3 2 -1 ] [ 1 ] A = [2 -2 4 ] b = [ -2 ] [2 -1 2 ] [ 0 ] `system = (A, b)` Symbols to solve for should be given as input in all the cases either in an iterable or as comma separated arguments. This is done to maintain consistency in returning solutions in the form of variable input by the user. The algorithm used here is Gauss-Jordan elimination, which results, after elimination, in an row echelon form matrix. Returns ======= A FiniteSet of ordered tuple of values of `symbols` for which the `system` has solution. Please note that general FiniteSet is unordered, the solution returned here is not simply a FiniteSet of solutions, rather it is a FiniteSet of ordered tuple, i.e. the first & only argument to FiniteSet is a tuple of solutions, which is ordered, & hence the returned solution is ordered. Also note that solution could also have been returned as an ordered tuple, FiniteSet is just a wrapper `{}` around the tuple. It has no other significance except for the fact it is just used to maintain a consistent output format throughout the solveset. Returns EmptySet(), if the linear system is inconsistent. Raises ====== ValueError The input is not valid. The symbols are not given. Examples ======== >>> from sympy import Matrix, S, linsolve, symbols >>> x, y, z = symbols("x, y, z") >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b = Matrix([3, 6, 9]) >>> A Matrix([ [1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b Matrix([ [3], [6], [9]]) >>> linsolve((A, b), [x, y, z]) {(-1, 2, 0)} * Parametric Solution: In case the system is under determined, the function will return parametric solution in terms of the given symbols. Free symbols in the system are returned as it is. For e.g. in the system below, `z` is returned as the solution for variable z, which means z is a free symbol, i.e. it can take arbitrary values. >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> b = Matrix([3, 6, 9]) >>> linsolve((A, b), [x, y, z]) {(z - 1, -2*z + 2, z)} * List of Equations as input >>> Eqns = [3*x + 2*y - z - 1, 2*x - 2*y + 4*z + 2, - x + S(1)/2*y - z] >>> linsolve(Eqns, x, y, z) {(1, -2, -2)} * Augmented Matrix as input >>> aug = Matrix([[2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> aug Matrix([ [2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> linsolve(aug, x, y, z) {(3/10, 2/5, 0)} * Solve for symbolic coefficients >>> a, b, c, d, e, f = symbols('a, b, c, d, e, f') >>> eqns = [a*x + b*y - c, d*x + e*y - f] >>> linsolve(eqns, x, y) {((-b*f + c*e)/(a*e - b*d), (a*f - c*d)/(a*e - b*d))} * A degenerate system returns solution as set of given symbols. >>> system = Matrix(([0,0,0], [0,0,0], [0,0,0])) >>> linsolve(system, x, y) {(x, y)} * For an empty system linsolve returns empty set >>> linsolve([ ], x) EmptySet() """ if not system: return S.EmptySet if not symbols: raise ValueError('Symbols must be given, for which solution of the ' 'system is to be found.') if hasattr(symbols[0], '__iter__'): symbols = symbols[0] try: sym = symbols[0].is_Symbol except AttributeError: sym = False if not sym: raise ValueError('Symbols or iterable of symbols must be given as ' 'second argument, not type %s: %s' % (type(symbols[0]), symbols[0])) # 1). Augmented Matrix input Form if isinstance(system, Matrix): A, b = system[:, :-1], system[:, -1:] elif hasattr(system, '__iter__'): # 2). A & b as input Form if len(system) == 2 and system[0].is_Matrix: A, b = system[0], system[1] # 3). List of equations Form if not system[0].is_Matrix: A, b = linear_eq_to_matrix(system, symbols) else: raise ValueError("Invalid arguments") # Solve using Gauss-Jordan elimination try: sol, params, free_syms = A.gauss_jordan_solve(b, freevar=True) except ValueError: # No solution return EmptySet() # Replace free parameters with free symbols solution = [] if params: for s in sol: for k, v in enumerate(params): s = s.xreplace({v: symbols[free_syms[k]]}) solution.append(simplify(s)) else: for s in sol: solution.append(simplify(s)) # Return solutions solution = FiniteSet(tuple(solution)) return solution
def solveset(f, symbol=None): """Solves a given inequality or equation with set as output Parameters ========== f : Expr or a relational. The target equation or inequality symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is True or is equal to zero. An `EmptySet` is returned if no solution is found. `solveset` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms for to find the solution of the given equation are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. `solveset` uses two underlying functions `solveset_real` and `solveset_complex` to solve equations. They are the solvers for real and complex domain respectively. The domain of the solver is decided by the assumption on the variable for which the equation is being solved. See Also ======== solveset_real: solver for real domain solveset_complex: solver for complex domain Examples ======== >>> from sympy import exp, Symbol, Eq, pprint >>> from sympy.solvers.solveset import solveset >>> from sympy.abc import x * Symbols in Sympy are complex by default. A complex variable will lead to the solving of the equation in complex domain. >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers()} * If you want to solve equation in real domain by the `solveset` interface, then specify the variable to real. Alternatively use `solveset\_real`. >>> x = Symbol('x', real=True) >>> solveset(exp(x) - 1, x) {0} >>> solveset(Eq(exp(x), 1), x) {0} * Inequalities are always solved in the real domain irrespective of the assumption on the variable for which the inequality is solved. >>> solveset(exp(x) > 1, x) (0, oo) """ from sympy.solvers.inequalities import solve_univariate_inequality if symbol is None: free_symbols = f.free_symbols if len(free_symbols) == 1: symbol = free_symbols.pop() else: raise ValueError( filldedent(''' The independent variable must be specified for a multivariate equation.''')) elif not symbol.is_Symbol: raise ValueError('A Symbol must be given, not type %s: %s' % (type(symbol), symbol)) real = (symbol.is_real is True) f = sympify(f) if f is S.false: return EmptySet() if f is S.true: if real: return S.Reals else: return S.Complex if isinstance(f, Eq): from sympy.core import Add f = Add(f.lhs, -f.rhs, evaluate=False) if f.is_Relational: if real is False: warnings.warn( filldedent(''' The variable you are solving for is complex but will assumed to be real since solving complex inequalities is not supported. ''')) return solve_univariate_inequality(f, symbol, relational=False) if isinstance(f, (Expr, Number)): if real is True: return solveset_real(f, symbol) else: return solveset_complex(f, symbol)
def expr_to_matrix(self, expr, row_dict, constr_query, constr_query_symbols): """ First normalizes a given expression with a visitor pattern then queries the knowledge base for the given query and assigns the results to their respective row and column index defined the the row and column dictionaries. :param expr: The expression to be grounded :type expr: Sympy Expression| RLPSum :param row_dict: An OrderedSet containing the row indices for the lp matrix for the given expression :type row_dict: OrderedSet :param constr_query: The query originating from a given constraint :type constr_query: Sympy Expression | RLPSum :param constr_query_symbols: A Set containing the query symbols for the given constraint query :type constr_query_symbols: FiniteSet :return: A dictionary containing a unique name for the variable and the results returned from the knowledge base. """ expr = Normalizer(expr).result if not isinstance(expr, Add): summands = [expr] else: summands = expr.args result = {} log.debug("\nSummands: %s", str(summands)) for summand in summands: log.debug("\n->summand: %s", str(summand)) if isinstance(summand, RlpSum): summand_query = summand.query summand_query_symbols = summand.query_symbols coef_query, coef_expr, variable = coefficient_to_query(summand.args[2]) else: summand_query = True summand_query_symbols = EmptySet() coef_query, coef_expr, variable = coefficient_to_query(summand) query_symbols = OrderedSet(constr_query_symbols + summand_query_symbols) query = constr_query & summand_query & coef_query answers = self.logkb.ask(query_symbols, query, coef_expr) variable_qs_indices = [] if variable is not None: variable_qs_indices = [query_symbols.index(arg) for arg in variable.args if isinstance(arg, SubSymbol)] constr_qs_indices = [query_symbols.index(symbol) for symbol in constr_query_symbols] variable_class = variable.__class__ col_dict = self.col_dicts.get(variable_class, OrderedSet()) self.col_dicts[variable_class] = col_dict # If the query yields no results we don't have to add anything to the matrix if len(answers) == 0: continue expr_index = len(answers[0]) - 1 sparse_data = [] for answer in answers: column_record = [] # use only subsymbols when they occur, otherwise constants qs_iterator = iter(variable_qs_indices) if variable is not None: for arg in variable.args: if isinstance(arg, SubSymbol): column_record.append(answer[qs_iterator.next()]) else: column_record.append(arg) col_dict_index = col_dict.add(tuple(column_record)) row_dict_index = row_dict.add(tuple(answer[i] for i in constr_qs_indices)) sparse_data.append([np.float(answer[expr_index]), row_dict_index, col_dict_index]) sparse_data = np.array(sparse_data) summand_block = sp.sparse.coo_matrix((sparse_data[:, 0], (sparse_data[:, 1], sparse_data[:, 2]))).todok() if variable_class in result: shape = (len(row_dict), len(col_dict)) result[variable_class].resize(shape) summand_block.resize(shape) result[variable_class] += summand_block else: result[variable_class] = summand_block return result
def solveset(f, symbol=None, domain=S.Complexes): """Solves a given inequality or equation with set as output Parameters ========== f : Expr or a relational. The target equation or inequality symbol : Symbol The variable for which the equation is solved domain : Set The domain over which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is True or is equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as unsolved object if algorithms to evaluatee complete solution are not yet implemented. `solveset` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. `solveset` uses two underlying functions `solveset_real` and `solveset_complex` to solve equations. They are the solvers for real and complex domain respectively. `solveset` ignores the assumptions on the variable being solved for and instead, uses the `domain` parameter to decide which solver to use. See Also ======== solveset_real: solver for real domain solveset_complex: solver for complex domain Examples ======== >>> from sympy import exp, Symbol, Eq, pprint, S, solveset >>> from sympy.abc import x * The default domain is complex. Not specifying a domain will lead to the solving of the equation in the complex domain. >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers()} * If you want to solve equation in real domain by the `solveset` interface, then specify that the domain is real. Alternatively use `solveset\_real`. >>> x = Symbol('x') >>> solveset(exp(x) - 1, x, S.Reals) {0} >>> solveset(Eq(exp(x), 1), x, S.Reals) {0} * Inequalities can be solved over the real domain only. Use of a complex domain leads to a NotImplementedError. >>> solveset(exp(x) > 1, x, S.Reals) (0, oo) """ from sympy.solvers.inequalities import solve_univariate_inequality if symbol is None: free_symbols = f.free_symbols if len(free_symbols) == 1: symbol = free_symbols.pop() else: raise ValueError( filldedent(''' The independent variable must be specified for a multivariate equation.''')) elif not symbol.is_Symbol: raise ValueError('A Symbol must be given, not type %s: %s' % (type(symbol), symbol)) f = sympify(f) if f is S.false: return EmptySet() if f is S.true: return domain if isinstance(f, Eq): from sympy.core import Add f = Add(f.lhs, -f.rhs, evaluate=False) if f.is_Relational: if not domain.is_subset(S.Reals): raise NotImplementedError("Inequalities in the complex domain are " "not supported. Try the real domain by" "setting domain=S.Reals") try: result = solve_univariate_inequality( f, symbol, relational=False).intersection(domain) except NotImplementedError: result = ConditionSet(symbol, f, domain) return result if isinstance(f, (Expr, Number)): if domain is S.Reals: return solveset_real(f, symbol) elif domain is S.Complexes: return solveset_complex(f, symbol) elif domain.is_subset(S.Reals): return Intersection(solveset_real(f, symbol), domain) else: return Intersection(solveset_complex(f, symbol), domain)
def _solveset(f, symbol, domain, _check=False): """Helper for solveset to return a result from an expression that has already been sympify'ed and is known to contain the given symbol.""" # _check controls whether the answer is checked or not from sympy.simplify.simplify import signsimp orig_f = f f = together(f) if f.is_Mul: _, f = f.as_independent(symbol, as_Add=False) if f.is_Add: a, h = f.as_independent(symbol) m, h = h.as_independent(symbol, as_Add=False) f = a/m + h # XXX condition `m != 0` should be added to soln f = piecewise_fold(f) # assign the solvers to use solver = lambda f, x, domain=domain: _solveset(f, x, domain) if domain.is_subset(S.Reals): inverter_func = invert_real else: inverter_func = invert_complex inverter = lambda f, rhs, symbol: inverter_func(f, rhs, symbol, domain) result = EmptySet() if f.expand().is_zero: return domain elif not f.has(symbol): return EmptySet() elif f.is_Mul and all(_is_finite_with_finite_vars(m, domain) for m in f.args): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we are not silently allowing any # wrong solutions we are using this technique only if both f and g are # finite for a finite input. result = Union(*[solver(m, symbol) for m in f.args]) elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \ _is_function_class_equation(HyperbolicFunction, f, symbol): result = _solve_trig(f, symbol, domain) elif f.is_Piecewise: dom = domain result = EmptySet() expr_set_pairs = f.as_expr_set_pairs() for (expr, in_set) in expr_set_pairs: if in_set.is_Relational: in_set = in_set.as_set() if in_set.is_Interval: dom -= in_set solns = solver(expr, symbol, in_set) result += solns else: lhs, rhs_s = inverter(f, 0, symbol) if lhs == symbol: # do some very minimal simplification since # repeated inversion may have left the result # in a state that other solvers (e.g. poly) # would have simplified; this is done here # rather than in the inverter since here it # is only done once whereas there it would # be repeated for each step of the inversion if isinstance(rhs_s, FiniteSet): rhs_s = FiniteSet(*[Mul(* signsimp(i).as_content_primitive()) for i in rhs_s]) result = rhs_s elif isinstance(rhs_s, FiniteSet): for equation in [lhs - rhs for rhs in rhs_s]: if equation == f: if any(_has_rational_power(g, symbol)[0] for g in equation.args) or _has_rational_power( equation, symbol)[0]: result += _solve_radical(equation, symbol, solver) elif equation.has(Abs): result += _solve_abs(f, symbol, domain) else: result += _solve_as_rational(equation, symbol, domain) else: result += solver(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), domain) if _check: if isinstance(result, ConditionSet): # it wasn't solved or has enumerated all conditions # -- leave it alone return result # whittle away all but the symbol-containing core # to use this for testing fx = orig_f.as_independent(symbol, as_Add=True)[1] fx = fx.as_independent(symbol, as_Add=False)[1] if isinstance(result, FiniteSet): # check the result for invalid solutions result = FiniteSet(*[s for s in result if isinstance(s, RootOf) or domain_check(fx, symbol, s)]) return result
def solveset_real(f, symbol): """ Solves a real valued equation. Parameters ========== f : Expr The target equation symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is equal to zero. An `EmptySet` is returned if no solution is found. `solveset_real` claims to be complete in the set of the solution it returns. Raises ====== NotImplementedError The algorithms for to find the solution of the given equation are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. See Also ======= solveset_complex : solver for complex domain Examples ======== >>> from sympy import Symbol, exp, sin, sqrt, I >>> from sympy.solvers.solveset import solveset_real >>> x = Symbol('x', real=True) >>> a = Symbol('a', real=True, finite=True, positive=True) >>> solveset_real(x**2 - 1, x) {-1, 1} >>> solveset_real(sqrt(5*x + 6) - 2 - x, x) {-1, 2} >>> solveset_real(x - I, x) EmptySet() >>> solveset_real(x - a, x) {a} >>> solveset_real(exp(x) - a, x) {log(a)} In case the equation has infinitely many solutions an infinitely indexed `ImageSet` is returned. >>> solveset_real(sin(x) - 1, x) ImageSet(Lambda(_n, 2*_n*pi + pi/2), Integers()) If the equation is true for any arbitrary value of the symbol a `S.Reals` set is returned. >>> solveset_real(x - x, x) (-oo, oo) """ if not symbol.is_Symbol: raise ValueError(" %s is not a symbol" % (symbol)) f = sympify(f) if not isinstance(f, (Expr, Number)): raise ValueError(" %s is not a valid sympy expression" % (f)) original_eq = f f = together(f) if f.has(Piecewise): f = piecewise_fold(f) result = EmptySet() if f.expand().is_zero: return S.Reals elif not f.has(symbol): return EmptySet() elif f.is_Mul and all([_is_finite_with_finite_vars(m) for m in f.args]): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we not are silently allowing any # wrong solutions we are using this technique only if both f and g and # finite for a finite input. result = Union(*[solveset_real(m, symbol) for m in f.args]) elif _is_function_class_equation(C.TrigonometricFunction, f, symbol) or \ _is_function_class_equation(C.HyperbolicFunction, f, symbol): result = _solve_real_trig(f, symbol) elif f.is_Piecewise: result = EmptySet() expr_set_pairs = f.as_expr_set_pairs() for (expr, in_set) in expr_set_pairs: solns = solveset_real(expr, symbol).intersect(in_set) result = result + solns else: lhs, rhs_s = invert_real(f, 0, symbol) if lhs == symbol: result = rhs_s elif isinstance(rhs_s, FiniteSet): equations = [lhs - rhs for rhs in rhs_s] for equation in equations: if equation == f: if any(_has_rational_power(g, symbol)[0] for g in equation.args): result += _solve_radical(equation, symbol, solveset_real) elif equation.has(Abs): result += _solve_abs(f, symbol) else: result += _solve_as_rational(equation, symbol, solveset_solver=solveset_real, as_poly_solver=_solve_as_poly_real) else: result += solveset_real(equation, symbol) else: raise NotImplementedError if isinstance(result, FiniteSet): result = [s for s in result if isinstance(s, RootOf) or domain_check(original_eq, symbol, s)] return FiniteSet(*result).intersect(S.Reals) else: return result.intersect(S.Reals)
def __new__(cls, *args): """ Construct a new instance of Diagram. If no arguments are supplied, an empty diagram is created. If at least an argument is supplied, ``args[0]`` is interpreted as the premises of the diagram. If ``args[0]`` is a list, it is interpreted as a list of :class:`Morphism`'s, in which each :class:`Morphism` has an empty set of properties. If ``args[0]`` is a Python dictionary or a :class:`Dict`, it is interpreted as a dictionary associating to some :class:`Morphism`'s some properties. If at least two arguments are supplied ``args[1]`` is interpreted as the conclusions of the diagram. The type of ``args[1]`` is interpreted in exactly the same way as the type of ``args[0]``. If only one argument is supplied, the diagram has no conclusions. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import IdentityMorphism, Diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> IdentityMorphism(A) in d.premises.keys() True >>> g * f in d.premises.keys() True >>> d = Diagram([f, g], {g * f: "unique"}) >>> d.conclusions[g * f] {unique} """ premises = {} conclusions = {} # Here we will keep track of the objects which appear in the # premises. objects = EmptySet() if len(args) >= 1: # We've got some premises in the arguments. premises_arg = args[0] if isinstance(premises_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet() for morphism in premises_arg: objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure(premises, morphism, empty) elif isinstance(premises_arg, dict) or isinstance(premises_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in premises_arg.items(): objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure( premises, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props)) if len(args) >= 2: # We also have some conclusions. conclusions_arg = args[1] if isinstance(conclusions_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet() for morphism in conclusions_arg: # Check that no new objects appear in conclusions. if ((sympify(objects.contains(morphism.domain)) is S.true) and (sympify(objects.contains(morphism.codomain)) is S.true)): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure( conclusions, morphism, empty, add_identities=False, recurse_composites=False) elif isinstance(conclusions_arg, dict) or \ isinstance(conclusions_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in conclusions_arg.items(): # Check that no new objects appear in conclusions. if (morphism.domain in objects) and \ (morphism.codomain in objects): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure( conclusions, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props), add_identities=False, recurse_composites=False) return Basic.__new__(cls, Dict(premises), Dict(conclusions), objects)
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 denom % 2 == 0 and \ g_ys.is_subset(Interval(S.NegativeInfinity, 0, right_open=True)): return (symbol, EmptySet()) 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)