about vector by using class - python

I need some helps with my code!
Here is some instruction:
v.mul(other) : If other is of type Vector , returns the dot > product of v and other , which is the sum of the products of the >
corresponding components; raises an assertion error if other is of >
different dimension. If other is of type int or float , returns a new
vector resulting from the scalar multiplication of v with other . If > the type of other is not Vector , int , or float , raises an
assertion > error.
v.rmul(other) : Defined exactly like v.mul(other)
========================================================================
Here is the code:
class Vector(object):
vec = []
def __init__(self, l):
self.vec = l
def dim():
return len(self.vec)
def __getitem__(self, i):
return self.vec[i - 1]
def __setitem__(self, i, x):
self.vec[i - 1] = x
def __str__(self):
s = 'Vector: ['
for i in range(0, len(self.vec)):
s = s + str(self.vec[i])
if i < len(self.vec) - 1:
s = s + ', '
s = s + ']'
return s
def __add__(self, other):
assert(type(other) == Vector)
v = self.vec
for i in range(0, len(v)):
v[i]=v[i] + other[i+1]
x = Vector(v)
return x
def __mul__(self, other):
if type(other) == type(self):
v = self.vec
for i in range(0, len(v)):
v[i]=v[i]*other[i+1]
x = Vector(v)
return sum(x)
elif type(other) == type(1) or type(other) == type(1.0):
v = self.vec
for i in range(0, len(v)):
v[i] = v[i] *other
x = Vector(v)
return x
def __rmul__(self, other):
return self.__mul__(other)
Here are some output from the code:
>>> v1 = Vector([2, 3, 4]); v2 = Vector([1, 2, 3])
>>> print(v2 * 2); print(2 * v2)
Vector: [2, 4, 6]
Vector: [4, 8, 12]
>>> print(v1 * v2); print(v2 * v1)
128
1376
But, the correct output is:
>>> v1 = Vector([2, 3, 4]); v2 = Vector([1, 2, 3])
>>> print(v2 * 2); print(2 * v2)
Vector: [2, 4, 6]
Vector: [2, 4, 6]
>>> print(v1 * v2); print(v2 * v1)
20
20
So, I want to know what the problem is and how to fix it.
Thanks!!

This method gives the desired output:
def __mul__(self, other):
if isinstance(other, self.__class__):
if len(self.vec) != len(other.vec):
raise AssertionError('Vectors have different lengths '
'of {} and {}'.format(len(self.vec), len(other.vec)))
return sum(x * y for x, y in zip(self.vec, other.vec))
elif isinstance(other, (int, float)):
return Vector([x * other for x in self.vec])
else:
raise AssertionError('Cannot use type ' + str(type(other)))

Related

How to execute the cross multiplication in unittest

I have the following class
from math import sqrt
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __eq__(self, other): # v == w
return self.x == other.x and self.y == other.y and self.z == other.z
def __ne__(self, other): # v != w
return not self == other
def __repr__(self):
return "Vector(" + str(self.x) + ", " + str(self.y) + ", " + str(self.z) + ")"
def __add__(self, other):
return Vector(self.x + other.x,self.y + other.y,self.z + other.z)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y, self.z - other.z)
def __mul__(self, other):
return self.x * other.x + self.y * other.y + self.z * other.z
def cross(self, other):
return Vector(self.y * other.z - self.z * other.y,self.z * other.x - self.x * other.z,self.x * other.y - self.y * other.x)
def length(self):
return sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
def __hash__(self):
return hash((self.x, self.y, self.z))
on which I am trying to use the unittest function as follows:
class TestVector(unittest.TestCase):
# test function to test equality of two value
def test_vector_equality(self):
A = [1, 2, 3]
B = [1, 2, 3]
# error message in case if test case got failed
#message = "First value and second value are not equal!"
self.assertTrue(A == B)
def test_vector_inequality(self):
A = [1, 2, 3]
B = [1,-2,-3]
self.assertFalse(A == B)
def test_vector_addition(self):
A = [1, 2, 3]
B = [1, 2, 3]
result = [2, 4, 6]
self.assertEqual([x + y for x, y in zip(A, B)], result)
def test_vector_mulitplication(self):
A = [1, 2, 3]
B = [1, 2, 3]
result = [1, 4, 9]
self.assertEqual([x*y for x, y in zip(A, B)], result)
def test_vector_subtraction(self):
A = [1, 2, 3]
B = [1, 5, 8]
result = [0, -3, -5]
self.assertEqual([x - y for x, y in zip(A, B)], result)
def test_vector_cross_multiplication(self):
A = [1, 2, 3]
B = [1, 5, 8]
result = [1 ,5, 3]
self.assertEqual([(x[0]*y[1], x[1]*y[0]) for x, y in zip(A, B)], result)
def test_length(self):
A = [1, 2, 3]
B = [1, 4, 9]
self.assertEqual(B, [i ** 2 for i in A])
if __name__ == "__main__":
unittest.main(argv=['first-arg-is-ignored'], exit= False)
It works great for all the tests before the cross multiplication one. I would like to get some suggestions about how to set it. Also, I do not know how to set the hash test. Just let me know if you possibly might suggest some way to fix this.
Thank you so much
Unrelated to the question, but imporant: this is not how you unittest. Tests are expected to use class methods, comparing results with expected ones.
Now the issues with test_vector_cross_multiplication:
the result should be [1, -5, 3] instead of [1, 5, 3]
the comprehension [(x[0]*y[1], x[1]*y[0]) for x, y in zip(A, B)] uses indexes on numbers and produces tuples
The correct way to calculate the cross product:
[(A[i]*B[i+1] - B[i]*A[i+1]) for i in range(1-len(A), 1)]

