[Python] Is there a way to convert from instances of sympy.core.numbers classes to python's...

Discussão em 'Python' iniciado por Stack, Dezembro 1, 2024.

  1. Stack

    Stack Membro Participativo

    When using sympy.solve(x,x), the output is always a sympy class, rather than being a native python class.

    Context:

    I am implementing the concept of Infinite Sets (like the set of integers, rationals etc), Binary Operations and Group-Like structures into python. The problem occurs when trying to determine if a Group-Like structure has an identity element.

    To do this, Infinite Sets operate using a condition (passed in as a lambda function) that then determines if an input would be a member of that set. As it does not behave as a python set (it has no strict values whatsoever), and has infinite length, it cannot be iterated over. The Infinite Set has no knowledge of what any of its elements are, but is capable of identifying a value as an element if it meets the condition passed in.

    An Identity Element of a Group-Like structure is an element (e) of a set S, such that the application of a Binary Operation ($) on e and any other element (a) of S will yield a. Consider the operation +, and the set of integers. The Identity Element (e) would be such that a+e = a, which is intuitively when e=0.

    Code:

    In Python, we can construct the binary operation as: ADD = BinaryOperation(lambda a,b: a+b), and the set of integers as: Integers = InfiniteSet(lambda x: isinstance(x,int)), where the parameter given is assigned to the variable self.Condition. The class Binary Operation uses the __call__ method which directly calls the lambda method it was passed (so ADD(5,3) uses the lambda function with a=5 and b=3, to give 8). It also has a property Expr, which substitutes in sympy Symbols "a" and "b" to its function and returns the result. ADD.Expr will result in the sympy expression a+b The class InfiniteSet uses the __contains__ method which reads: def __contains__(self,o): return self.Condition(o) Note that x.__contains__(y) is identical to y in x.

    When determining if a Group-Like structure has an identity element, it is possible (but not optimised) to iterate over the set, but this cannot be done for Infinite Sets, as they only store a condition. I am therefore using Sympy to find the value "e", such that when the binary operation is applied, the same result is produced, which can be done with sympy.solve.

    The Group-Like structure has variables Set and BinOp representing the Infinite Set and Binary Operation objects respectively, and a property HasIdentity, which determines if the group has an identity element as described above (in this case b, in order to be consistent with the Binary Operation's .Expr property). def HasIdentity(self): return sympy.solve(self.BinOp.Expr-"a","b")[0] in self.Set As sympy.solve returns a list of all solutions, indexing with 0 will find the only solution (there is a proof that only 1 such value exists).

    Problem: It would be expected that running G.HasIdentity on a Group-Like structure G, with Set: Integer, and Binary Operation: ADD (both defined earlier) would result in True.

    However, this statement will return False. When trying to determine the bug, I tested the Condition function against the expected output of solve (which is 0), and received the expected output (True), confirming that 0 is in the set of integers. As this condition only holds 1 basic Boolean operation, I concluded that the type of the sympy.solve output was different, and using the type() function identified it as sympy.core.numbers.Zero. When testing other equality expressions for reproducibility, such as sympy.solve(x-2,x), the output is instead an instance of sympy.core.numbers.Integer with internal value 2. When printing sympy.core.numbers.Zero's mro() function, it gives a list of other sympy.core classes that it inherits from. This list does not include any native Python classes (other than object), where one would expect that sympy.core.numbers.Integer (which sympy.core.numbers.Zero inherits from) would inherit from int.

    What I expected sympy.solve to return was the same solution but as it's native python type.

    I am only interested in solving univariate functions and therefore the case of the solution being an instance of sympy.Expr is irrelevant (solutions will never be in terms of other variables). I am aware that it is possible to explicitly typecast the output to an integer/float etc, but typecasting all outputs of sympy.solve to int would result in values failing to adhere to conditions only allowing floats, and vice versa. This is therefore not really an option. I am looking for a solution that will convert the output to its native python type, e.g. an output of 0.5 to a float, but an output of *i* to a complex. Note that typecasting a variable to a specific type will force it to that type, such that float(0) and complex(0) are no longer instances of int

    It is possible to set up a mapping (probably as a dictionary of sympy's classes as keys, and the respective python classes as values), then run the typecast through this, but I was looking for a more elegant solution.

    From looking online, I have been unable to find a generic solution to this that can typecast a solution to sympy.solve to native Python.

    As a side note, if anyone can explain why sympy chooses to return its values as these, that would be appreciated.

    Continue reading...

Compartilhe esta Página