Overloading Addition with Python Vectors - python

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

Related

How to improve my implementation of an arithmetic neutral element (identity) so that it works with numpy.around?

Context
So for a project I was writing some Monte Carlo code and I wanted to support both 2D coordinates and 3D coordinates. The obvious solutions were to implement either 2D and 3D versions of certain functions or to have some 'if' checking in the algorithm itself. I wanted a more elegant solution where I could just work with one algorithm capable of handling both situations. The idea I came up with was to work with some kind of neutral element 'I' for the optional third coordinate (z-direction). It's usage is as follows: if no explicit z value is provided it defaults to I. In any case the z value is effectively used in the calculations but has no effect if z = I.
For example: let a be any number then a + I = I + a = a. Likewise a x I = I x a = a
For addition and multiplication these are I = 0 and respectively I = 1. It is immediately clear that any numerical value for I will not work. For example if I have a cost function of the form xyz + (x +y +x)^2.
Implementation
Luckily, programmatically we are not constrained by mathematics to implement something like that and here's my attempt:
class NeutralElement:
def __add__(self, other):
return other
def __sub__(self, other):
return other
def __mul__(self, other):
return other
def __truediv__(self, other):
return other
def __pow__(self, other):
return self
def __radd__(self, other):
return other
def __rsub__(self, other):
return other
def __rmul__(self, other):
return other
def __rtruediv__(self, other):
return other
def __bool__(self):
return True
def __getitem__(self, index):
return self
def __str__(self):
return 'I'
def __repr__(self):
return 'I'
Usage is simple: n = NeutralElement() and you can then use n in whatever equation you want. The above implementation works well in the sense that the Monte Carlo algorithm finishes without problems and manages to give meaningful results. I can even construct a Numpy array of it and use it. Though it's not compatible with everything. Calling np.around on an array of it gives an error about '_rint' not implemented. Though I did manage to get it to work with round() and ndarray.round(). (Not reflected in the code above.)
Question
My question now is if there's anything I can do to improve compatibility with other functions or just improve this implementation itself. Also welcome are better alternative solutions to the problem described above.
After some feedback I've attempted to narrow down the scope of my question. I would like to modify the above class so that it returns a Numpy array of strings ['I', 'I', ..., 'I'] when numpy.around is used on a Numpy array of NeutralElements

Vector multiplication python

Hello im learning python and i get class topic.
I recived a error message like this:
"TypeError: __init__() missing 1 required positional argument: 'y'"
this is my code from shell:
class Vektor():
""" Bu bir vektör sınıfıdır"""
def __init__(self,x,y):
self.x = x
self.y = y
def boyu(self):
boy = (self.x**2+self.y**2)**0.5
return boy
def __repr__(self):
return ("%di + %dy" %(self.x, self.y))
def __sub__(self,digeri):
return Vektor(self.x - digeri.x, self.y - digeri.y)
def __add__(self,digeri):
return Vektor(self.x + digeri.x, self.y + digeri.y)
def __eq__(self,digeri):
if self.boyu() == digeri.boyu(): return True
def __mul__(self,digeri):
self.x = Vektor(self.x + digeri.x)
self.y = Vektor(self.y + digeri.y)
return Vektor(self.x*digeri.x,self.y*digeri.y)
When i try to create a C = A*B like this i get error:
TypeError: init() missing 1 required positional argument: 'y'
Im already thank you and i want to remind im a newbite in programming :))
How many arguments does Vektor.__init__ require? Ignoring self, it's two - x and y.
When you wrote return Vektor(self.x*digeri.x,self.y*digeri.y), you passed two arguments, so this works.
When you wrote self.x = Vektor(self.x + digeri.x), this doesn't work, because you don't pass a second argument for the y value.
When Python gave you the error, it should have included a line number, which is supposed to show where the error occurred. You didn't include that, but it was this line, wasn't it?
Since Vektor is supposed to contain two scalars and not sometimes replace them with two vectors, you could just write
self.x = self.x + digeri.x # still not a vector
self.y = self.y + digeri.y # also not a vector
but the more important lesson is to read the error message carefully. Everything you needed was there.
A note on operator semantics: since you wouldn't normally expect an expression like x = v * w to modify x, you shouldn't be mutating self inside the operator function anyway.
You return the resultant vector, which is enough. I showed you how to fix the syntax of those two lines, but you should really just remove them entirely.
And another note on vectors: overloading * isn't such an obvious win as it is for a scalar numeric type, because vectors usually have more than one possible type of product.
In __mul__ you do for some reason:
self.x = Vektor(self.x + digeri.x)
which is calling Vektor.__init__ providing only the positional argument x, with the value self.x + digeri.x, but nothing for y, thus the error.
Also this attempts to change the attribute x into an object from Vektor itself, I can't imagine that this is somehow what you want.
To me it is not clear what the 2 lines before the return statement in your __mul__ are supposed to do. Also both lines will produce the error you see.
Should your __mul__ be the dot product? If so, try:
return self.x*digeri.x + self.y*digeri.y
Another simplification to your class could be to allow iteration on your coords, like:
#property
def coords(self):
return self.x, self.y
def __iter__(self):
return self.coords.__iter__()
Then your dot product might just look like:
def dot(self, w):
"""
The dot product of self and other vector w.
"""
return sum([xi_s * xi_w for xi_s, xi_w in zip(self, w)])
There is VecPy, a very simple example class that does this kind of things. Maybe having a look can give you some more ideas.
The error is due to
self.x = Vektor(self.x + digeri.x)
When we call Vector like the way you write the syntax, it is thinking that you want to initialize it and it is expecting two inputs. Just get rid of the first two lines of mul function should fix the problem.

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.