Vector addition and multiplication, adding error

I'm supposed to create a program that is used to multiply or and/or add vectors. I'm supposed to do this using classes and overloading the built in functions like "+" and "str". I've done most of it but my problem is when I run the cases
v1 = Vector([2, 3, 4])
v2 = Vector([1, 2, 2])
v2[3] = 3
print(str(v2) == 'Vector: [1, 2, 3]')
print(str(v1 + v2) == 'Vector: [3, 5, 7]')
print(str(v2 * 2) == 'Vector: [2, 4, 6]')
print(str(2 * (v1 + v2)) == 'Vector: [6, 10, 14]')
For the last case I receive false, I did some poking around and found that my function is storing the data from the previous cases and is using them to compute the last case.
using print(str(v1 + v2) == 'Vector: [3, 5, 7]')
print(str(v2 * 2) == 'Vector: [2, 4, 6]')
as the 2 vectors instead and getting Vector: [10, 18, 26] as an output
my code is below:
class Vector:
def __init__(self,l):
if (isinstance(l,list) == False):
raise TypeError
elif(isinstance(l,list)):
for i in l:
if (isinstance(i, int) == False and isinstance(i,int) == False):
raise TypeError
else:
self.l = l
def dim(self):
return len(self.l)
def __getitem__ (self,i):
if i > len(self.l) or i < 1:
raise IndexError
return (self.l[i-1])
def __setitem__(self, i, x):
if i > len(self.l) or i < 1:
raise IndexError
self.l[i-1] = x
def __str__(self):
print ("Vector: "+ str(self.l))
return ("Vector: "+ str(self.l))
def __add__(self, other):
if (not isinstance(other, Vector)):
raise ValueError
elif(other.dim() != self.dim()):
raise ValueError
for i in range(0,len(self.l)):
self.l[i] = self.l[i] + other[i+1]
return Vector(self.l)
def __mul__(self, other):
if (isinstance(other,float)) or (isinstance(other,int)):
for j in range (0, len(self.l)):
self.l[j] = self.l[j] * other
return Vector(self.l)
elif (isinstance(other, Vector)):
for i in range(0,len(self.l)):
self.l[b] = self.l[b] * other[i+1]
return sum(self.l)
else:
raise AssertionError
def __rmul__(self,other):
if (isinstance(other,float)) or (isinstance(other,int)):
for k in range (0, len(self.l)):
self.l[k] = self.l[k] * other
return Vector(self.l)
elif (isinstance(other, Vector)):
for i in range(0,len(self.l)):
self.l[b] = self.l[b] * other[i+1]
return sum(self.l)
else:
raise AssertionError
How can I fix this unwanted overwriting?

Assigning variable = self creating a copy. Need it to be a reference (pointer)

