In my Python script for the line
result = sp.solve(eqn)
I get the following output in the format similar to
result = 0.0100503358535014*I
I gather this means the solution is a complex number. So in this case it could also be seen as result = 0.01j.
I want to add formatting to my code to change result = 0.0100503358535014*I to something more like result = 0.01j. However I am finding issues trying to do this as I was trying to use isinstance to check if result was complex
if isinstance(result, complex):
print "Result is complex!"
... my code here...
However this loop is never entered (i.e 0.0100503358535014*I isn't classified as complex here).
What way should I write an if statement to check if result is given in the manner xxxxxxx*I correctly?
SymPy supports Python's built-in function complex():
>>> import sympy
>>> x = sympy.sqrt(-2)
>>> x
sqrt(2)*I
>>> complex(x)
1.4142135623730951j
There are some examples in http://docs.sympy.org/latest/modules/evalf.html
A Python complex number can be formatted similar to a float:
>>> format(complex(x), 'e')
'0.000000e+00+1.414214e+00j'
>>> format(complex(x), 'f')
'0.000000+1.414214j'
>>> format(complex(x), 'g')
'0+1.41421j'
If you want to format the real and imag parts separately you can do it yourself.
The conversion would raise a TypeError if it can't be done:
>>> complex(sympy.Symbol('x'))
Traceback (most recent call last):
TypeError: can't convert expression to float
Here's an alternative which incidentally indicates how to check whether one or both parts of a complex number are available.
>>> from sympy import *
>>> var('x')
x
>>> expr = (x+0.012345678*I)*(x-0.2346678934)*(x-(3-2.67893455*I))
>>> solve(expr)
[0.234667893400000, -0.012345678*I, 3.0 - 2.67893455*I]
>>> roots = solve(expr)
>>> for root in roots:
... r, i = root.as_real_imag()
... '%10.3f %10.3f i' % (r,i)
...
' 0.235 0.000 i'
' 0.000 -0.012 i'
' 3.000 -2.679 i'
You could check the sign of the complex part to decide whether to put a plus sign in. I would like to have been able to use the newfangled formatting but fell afoul of the bug which comes with Py3.4+ mentioned in Python TypeError: non-empty format string passed to object.__format__ for which I have no remedy.
The following checks whether the sympy object result represents a complex number and truncates the float value to 2 decimal points.
import sympy as sp
result = 0.0100503358535014*sp.I
print(result.is_complex)
print(sp.N(result,2))
True
0.01*I
Related
I am using sympy to differentiate a function in python. After differentiating the function, I would like to add in the numerical value of the variable that I differentiated with. However, using .subs() does not return a different answer. Does anyone have an idea s to what my issue is?
Code:
CA1 = CA0 * sympy.exp(-(A1*sympy.exp(-E1/(R*T)))*t)
dCa_dA12 = diff(CA1, A1)
print("No substitution:", dCa_dA12)
dCa_1 = dCa_dA12.subs(A1, theta[0])
print("Substitution:", dCa_1)
Output:
I had the same problem and was tinkering around a bit:
This works:
>>> sympify("k").evalf(subs={"k":1})
1.00000000000000
This doesn't work:
>>> sympify("k+x").evalf(subs={"k":1})
k + x
This again works:
>>> sympify("k+x").evalf(subs={"k":1, "x":2})
3.00000000000000
So it seems the substitution doesn't work if the result is not a number. Strangely, this only applies to the subs part:
>>> sympify("2/3*x")
2*x/3
>>> sympify("2/3*x").evalf()
0.666666666666667*x
This looks like a bug to me. At least, it should be documented properly.
I am trying to convert latex expression to sympy form and then solve it.
When I feed the output of the parser(or converter actually?) to solve method, it finds no solution. However, if I manually enter the parser generated expression, it finds the roots successfully. What is wrong with parse_latex ( most probably ) or solve method?
Thanks in advance. Here is the code sample you can try:
from sympy import*
from sympy.parsing.latex import*
x = Symbol("x", real=True)
sym_eqn = parse_latex("|x-2|-1")
print sym_eqn # Abs(x - 2) - 1
print type(sym_eqn) # <class 'sympy.core.add.Add'>
print type(Abs(x - 2) - 1) # <class 'sympy.core.add.Add'>
print solve(Abs(x-2)-1) # [1,3], which is ok
#print solve(sym_eqn) # NotImplementedError: solving Abs(x - 2) when the argument is not real or imaginary.
print solve(sym_eqn,x) # []
The root issue here is whether or not your symbol 'x' has an attribute "real" set to True, or not.
Consider the following two symbols:
a = Symbol('x',real=True)
b = Symbol('x')
a and b are not of the same type and in fact a==b is False.
What happens when you execute
sym_eqn = parse_latex("|x-2|-1")
is that that sym_eqn is now an expression that contains a Symbol that does not have the attribute real set to True which is required to run solve on it.
Having understood this, the question is now how to get parse_latex to return an expression that would contain a Symbol that is real?
The only way I found is to write a function that recursively traverses the expression's tree and rebuilds a copy of it such that the result is the same, except all Symbols are now real.
def rewrite_expr_real(expr):
res_list = []
if isinstance(expr,Symbol):
return Symbol(str(expr),real=True)
if not expr.args:
return expr
for a in expr.args:
res_list.append(rewrite_expr_real(a))
return expr.func(*tuple(res_list))
Now,
if you rewrite your code as follows:
sym_eqn = rewrite_expr_real(parse_latex("|x-2|-1"))
The rest of your code will work as you expect it.
Yakov's answer is on point, but I'd like to offer a code snippet that converts all symbols to "real" in a single substitution.
from sympy import symbols
expr = expr.subs((str(symbol), symbols(str(symbol), real=True))
for symbol in expr.free_symbols)
In Python, if I print different data types separated by commas, they will all act according to their __str__ (or possibly __repr__) methods, and print out a nice pretty string for me.
I have a bunch of variables like data1, data2... below, and I would love to get their total approximate size. I know that:
not all of the variables have a useful sys.getsizeof (I want to know the size stored, not the size of the container.) -Thanks to Martijn Pieters
the length of each of the printed variables is a good enough size estimate for my purposes
I'd like to avoid dealing with different data types individually. Is there any way to leverage a function like print to get the total length of data? I find it quite unlikely that something like this is not already built into Python.
>>> obj.data1 = [1, 2, 3, 4, 5]
>>> obj.data2 = {'a': 1, 'b':2, 'c':3}
>>> obj.data3 = u'have you seen my crossbow?'
>>> obj.data4 = 'trapped on the surface of a sphere'
>>> obj.data5 = 42
>>> obj.data6 = <fake a.b instance at 0x88888>
>>> print obj.data1, obj.data2, obj.data3, obj.data4, obj.data5, obj.data6
[1, 2, 3, 4, 5] {'a': 1, 'c': 3, 'b': 2} have you seen my crossbow? trapped on the surface of a sphere 42 meh
I'm looking for something like:
printlen(obj.data1, obj.data2, obj.data3, obj.data4, obj.data5, obj.data6)
109
I know most of you could write something like this, but I'm mostly asking if Python has any built-in way to do it. A great solution would show me a way to return the string that print prints in Python 2.7. (Something like print_r in PHP, which I otherwise feel is wholly inferior to Python.) I'm planning on doing this programmatically with many objects that have pre-filled variables, so no writing to a temporary file or anything like that.
Thanks!
As a side-note, this question arose from a need to calculate the approximate total size of the variables in a class that is being constructed from unknown data. If you have a way to get the total size of the non-callable items in the class (honestly, the total size would work too), that solution would be even better. I didn't make that my main question because it looks to me like Python doesn't support such a thing. If it does, hooray!
"A great solution would show me a way to return the string that print prints in Python 2.7."
This is roughly what print prints (possibly extra spaces, missing final newline):
def print_r(*args):
return " ".join((str(arg) for arg in args))
If you run in to lots of objects that aren't str-able use safer_str instead:
def safer_str(obj):
return str(obj) if hasattr(obj,"__str__") else repr(obj)
First of all, sys.getsizeof() is not the method to use to determine printed size. A python object memory footprint is a poor indicator for the number of characters required to represent a python object as a string.
You are looking for len() instead. Use a simple generator expression plus sum() to get a total:
def printlen(*args):
if not args:
return 0
return sum(len(str(arg)) for arg in args) + len(args) - 1
The comma between expressions tells print to print a space, so the total length print will write to stdout is the sum length of all string representations, plus the whitespace between the elements.
I am assuming you do not want to include the newline print writes as well.
Demo:
>>> printlen(data1, data2, data3, data4, data5, data6)
136
This should now do it correctly:
def printlen(*args):
return sum(map(len, map(str, args)))
For objects which do not support the str(obj) function. You could replace the str with a self made function or lambda:
def printlen(*args):
return sum(map(len, map(lambda x: str(x) if hasattr(x, '__str__') else '', args)))
If you want the length you can use this:
printlen = lambda *x: print(sum(len(str(i)) for i in x))
usage:
printlen(obj1, obj2, ..)
If you have an object structure and you want to know how much does it require to store it, you could also pickle/cpickle the object and use that number as a measure, and to also to store the data into database.
So, my code is like this:
def func(s,x):
return eval(s.replace('x',x)
#Example:
>> func('x**2 + 3*x',1)
4
The first argument of the function func must be a string because the function eval accepts only string or code objects. However, I'd like to use this function in a kind of calculator, where the user types for example 2 + sin(2*pi-0.15) + func(1.8*x-32,273) and gets the answer of the expression, and it's annoying always to have to write the quotes before in the expression inside func().
Is there a way to make python understands the s argument is always a string, even when it's not between quotes?
No, it is not possible. You can't intercept the Python interpreter before it parses and evaluates 1.8*x-32.
Using eval as a glorified calculator is a highly questionable idea. The user could pass in all kinds of malicious Python code. If you're going to do it, you should provide as minimal an environment as possible for the code to run in. Pass in your own globals dict containing only the variables the user is allowed to reference.
return eval(s, {'x': x})
Besides being safer, this is also a better way to substitute x into the expression.
You could have it handle both cases:
def func(s, x=0):
if isinstance(s, basestring):
# x is in the scope, so you don't need to replace the string
return eval(s)
else:
return s
And the output:
>>> from math import *
>>> func('2 + sin(2*pi-0.15) + func(1.8*x-32,273)')
-30.1494381324736
>>> func('x**2 + 3*x', 1)
4
Caution: eval can do more than just add numbers. I can type __import__('os').system('rm /your/homework.doc') and your calculator will delete your homework.
In a word: no, if I understand you.
In a few more, you can sort of get around the problem by making x be a special object. This is how the Python math library SymPy works. For example:
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> x**2+3*x
x**2 + 3*x
>>> (x**2+3*x).subs(x,1)
4
There's even a handy function to turn strings into sympy objects:
>>> from sympy import sympify, pi
>>> sympify("x**2 - sin(x)")
x**2 - sin(x)
>>> _.subs(x, pi)
pi**2
All the warnings about untrusted user input hold. [I'm too lazy to check whether or not eval or exec is used on the sympify code path, and as they say, every weapon is loaded, even the unloaded ones.]
You can write an interpreter:
import code
def readfunc(prompt):
raw = input(prompt)
if raw.count(',')!=1:
print('Bad expression: {}'.format(raw))
return ''
s, x = raw.split(',')
return '''x={}; {}'''.format(x, s)
code.interact('Calc 0.1', readfunc)
A quick no-brainer:
some_float = 1234.5678
print '%02d' % some_float # 1234
some_float = 1234.5678
print '{WHAT?}'.format(some_float) # I want 1234 here too
Note: {:.0f} is not an option, because it rounds (returns 1235 in this example).
format(..., int(some_float)) is exactly the thing I'm trying to avoid, please don't suggest that.
It's worth mentioning the built in behavior for how floats are rendered using the raw format strings. If you know in advance where your fractional part lies with respect to 0.5 you can leverage the format string you originally attempted but discovered it fell short from rounding side effects "{:0.0f}". Check out the following examples...
>>> "{:0.0f}".format(1.999)
'2'
>>> "{:0.0f}".format(1.53)
'2'
>>> "{:0.0f}".format(1.500)
'2'
>>> "{:0.0f}".format(1.33)
'1'
>>> "{:0.0f}".format(0.501)
'1'
>>> "{:0.0f}".format(0.5)
'0'
>>> "{:0.0f}".format(0.1)
'0'
>>> "{:0.0f}".format(0.001)
'0'
As you can see there's rounding behavior behind the scenes. In my case where I had a database converting ints to floats I knew I was dealing with a non fractional part in advance and only wanted to render in an html template the int portion of the float as a workaround. Of course if you don't know in advance the fractional part you would need to carry out a truncation operation of some sort first on the float.
It's possible to extend the standard string formatting language by extending the class string.Formatter:
class MyFormatter(Formatter):
def format_field(self, value, format_spec):
if format_spec == 't': # Truncate and render as int
return str(int(value))
return super(MyFormatter, self).format_field(value, format_spec)
MyFormatter().format("{0} {1:t}", "Hello", 4.567) # returns "Hello 4"
This works:
from math import trunc
some_float = 1234.5678
print '{:d}'.format(trunc(some_float))
=> 1234
Or just do this, for that matter:
print trunc(some_float)
=> 1234
I think it's an acceptable answer, it avoids the conversion to int. Notice that in this snippet: '%02d' % some_float an implicit conversion to int is happening, you can't avoid some sort of conversion for printing in the desired format.
This will work too:
some_float = 1234.5678
f = lambda x: str(x)[:str(x).find('.')]
print '{}'.format(f(some_float))
=> 1234
After doing a %timeit test it looks like this is a bit faster than the trunc method.