How to perform a range on a Theano's TensorVariable? - python

How to perform a range on a Theano's TensorVariable?
Example:
import theano.tensor as T
from theano import function
constant = T.dscalar('constant')
n_iters = T.dscalar('n_iters')
start = T.dscalar('start')
result = start
for iter in range(n_iters):
result = start + constant
f = function([start, constant, n_iters], result)
print('f(0,2,5): {0}'.format(f(1,2)))
returns the error:
Traceback (most recent call last):
File "test_theano.py", line 9, in <module>
for iter in range(n_iters):
TypeError: range() integer end argument expected, got TensorVariable.
What is the correct way to use a range on a Theano's TensorVariable?

It's not clear what this code is attempting to do because even if the loop worked, it wouldn't compute anything useful: result will always equal the sum of start and constant irrespective of the number of iterations.
I'll assume that the intention was to compute result like this:
for iter in range(n_iters):
result = result + constant
The problem is that you're mixing symbolic, delayed execution, Theano operations with non-symbolic, immediately executed, Python operations.
range is a Python function that expects a Python integer parameter but you're providing a Theano symbolic value (n_iters, which has a double type instead of an integer type but let's assume it's actually an iscalar instead of a dscalar). As far as Python is concerned all Theano symbolic tensors are just objects: instances of a class type somewhere within the Theano library; they are most assuredly not integers. Even if you squint and try to pretend a Theano iscalar looks like a Python integer, it still doesn't work because Python operations execute immediately which means n_iters needs to have a value immediately. Theano on the other hand doesn't have a value for any iscalar until one is provided by calling a compiled Theano function (or via eval).
To create a symbolic range, you can use theano.tensor.arange which operates just like NumPy's arange, but symbolically.
Example:
import theano.tensor as T
from theano import function
my_range_max = T.iscalar('my_range_max')
my_range = T.arange(my_range_max)
f = function([my_range_max], my_range)
print('f(10): {0}'.format(f(10)))
outputs:
f(10): [0 1 2 3 4 5 6 7 8 9]
By making n_iters a symbolic variable you are implicitly saying "I don't know how many iterations there need to be in this loop until a value is provided for n_iters later". That being the case, you must use a symbolic loop instead of a Python for loop. In the latter case you must tell Python how many times to iterate now, you can't delay that decision until a value is provided for n_iters later. To solve this you need to switch to a symbolic loop, which is provided by Theano's scan operator.
Here's the code changed to use scan (as well as the other assumed changes).
import theano
import theano.tensor as T
from theano import function
constant = T.dscalar('constant')
n_iters = T.iscalar('n_iters')
start = T.dscalar('start')
results, _ = theano.scan(lambda result, constant: result + constant,
outputs_info=[start], non_sequences=[constant], n_steps=n_iters)
f = function([start, constant, n_iters], results[-1])
print('f(0,2,5): {0}'.format(f(0, 2, 5)))

Related

How to repeat a function for a list of inputs?

I'm trying to use the following function of QuTip library:
coherent_dm(N=10, alpha = c, offset=0, method='operator')
It's output is a matrix and it's input is a complex number "c", however I want to get the matrices for a list of multiple "c" numbers, but if I define "c" as:
t = np.linspace(0,2*np.pi,100)
c = 2*np.exp(-t*1j) + 0.1*10*(1 - np.exp(-t*1j))
And run the code it gives me "dimension mismatch" error. In this case I tried to run a list of a 100 complex numbers as input "c" expecting an output of a 100 matrices. Any ideas on how to solve this problem would be appreciated.
coherent_dm returns a qutip.Qobj instance. This is a specialized object that fulfills the __array__ interface, but is not actually a numpy array. Internally, it appears to contain a sparse matrix. That means that you can not readily make coherent_dm return more than one matrix at a time, or even concatenate the results of multiple calls into a single array.
Your best bet is therefore probably to use a list comprehension:
result = [coherent_dm(N=10, alpha=i, offset=0, method='operator') for i in c]

scipy.ndimage.generic_filter1d not working

