Weird behavior with class attribute, __iadd__ (+=) and numpy.random.randn() - python

I have been modelling a stochastic process with Python and Numpy and witnessing weird behavior with the following code:
import numpy as np
class Example( object ):
def __init__( self ):
self.x = 0
def add_random( self ):
self.x += np.random.randn(1)
return self.x
if __name__ == '__main__':
example = Example()
state = []
for x in range(10):
state.append( example.add_random() )
print state
This will return an array of 10 identical random numbers as opposed to 10 different random numbers as expected. Eliminating the object.__iadd__ operator and/or replacing np.random.randn(.) with a constant will solve the issue. Anybody has an idea what is the root of this?

np.random.randn(1) returns an array containing a single element:
In [27]: np.random.randn(1)
Out[27]: array([-1.90409169])
The first time this line is executed
self.x += np.random.randn(1)
self.x--initially a Python integer--is replaced by a numpy array. Subsequent execution of that line modifies x in-place, because that's how numpy arrays implement in-place addition. So return self.x always returns the same array. Thus the list that you create in the main section is a list containing the same object repeated 10 times.
One way to fix this is to use np.random.randn() instead of np.random.randn(1). np.random.randn() returns a scalar, so the assignment self.x += np.random.randn(1) creates a new self.x object each time it is executed.

You are returning the array self.x by reference, so you have 10 pointers to the same array. Every time the array is modified, all ten pointers point to the same modified version.
If you want to return separate copies of the array each time, you could return self.x.copy() in the add_random function.
An alternative fix would be to replace np.random.rand(1) with np.random.rand() so self.x would remain a scalar rather than being up-cast to an array.

Related

In an instance of a class, can you use a value returned from a one method, as a parameter for calling another method

class A:
def __init__(self, matrix=[]):
self.matrix = matrix
def dimension(self):
return len(self.matrix), len(self.matrix[0])
def reduce_matrix(self, i, j):
temp = self.matrix[:i-1] + self.matrix[i:]
M = A([row[:j-1] + row[j:] for row in temp])
return M
def determinant(self):
(nrows, ncols) = self.dimension()
if nrows != ncols:
return ("Cannot find determinant of non-square matrix.")
elif nrows == 1:
return self.matrix[0][0]
else:
M = A(sum([ ((-1)**j) * self.matrix[0][j] * self.reduce_matrix(1,
j+1).determinant() for j in range(ncols) ]))
return M
Hello, I just started OOP so I have a question regarding using the returned value of a method in place of the "instance name" that is passed as "self" for some other method.
I included the rest of the code that just makes the calculations for a matrix problem, but I'm only focusing on the "self.reduce_matrix(1, j+1)).determinant()" bit of it. I need to take a matrix (which is a list of lists ex. [[1,2,3],[4,5,6]] ), and perform the "reduce_matrix" method 1 time per column in the matrix, and each time, the "determinant(self)" method passes in the value returned from the other method. When I run it, it says that "list object has no attribute "determinant"" because I can't pass in "self" to the determinant method like I usually do --> "self.determinant(self)"
Any suggestions will be very appreciated
In reduce_matrix:
create M as M = A([row[:j-1] + row[j:] for row in temp])
do not return M.matrix but M itself.
That said, numpy is there for all kind of matrix operations and more.

Python fsolve tempering with object

I wrote a script in Python that finds the zero of a fairly complicated function using fsolve. The way it works is as follows. There is a class that simply stores the parameter of the function. The class has an evaluate method that returns a value based on the stored parameter and another method (inversion) that finds the parameter at which the function takes the supplied output.
The inversion method updates the parameter of the function at each iteration and it keeps on doing so until the mismatch between the value returned by the evaluate method and the supplied value is zero.
The issue that I am having is that while the value returned by the inversion method is correct, the parameter, that is part of the object, is always 0 after the inversion method terminates. Oddly enough, this issue disappears if I use root instead of fsolve. As far as I know, fsolve is just a wrapper for root with some settings on the solver algorithm and some other things enforced.
Is this a known problem with fsolve or am I doing something dumb here? The script below demonstrates the issue I am having on the sine function.
from scipy.optimize import fsolve, root
from math import sin, pi
class invertSin(object):
def __init__(self,x):
self.x = x
def evaluate(self):
return sin(self.x)
def arcsin_fsolve(self,y):
def errorfunc(xnew):
self.x = xnew
return self.evaluate() - y
soln = fsolve(errorfunc, 0.1)
return soln
def arcsin_root(self,y):
def errorfunc(xnew):
self.x = xnew
return self.evaluate() - y
soln = root(errorfunc, 0.1, method = 'anderson')
return soln
myobject = invertSin(pi/2)
x0 = myobject.arcsin_fsolve(0.5) #find x s.t. sin(x) = 0.5 using fsolve
print(x0) #this prints pi/6
x0obj = myobject.x
print(x0obj) #this always prints 0 no matter which function I invert
myobject2 = invertSin(pi/2)
x1 = myobject2.arcsin_root(0.5) #find x s.t. sin(x) = 0.5 using root
print(x1) #this prints pi/6
x1obj = myobject2.x
print(x1obj) #this prints pi/6
If you add print statements for xnew in the errorfunc then you will see that fsolve works with a list (of one element). This means that the function is re-interpreted that way, not the original function. Somehow the type information is lost after exiting the solver so that then the address/reference to that list is interpreted as floating point data, which gives the wrong value.
Setting self.x = xnew[0] there restores the desired behavior.

