Problem with mpmath under Python 3.8, but OK under 2.7 - python

The following lttle program fails using Python 3.8, but is OK under 2.7:
from mpmath import mpf, nsum
def z(n):
x = [mpf(1) for k in range(1,n)]
return 99
print (nsum(z, [2,2]))
The code looks odd, as it is pared down from a rather larger program. I can't pare it down any further. This can be confirmed easily using the interactive shell at https://www.python.org/shell/
The error report is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/site-packages/mpmath/calculus/extrapolation.py", line 1698, in nsum
return +g()
File "/usr/lib/python3.8/site-packages/mpmath/calculus/extrapolation.py", line 1745, in <lambda>
return False, lambda: f(*([0]*len(intervals)))
File "/usr/lib/python3.8/site-packages/mpmath/calculus/extrapolation.py", line 1777, in g
s += f(*args)
File "<stdin>", line 2, in z
TypeError: 'mpf' object cannot be interpreted as an integer
Have I missed something obvious?

nsum passes n as mpf to z, but range expects:
...int or any object that implements the __index__ special method.
So you could cast n explicitly to int, e.g.:
x = [mpf(1) for k in range(1, int(n))]

Related

Python all short-circuiting with None element

I read everywhere that Python all and any functions support short-circuiting.
However:
a = None
all((a is not None, a + 1 > 2))
Throws the following error:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-4-6e28870e65c8>", line 1, in <module>
all((a is not None, a + 1 > 2))
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
I would have expected the code not to evaluate a + 1 > 2 since a is None.
Why is this happening? Is this because each term is evaluated before the call? Am I forced to use the and operator as in a is not None and a + 1 > 2?
The tuple (a is not None, a + 1 > 2) needs to be created before all() can be called. It is during the creation of the tuple that the TypeError is raised. all() doesn't even get a chance to run.
If you want to see all's short circuiting in action, pass it a generator expression. For example:
>>> all('foobaR'[i].islower() for i in range(7))
False
>>> all('foobar'[i].islower() for i in range(7))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
IndexError: string index out of range
In the first run all stops when it hits the 'R'.islower() case since that's False. In the second run it keeps going until i == 6, which triggers an index error.
Am I forced to use the and operator as in a is not None and a + 1 > 2?
I wouldn't say "forced"—I'm sure there other convoluted options—but yes, that's the obvious and idiomatic way to write it.

z3.parse_smt2_string fails on int2bv

When I use parse_smt2_string on the example string from the docs, it works correctly. However, the parsing fails on int2bv. How can I diagnose this?
>>> import z3
>>> z3.parse_smt2_string('(declare-const x Int) (assert (> x 0)) (assert (< x 10))')
[x > 0, x < 10]
>>> z3.parse_smt2_string('((_ int2bv 1) 1)')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/elliot/miniconda3/envs/angr/lib/python3.6/site-packages/z3_solver-4.8.7.0-py3.6-linux-x86_64.egg/z3/z3.py", line 8601, in parse_smt2_string
return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx)
File "/home/elliot/miniconda3/envs/angr/lib/python3.6/site-packages/z3_solver-4.8.7.0-py3.6-linux-x86_64.egg/z3/z3core.py", line 3222, in Z3_parse_smtlib2_string
_elems.Check(a0)
File "/home/elliot/miniconda3/envs/angr/lib/python3.6/site-packages/z3_solver-4.8.7.0-py3.6-linux-x86_64.egg/z3/z3core.py", line 1381, in Check
raise self.Exception(self.get_error_message(ctx, err))
z3.z3types.Z3Exception: b'(error "line 1 column 2: invalid command, symbol expected")\n'
This has nothing to do with int2bv, but rather due to the fact that you've not provided a line that is valid SMTLib at the top-level. The following, for instance, works:
>>> z3.parse_smt2_string('(assert (= #b1 ((_ int2bv 1) 1)))')
[1 == int2bv(1)]
At the top-level, you can have declarations, assertions, or general SMTLib commands, not a standalone expression.

Why does the timeit() function return different results when handed a function vs a string expression?