I am trying to use scipy.ndimage.generic_filter1d for the first time, but it's not going well. Here's what I'm trying
import numpy as np
from scipy.ndimage import generic_filter1d
def test(x):
return x.sum()
im_cube = np.zeros((100,100,100))
calc = generic_filter1d(im_cube, test, filter_size=5, axis=2)
But I get this error:
TypeError: test() takes 1 positional argument but 2 were given
I'm using scipy 1.4.1 What am I doing wrong?
For the function, I also tried np.mean but then I got this:
TypeError: only integer scalar arrays can be converted to a scalar index
According to the documentation, the callback accepts two arguments: a reference to the input line, and a reference to the output line. It does not return the output, but rather modifies the provided buffer in-place.
If you want to implement a rolling sum filter, you will need to do that somewhat manually. For example:
def test(x, out)
out[:] = np.lib.stride_tricks.as_strided(x, strides=x.strides * 2, shape=(5, x.size - 4)).sum(axis=0)
To make it a mean, add / 5 at the end.
The purpose of genetic_filter1d is to format the edges and run the outer loop. It does not actually implement the rolling filter for you. You are still required to implement the entire inner loop yourself.

Function integration returns “only length-1 arrays can be converted to Python scalars”

I'm trying to integrate a function into a given range that shows the flow of particles in a zero-angle (theta) direction as a function of the energy E of the particles. I've tried several ways and got different errors but there are two that persist at the end. My knowledge of Python is limited, I try to learn new ways of doing stuff as I need them but I've been around this function for days with no success.
My function at the moment looks like this:
from numpy import radians, cos, arange
from scipy.integrate import quad
def integral(self):
theta=0
E = arange(1, 5000, 1)
costh = cos(radians(theta))
a = 18 / (E * costh + 145)
b = (E + 2.7 / costh)**-2.7
c = (E + 5) / (E + 5 / costh)
return a*b*c*1**4
A = quad(integral, 500, 1000)
Applying "quad" to the function like this returns:
TypeError: only length-1 arrays can be converted to Python scalars
If I don't put "self" as argument in the funtion, it returns:
TypeError: integral() takes 0 positional arguments but 1 was given
Has someone an idea on how to bypass this?
integral must have one of the signatures described in the scipy documentation. In your case, a function taking a double as argument and returning a double seems appropriate.
self is only used for member functions of a class. It does not make sense outside a class definition. Replace that with a simple name, say x that will be the input argument of the function to integrate.
The function must return a double. Since E is an array and you seem to make calculations with it, then the computed return value is likely to be an array too. It must be a scalar. Fix that and it will work. When you replace your function with something like:
def integral(x):
return x * x
then it works. This is not what you need, of course, but this is the kind of arguments and return values that are required for quad() to work.
You may want to look here for an example on how quad() is being used.
Some recommendations:
use four spaces for indentation (not 5 as in the example)
parentheses around the result are not required. Remove for more clarity.

Python sum() has a different result after importing numpy

