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))
Related
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?
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.
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)
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)))
below classes are in pure python, but the are a little slow on heavily dense calculation and lead to about 1 minute to do about 5 million action.
the question:
Is there any way to write them in C and import them to python for more speed?
how?
the usage is something like this:
_cm=Unit(...) # Unit
_m =Unit(...) # Unit
a= 1*_cm # UnitValue
b= 2*_m # UnitValue
_m2 = _m**2 # Unit
b*a == 0.02 * _m2 # UnitValue
a*b == 200 * _cm2 # UnitValue # _cm2 is auto created unit based on Unit.__new__
b-a = 0.99*_m # UnitValue
a-b = -99*_cm # UnitValue
# and so on...
NOTE: the classes are bigger that what included here...
class Unit(object):
def __new__(self, *args, **kwargs):
# check if this unit not created before and if ues return before created-one.
# useful for cmp between units.
return created_or_new_unit_instance
def __div__(self, other):
return self * (other ** -1) # self / other
def __rdiv__(self, other):
return other * (self ** -1) # other / self
def __rmul__(self, other):
return self * other # other * self
def __mul__(self, other): # self * other
if isinstance(other, SUPPORTED_NUMBERS):
return UnitValue(other, self)
elif isinstance(other, UnitValue): # FIXME DOUBLICATED!
return (other.value * (other.unit * self))
elif isinstance(other, Unit): # multipling two units self * other
# calculate the other exchange factor againest self in `v`
if v == 1.0:
# the bases may differ from self.bases or other.bases
# so just create a new Unit and let __new__ handle doublication.
return Unit(bases)
else:
return v * Unit(bases)
return NotImplemented
def __pow__(self, other, modulo=None): # #UnusedVariable
# create new powered unit.
return new Unit
and the other Class:
class UnitValue(object):
def __init__(self, value, unit):
self.value = value
self.unit = unit
def __add__(self, other): # self + other
if isinstance(other, UnitValue):
o = self.unit.get_unitvalue_in_this_unit(other) # other is UnitValue
v = self.value + o.value
return UnitValue(v, self.unit)
if other == 0:
return UnitValue(self.value, self.unit)
return NotImplemented
def __mul__(self, other): # self * other
if isinstance(other, SUPPORTED_NUMBERS):
return UnitValue(other * self.value, self.unit)
elif isinstance(other, UnitValue):
return (self.value * other.value) * (self.unit * other.unit)
return NotImplemented
def __pow__(self, other, modulo=None):
v = self.value ** other
u = self.unit ** other
if modulo:
v = v % modulo
return UnitValue(v, u)
def __cmp__(self, other):
if isinstance(other, UnitValue):
vo = self.unit.get_unitvalue_in_this_unit(other).value
else:
vo = other
if vo is None:
vo = 0
diff = self.value - vo
epsi = 1e-10
if abs(diff) < epsi: return 0
elif diff > 0: return 1
elif diff < 0: return -1