How do I find the dot product of two 3d vectors which are lists and as args in a class, in which I have used __mul__?

This is my code where only in __mul__ do I have a problem...
class Vector:
def __init__(self, vector):
self.vector = vector
##here lies the issue
def __mul__(self, other):
if len(self.vector) != len(other.vector):
#differentiating scalar multiplication of a single num and a vector versus
#dot product of 2 vectors
return Vector([a*other for a in self.vector])
__rmul__ = __mul__
# found this on this website and it worked amazingly Thank you khelwood for
# scalar! But this doesnt solve dot product!!!
else:
return sum(i[0] * i[1] for i in zip(self.vector,other.vector))
Sum never works for dot product. I don't know why? How do I find the dot product of two vectors? I can multiply each individual number of both lists using zip but the sum of the final list doesnt work!
Am I missing something here?
A link that kinda helped but did't:
http://www.pradeepadiga.me/blog/2017/04/18/finding-dot-product-in-python-without-using-numpy/
Sorry if this is a dumb question:(.
The
__rmul__ = __mul__
appears to be in the wrong spot in your post.
It should really be
def __rmul__(self, other):
self.__mul__(other)
Edit:
This error keeps popping up still....Traceback (most recent call last): File "C:\Users...Classess.py", line 43, in print(x*5==Vector([10, 20, 30])) File "C:...Classess.py", line 25, in mul if len(self.vector) != len(other.vector): AttributeError: 'int' object has no attribute 'vector'
From one of your comments to someone else. He replied and is correct. This is failing in the case of scalar multiplication of 'ints' don't have a 'vector' property. This will be the case for a vector being multiplied by an integer:
x = Vector(1,2,3)
y = x * 5
The above will fail due to the error check in the if statement. 5 has no property vector. You need to first check that other is not an int, if it is an int then you perform your scalar multiplication of the vectors. Change:
if len(self.vector) != len(other.vector):
to
if type(other) is int:
...
Edit 2:
I'll try what someone else has tried but slightly differently.
class Vector:
def __init__(self, vector):
self.vector = vector
##here lies the issue
def __rmul__(self,other):
return self.__mul__(other)
def __mul__(self, other):
if type(other) is int:
return Vector([a*other for a in self.vector])
else:
return sum(i[0] * i[1] for i in zip(self.vector,other.vector))
Test it with:
x = Vector((1,2,3))
y = Vector((3,2,1))
z = 5
print(y*x)
print(x*y)
print(z*y)
print(y*z)
Also, as pointed out my first suggestion won't actually change the output of the code. It has since been changed.

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

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.

Categories