I came across this problem by Jake VanderPlas and I am not sure if my understanding of why the result differs after importing the numpy module is entirely correct.
>>print(sum(range(5),-1)
>> 9
>> from numpy import *
>> print(sum(range(5),-1))
>> 10
It seems like in the first scenario the sum function calculates the sum over the iterable and then subtracts the second args value from the sum.
In the second scenario, after importing numpy, the behavior of the function seems to have modified as the second arg is used to specify the axis along which the sum should be performed.
Exercise number (24)
Source - http://www.labri.fr/perso/nrougier/teaching/numpy.100/index.html
"the behavior of the function seems to have modified as the second arg is used to specify the axis along which the sum should be performed."
You have basically answered your own question!
It is not technically correct to say that the behavior of the function has been modified. from numpy import * results in "shadowing" the builtin sum function with the numpy sum function, so when you use the name sum, Python finds the numpy version instead of the builtin version (see #godaygo's answer for more details). These are different functions, with different arguments. It is generally a bad idea to use from somelib import *, for exactly this reason. Instead, use import numpy as np, and then use np.sum when you want the numpy function, and plain sum when you want the Python builtin function.
Only to add my 5 pedantic coins to #Warren Weckesser answer. Really from numpy import * does not overwrite the builtins sum function, it only shadows __builtins__.sum, because from ... import * statement binds all names defined in the imported module, except those beginning with an underscore, to your current global namespace. And according to Python's name resolution rule (unofficialy LEGB rule), the global namespace is looked up before __builtins__ namespace. So if Python finds desired name, in your case sum, it returns you the binded object and does not look further.
EDIT:
To show you what is going on:
In[1]: print(sum, ' from ', sum.__module__) # here you see the standard `sum` function
Out[1]: <built-in function sum> from builtins
In[2]: from numpy import * # from here it is shadowed
print(sum, ' from ', sum.__module__)
Out[2]: <function sum at 0x00000229B30E2730> from numpy.core.fromnumeric
In[3]: del sum # here you restore things back
print(sum, ' from ', sum.__module__)
Out[3]: <built-in function sum> from builtins
First note: del does not delete objects, it is a task of garbage collector, it only "dereference" the name-bindings and delete names from current namespace.
Second note: the signature of built-in sum function is sum(iterable[, start]):
Sums start and the items of an iterable from left to right and returns the total. start defaults to 0. The iterable‘s items are normally numbers, and the start value is not allowed to be a string.
I your case print(sum(range(5),-1) for built-in sum summation starts with -1. So technically, your phrase the sum over the iterable and then subtracts the second args value from the sum isn't correct. For numbers it's really does not matter to start with or add/subtract later. But for lists it does (silly example only to show the idea):
In[1]: sum([[1], [2], [3]], [4])
Out[1]: [4, 1, 2, 3] # not [1, 2, 3, 4]
Hope this will clarify your thoughts :)

Python fsolve ValueError

Why does the following code return a ValueError?
from scipy.optimize import fsolve
import numpy as np
def f(p,a=0):
x,y = p
return (np.dot(x,y)-a,np.outer(x,y)-np.ones((3,3)),x+y-np.array([1,2,3]))
x,y = fsolve(f,(np.ones(3),np.ones(3)),9)
ValueError: setting an array element with a sequence.
The basic problem here is that your function f does not satisfy the criteria required for fsolve to work. These criteria are described in the documentation - although arguably not very clearly.
The particular things that you need to be aware of are:
the input to the function that will be solved for must be an n-dimensional vector (referred to in the docs as ndarray), such that the value of x you want is the solution to f(x, *args) = 0.
the output of f must be the same shape as the x input to f.
Currently, your function takes a 2 member tuple of 1x3-arrays (in p) and a fixed scalar offset (in a). It returns a 3 member tuple of types (scalar,3x3 array, 1x3 array)
As you can see, neither condition 1 nor 2 is met.
It is hard to advise you on exactly how to fix this without being exactly sure of the equation you are trying to solve. It seems you are trying to solve some particular equation f(x,y,a) = 0 for x and y with x0 = (1,1,1) and y0 = (1,1,1) and a = 9 as a fixed value. You might be able to do this by passing in x and y concatenated (e.g. pass in p0 = (1,1,1,1,1,1) and in the function use x=p[:3] and y = p[3:] but then you must modify your function to output x and y concatenated into a 6-dimensional vector similarly. This depends on the exact function your are solving for and I can't work this out from the output of your existing f (i.e based on a dot product, outer product and sum based tuple).
Note that arguments that you don't pass in the vector (e.g. a in your case) will be treated as fixed values and won't be varied as part of the optimisation or returned as part of any solution.
Note for those who like the full story...
As the docs say:
fsolve is a wrapper around MINPACK’s hybrd and hybrj algorithms.
If we look at the MINPACK hybrd documentation, the conditions for the input and output vectors are more clearly stated. See the relevant bits below (I've cut some stuff out for clarity - indicated with ... - and added the comment to show that the input and output must be the same shape - indicated with <--)
1 Purpose.
The purpose of HYBRD is to find a zero of a system of N non-
linear functions in N variables by a modification of the Powell
hybrid method. The user must provide a subroutine which calcu-
lates the functions. The Jacobian is then calculated by a for-
ward-difference approximation.
2 Subroutine and type statements.
SUBROUTINE HYBRD(FCN,N,X, ...
...
FCN is the name of the user-supplied subroutine which calculates
the functions. FCN must be declared in an EXTERNAL statement
in the user calling program, and should be written as follows.
SUBROUTINE FCN(N,X,FVEC,IFLAG)
INTEGER N,IFLAG
DOUBLE PRECISION X(N),FVEC(N) <-- input X is an array length N, so is output FVEC
----------
CALCULATE THE FUNCTIONS AT X AND
RETURN THIS VECTOR IN FVEC.
----------
RETURN
END
N is a positive integer input variable set to the number of
functions and variables.
X is an array of length N. On input X must contain an initial
estimate of the solution vector. On output X contains the
final estimate of the solution vector.

Categories

Resources