I am working on creating a matrix class for an assignment I have and usually if I assign a variable as x = self, x is a reference to self and thus all operations are in place. I have a function that reduces the matrix, and as an optional parameter I've added inplace=False such that:
if inplace:
self = A
else:
A = self.copy()
Now normally when I do this, if I were to do an operation such as A += B, self would be modified. However, when I run A.reduce(inplace=True), A is not modified. I've included the full class below and am hoping that someone can tell my why the operations are not happening in place. Thanks in advance.
import numpy as np
class matrix:
def __init__(self, A):
self.value = np.array(A, dtype=np.float)
self.indices = np.arange(self.value.shape[0])
self.shape = self.value.shape
def swap_rows(self, r1, r2):
ind = np.arange(self.value.shape[0])
swap = (r1, r2)
ind[swap[0]] = swap[1]
ind[swap[1]] = swap[0]
temp_ind = self.indices[swap[0]]
self.indices[swap[0]] = self.indices[swap[1]]
self.indices[swap[1]] = temp_ind
self.value = self.value[ind]
def add_rows(self, operations):
# operations = [(c, row1, row2)]
# where operation will be:
# c * row1 + row2 -> row2
for c, row1, row2 in operations:
self.value[row2] += c * self.value[row1]
# ... #
def reduce(self, b_ = None, swap=True, normalize=True, return_steps=False, inplace=False, debug=False):
if inplace:
A = self
else:
A = self.copy()
if b_:
b = b_.copy()
if len(b.shape) == 1:
b.reshape((-1, 1), inplace=True)
if return_steps:
steps = []
# Normalize
if normalize:
A_max = A.row_max()
A /= A_max
if debug:
print("A after normalization:")
print(A)
print("")
if return_steps:
steps.append([('normalize', A_max)])
if b_:
b /= A_max
m, n = A.shape
for col in range(n-1):
# Swap
if swap:
# Check for max value
max_ind = np.argmax(np.abs(A[:, col]))
# Check if max is zero
if np.abs(A[max_ind, col]) < 1e-30:
print('Matrix is singular')
if b_:
return A, b
else:
return A
# Swap if necessary
if max_ind > col:
A.swap_rows(col, max_ind)
if return_steps:
steps.append([('swap', col, max_ind)])
if b_:
b.swap_rows(col, max_ind)
# Get constants
cs = -A[col+1:, col] / A[col, col]
operations = [(c, col, i+col+1) for i, c in enumerate(cs)]
if return_steps:
steps.append(operations)
A.add_rows(operations)
if b_:
b.add_rows(operations)
if debug:
print("A after row operations:")
print(A)
print("")
return_vals = np.array([A, None, None])
if b_:
return_vals[1] = b
if return_steps:
return_vals[2] = steps
if inplace:
return_vals = return_vals[1:]
if return_vals.any():
return tuple(return_vals[return_vals != None])
# ... #
def row_max(self):
return np.array([self[row, i] for row, i in enumerate(np.argmax(np.abs(self.value), axis=1))]).reshape(-1, 1)
# ... #
def copy(self):
return matrix(np.copy(self.value))
def T(self):
return matrix(self.value.T)
def inverse(self):
return matrix(np.linalg.inv(self.value))
def flip(self, axis=None, inplace=False):
if inplace:
self.value = np.flip(self.value, axis=axis)
else:
return matrix(np.flip(self.value, axis=axis))
def reshape(self, shape, inplace=False):
if inplace:
self.value = self.value.reshape(*shape)
else:
return matrix(self.value.reshape(*shape))
def __add__(self, x):
if isinstance(x, matrix):
return matrix(self.value + x.value)
else:
return matrix(self.value + x)
def __sub__(self, x):
if isinstance(x, matrix):
return matrix(self.value - x.value)
else:
return matrix(self.value - x)
def __mul__(self, x):
if isinstance(x, matrix):
return matrix(self.value * x.value)
else:
return matrix(self.value * x)
def __truediv__(self, x):
if isinstance(x, matrix):
return matrix(self.value / x.value)
else:
return matrix(self.value / x)
# ... #
def __matmul__(self, A):
if isinstance(A, matrix):
return matrix(self.value # A.value)
else:
return matrix(self.value # A)
def __repr__(self):
return str(self.value)
def __getitem__(self, item):
return self.value[item]
def __setitem__(self, i, v):
self.value[i] = v
A = matrix([ [ 5, 6, 7, 5, -1],
[ 8, -4, -1, 0, -3],
[ 2, 1, -1, 3, 6],
[-9, 10, 1, -4, 6],
[ 9, 5, -5, -8, 4] ])
print("Original A:")
print(A)
print("")
A.reduce(inplace=True, debug=True)
print("A after inplace reduce function:")
print(A)
print("")
EDIT
Here is what I am trying to recreate in a simplistic way:
class obj:
def __init__(self, value):
self.value = value
def copy(self):
return obj(self.value)
def op(self, y, inplace=False):
if inplace:
x = self
else:
x = self.copy()
x.value += y
x.value /= y
if not inplace:
return x
def __repr__(self):
return str(self.value)
x = obj(5)
x.op(3)
print("Copy:", x)
x.op(3, inplace=True)
print("Inplace:", x)
You say that operators like += modify objects in place, but that's not always true. It only happens if the type of the object on the left side of the operator has an __iadd__ method. If it only has an __add__ method, then the Python interpreter translates X += Y to X = X + Y which is generally not an in-place operation.
So the reason your code doesn't do what you expect is because you don't have an __itruediv__ operator, and when you call A /= A_max (if normalize is True), you make a copy, despite your intention to be operating in place.

Updating object values in class

I have a question about how to return the update value of an object in a class and then use that in another function in the same class. Here is my old code.
class Vector:
def __init__(self, a):
self.a = a
assert type(self.a) == list
for i in self.a:
assert type(i) == int or type(i) == float
def dim(self):
return len(self.a)
def __getitem__(self, i):
assert i >= 1 and i <= self.dim()
return self.a[i-1]
def __setitem__(self, i, x):
assert i >= 1 and i <= self.dim()
self.a[i-1] = x
return self.a[i-1]
def __str__(self):
return 'Vector: ' + str(self.a)
def __add__(self, other):
assert type(other.a) == list and other.dim() == self.dim()
n = []
for j in range(self.dim()):
n.append(self.a[j]+other.a[j])
self.a = n
return self.a
so when i'm running this test case:
v1 = Vector([2, 3, 4])
v2 = Vector([1, 2, 3])
str(v1 + v2)
my output is '[3, 5, 7]' which means it is only following return self.a and not the __str__ function however i want my output to be 'Vector: [3, 5, 7]' as it should be following the __str__ function. I fixed this by returning Vector(self.a) in the __add__ function but i dont know why this works. Can anyone explain why that works, and why return self.a does not simply update the object value and run the __str__ function instead?
Note: Python uses following equivalent notations:
v[i] == v.__getitem__(i)
v[i] = x == v.__setitem__(i, x)
str(v) == v.__str__()
v + other == v.__add__(other)

Error Dividing Vectors Python

I've made a class vector but it doesn't divide correctly when I want to divide Vector / 0, it doesn't throw an error:
class Vector(tuple):
'''"Class to calculate the usual operations with vectors in bi and
tridimensional coordinates. Too with n-dimmensinal.'''
# __slots__=('V') #It's not possible because V is a variable list of param.
def __new__(cls, *V):
'''The new method, we initialize the coordinates of a vector.
You can initialize a vector for example: V = Vector() or
V = Vector(a,b) or V = Vector(v1, v2, ..., vn)'''
if not V:
V = (0, 0)
elif len(V) == 1:
raise ValueError('A vector must have at least 2 coordinates.')
return tuple.__new__(cls, V)
def __mul__(self, V):
'''The operator mult overloaded. You can multipy 2 vectors coordinate
by coordinate.'''
if type(V) == type(self):
if len(self) != len(V):
raise IndexError('Vectors must have same dimmensions')
else:
multiplied = tuple(a * b for a, b in zip(self, V))
elif isinstance(V, type(1)) or isinstance(V, type(1.0)):
multiplied = tuple(a * V for a in self)
return Vector(*multiplied)
__rmul__ = __mul__
def make_one(self, long):
one = tuple(1 for a in range(0, long))
return Vector(*one)
def __truediv__(self, V):
if type(V) == type(self):
if len(self) != len(V):
raise IndexError('Vectors must have same dimmensions.')
if 0 in V:
raise ZeroDivisionError('Division by 0.')
divided = tuple(a / b for a, b in zip(self, V))
return Vector(*divided)
elif isinstance(V, int) or isinstance(V, float):
if V == 0:
return self * V * Vector().make_one(len(self))
#raise ZeroDivisionError('Division by 0.')
return self * (1 / V) * Vector().make_one(len(self))
__rtruediv__ = __truediv__
The test code:
from Vector import Vector
def main():
V1 = Vector(3, 2, -1, 5)
print(0 / V1)
print(V1 / 0)
if __name__ == '__main__':
main()
The console output
(0, 0, 0, 0)
(0, 0, 0, 0)
The first output is right, but the second one is wrong, the right way would be ErrorDivision by 0.
ok, thanks to #user2357112 the right code is this:
def __truediv__(self, V):
if type(V) == type(self):
if len(self) != len(V):
raise IndexError('Vectors must have same dimmensions.')
if 0 in V:
raise ZeroDivisionError('Division by 0.')
divided = tuple(a / b for a, b in zip(self, V))
return Vector(*divided)
elif isinstance(V, int) or isinstance(V, float):
if V == 0:
raise ZeroDivisionError('Division by 0.')
return self * (1 / V) * Vector().make_one(len(self))
#__rtruediv__ = __truediv__
def __rtruediv__(self, V):
if isinstance(V, int) or isinstance(V, float):
if V == 0:
return self * V * Vector().make_one(len(self))
return self * (1 / V) * Vector().make_one(len(self))

Categories