instance variable not modified in a for loop

I have a class with instance variables which I want to modify in a loop using a class method, simplified version of what I'm doing:
class Example:
def __init__(self,x,z):
self.x=x
self.z=z
def run(self,y):
temp_list=[self.x, self.z]
for ind,item in enumerate(temp_list):
temp_list[ind] = temp_list[ind]+y
print (self.x, self.z)
ex = Example(5,6)
ex.run(5)
The output I get is [5,6] instead of the desired [10,11].
I was wondering if anyone could point me to an explanation as to why this happens?
In run(), you create a list of 2 items, the value self.x and self.z. Next, you iterate over that list, and modify each value by adding y to it.
After the for-loop, temp_list will be [10, 11], but you have not modified self.x or self.y in any way.
Hence, the print() call will print the unmodified self.x and self.y values, being 5 and 6 in your example.
If you don't actually write self.x = ..., then you can generally assume that self.x will not be modified. When you write temp_list[ind] + y and store it in temp_list[ind], you're updating the list with a new value, which has no bearing on any values that other variables happen to hold (including your object's x variable).
To get the desired result with code similar to yours, you could do something like this:
class Example:
def __init__(self,x,z):
self.list=[x, z]
def run(self,y):
for ind,item in enumerate(self.list):
self.list[ind] = self.list[ind]+y
print (self.list)
ex = Example(5,6)
ex.run(5)
This would create a self.list item in your init definition that would then be used to iterate over the initial values and add your y value to it. The main error you had was printing an unaltered list (but you were on the right track!)
Hope this helps!
You can use, the example under.
class Example:
def __init__(self, x, z):
self.x = x
self.z = z
def run(self,y):
# Put your init arguments into the array
result = [self.x, self.z]
# Modify your init arguments
for x in range(len(result)):
result[x] += y
# Return the array with new values
return result
ex = Example(5, 6)
print(ex.run(5))
Maybe the link would be helpful for you, learn for loop in python

Python list assignation

I've got this code
class coordenates:
x = 0
y = 0
coor = coordenates()
coor.x=0
coor.y=0
list = []
list.append(coor)
list.append(coor)
Now, the problem is that when I update
list[0].x=100
it is also modifing list[1].x somehow!
print str(list[0].x)
>> 100
print str(list[1].x)
>> 100
which must remain in 0 since I haven't update it. Is append() creating the same object pointing in the same position in memory in positions 0 and 1? why creating 2 different objects solves the problem?
In your current code, x and y are class-level attributes. I suspect that you want them to be instance-level attributes. If so, set them in __init__():
class Coordinates:
def __init__(self):
self.x = 0
self.y = 0
More important, if you append the same coor to the list twice, any mutation of the coor will be reflected in "both" coordinates (because the list is just holding a reference to the same underlying coordinate in both positions of the list). Maybe you want something like this instead, where you create two independent coordinate instances?
list = []
list.append(Coordinates())
list.append(Coordinates())
You can see an illustration of your problem with this code:
c = Coordinates()
cs = []
cs.append(c)
cs.append(c)
for c in cs:
print id(c) # Both elements of the list refer to the same object.

Overloading Addition with Python Vectors

As you can see i've created a function that allows me to create and alter a vector. Now i'm trying to add vectors together using def __add__(self, y). However, i'm getting an IndexError. Is there anything obvious you can see wrong with my code because I'm getting stuck.
def __add__(self, y):
self.vector = []
for j in range(len(self.vector)):
self.vector.append(self.vector[j] + y.self.vector[j])
return Vec(self.vector)
You've got a few issues in your code:
When you do self.vector = [], you are basically clearing your vector. That's makes it impossible to add it to the other vector.
When you do return Vec(self.vector), you're passing a list to the Vec constructor - but you've defined it to take a vector length.
You can only add vectors that are the same length as each other - you don't check that that is the case.
The following is a possible implementation of __add__ with those problems addressed:
def __add__(self, y):
size = len(self.vector)
if size != len(y.vector):
raise ValueError("Vectors must be the same size.")
result = Vec(size)
for j in range(size):
result.vector[j] = self.vector[j] + y.vector[j]
return result

Categories