I'm trying out the python timeit function in my Python REPL. It can time small pieces of code in two ways: Either as a callable, or as a quoted expression. I'd like to know why the following code produces different timing results.
>>> import timeit
>>> timeit.timeit("lambda *args: None")
0.058281898498535156
>>> timeit.timeit(lambda *args: None)
0.0947730541229248
>>>
My intuition tells me that there should be more 'overhead' associated with the quoted string variant because it requires interpretation, but this does not appear to be the case. But apparently my intuition is mistaken..
Here's another code snippet. There does not appear a huge time difference between invoking the callable function vs. timing the quoted function statement:
>>> def costly_func():
... return list(map(lambda x: x^2, range(10)))
...
>>> import timeit
>>> timeit.timeit(costly_func)
2.421797037124634
>>> timeit.timeit("list(map(lambda x: x^2, range(10)))")
2.3588619232177734
Observe:
>>> def costly():
... return list(map(str, list(range(1_000_000))))
...
>>> timeit.timeit(costly, number=100)
30.65105245400082
>>> timeit.timeit('costly', number=1_000_000_000, globals=globals())
27.45540758000061
Look at the number argument. It took 30 seconds to execute the function costly 100 times. It took almost 30 seconds to execute the expression costly 1'000'000'000 (!) times.
Why? Because the second code does not execute the function costly! The only thing it executes is the expression costly: notice the lack of parentheses, which means it's not a function call. The expression costly is basically a no-op (well, it just requires checking whether the name "costly" exists in the current scope, that's all), that's why it's so fast, and if Python was smart enough to optimise it away, the execution of the expression costly (not costly()!) would be instantaneous!
In your case, saying lambda *args: None is simply defining an anonymous function, right? When you execute this exact code, a new function is created, but not executed (in order to do that, you should call it: (lambda *args: None)()).
So, timing the string "lambda *args: None" with timeit.timeit("lambda *args: None") basically tests how fast Python can spit out new anonymous functions.
Timing the function itself with timeit.timeit(lambda *args: None) tests how fast Python can execute an existing function.
Spitting out newly created functions is a piece of cake, while actually running them can be really hard.
Take this code for example:
def Ackermann(m, n):
if m == 0:
return n + 1
if m > 0:
if n == 0:
return Ackermann(m - 1, 1)
elif n > 0:
return Ackermann(m - 1, Ackermann(m, n - 1))
If you put that exact code in a string and timeit it, you'll get something like this:
>>> code = """def Ackermann(m, n):
... if m == 0:
... return 0
... if m > 0:
... if n == 0:
... return Ackermann(m - 1, 1)
... elif n > 0:
... return Ackermann(m - 1, Ackermann(m, n - 1))"""
>>> timeit.timeit(code, number=1_000_000)
0.10481472999890684
Now try to timeit the function itself:
>>> timeit.timeit(lambda : Ackermann(6, 4), number=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/timeit.py", line 232, in timeit
return Timer(stmt, setup, timer, globals).timeit(number)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/timeit.py", line 176, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
File "<stdin>", line 1, in <lambda>
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
[Previous line repeated 1 more time]
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
[Previous line repeated 983 more times]
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 2, in Ackermann
RecursionError: maximum recursion depth exceeded in comparison
See - you can't even run that! Actually, probably nobody can since it's so much recursion!
Why did the first call succeed, though? Because it didn't execute anything, it just spit out a lot of new functions and got rid of all of them shortly after.

TypeError: 'int' object is not callable for a recursive function

a = 3
def f(x):
x = (x**3-4*x)/(3(x**2)-4)
return x
while True:
print(a)
a = f(a)
I'm getting a type error here, and I'm not sure why. I'm trying to run this recursive function, is there any way to fix this?
You need a * operator after your parentheses. Multiplication is only implied in mathematical notation in this context, in Python it looks like you're trying to call a function.
3(x**2)
So it would be
3*(x**2)
For example
>>> 3(5*2)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
3(5*2)
TypeError: 'int' object is not callable
>>> 3*(5*2)
30

TypeError: return arrays must be of ArrayType for a function that uses only floats

This one really stumps me. I have a function that calculates the weight of a word, I've confirmed that both a and b local variables are of type float:
def word_weight(term):
a = term_freq(term)
print a, type(a)
b = idf(term)
print b, type(b)
return a*log(b,2)
running word_weight("the") logs:
0.0208837518791 <type 'float'>
6.04987801572 <type 'float'>
Traceback (most recent call last):
File "summary.py", line 59, in <module>
print word_weight("the")
File "summary.py", line 43, in word_weight
return a*log(b,2)
TypeError: return arrays must be of ArrayType
why?
You are using numpy.log function here, its second argument is not base but out array:
>>> import numpy as np
>>> np.log(1.1, 2)
Traceback (most recent call last):
File "<ipython-input-5-4d17df635b06>", line 1, in <module>
np.log(1.1, 2)
TypeError: return arrays must be of ArrayType
You can now either use numpy.math.log or Python's math.log:
>>> np.math.log(1.1, 2)
0.13750352374993502
>>> import math
>>> math.log(1.1, 2) #This will return a float object not Numpy's scalar value
0.13750352374993502
Or if you're dealing only with base 2 then as #WarrenWeckesser suggested you can use numpy.log2:

Categories

Resources