I'm working on a couple of basic math classes for performing line collisions in 2D.
Here is my python code:
collisions.py
import math
class Vector:
def __init__(self, x, y):
self._x = x
self._y = y
def __str__(self):
return '(%d, %d)' %(self._x, self._y)
def __add__(self, other):
return Vector(self._x + other._x, self._y + other._y)
def __sub__(self, other):
return Vector(self._x - other._x, self._y - other._y)
def __mul__(self, val):
return Vector(self._x * val, self._y * val)
# same as dot product
#def __mul__ (self, other):
# return self.dot(other)
# same as cross product
#def __pow__(self, other):
# return self.cross(other)
def x(self):
return self._x
def y(self):
return self._y
def cross(self, other):
return (self._x * other._y - self._y * other._x)
def dot(self, other):
return (self._x * other._x + self._y * other._y)
class Line:
def __init__(self, p1, p2):
self._p1 = p1
self._p2 = p2
def slope(self):
if self._p1.x() == self._p2.x():
if self._p1.y() == self._p2.y():
return str("both points coincide")
else:
if self._p1.y() < self._p2.y():
return float('inf')
else:
return float('-inf')
self._m = float((self._p2.y() - self._p1.y()) / (self._p2.x() - self._p1.x()))
return self._m
def p1(self):
return self._p1
def p2(self):
return self._p2
def LineIntersect(l1, l2):
a = l1.p1()
b = l1.p2()
c = l2.p1()
d = l2.p2()
#r = l1.p2() - l1.p1()
r = b - a
#s = l2.p2() - l2.p1()
s = d - c
d = r.cross(s)
#u = ((l2.p2.x() - l1.p1.x()) * r.y() - (l2.p2.y() - l1.p1.y()) * r.x()) / d
u = ((c.x() - a.x()) * r.y() - (c.y() - a.y()) * r.x()) / d
#t = ((l2.p2.x() - l1.p1.x()) * s.y() - (l2.p2.y() - l1.p1.y()) * s.x()) / d
t = ((c.x() - a.x()) * s.y() - (c.y() - a.y()) * s.x()) / d
if (0 <= u and u <= 1 and 0 <= t and t <= 1):
return (a + t * r)
else:
return False;
l1 = Line(Vector(0, 0), Vector(3, 3))
l2 = Line(Vector(3, 0), Vector(0, 3))
intersected = LineIntersect(l1, l2)
print(intersected)
When I run this through Windows 7 command prompt using Python 3.7's interpreter via python collisions.py
It is generating this error message:
D:\Dev\Languages\Python\Projects\Test>python collisions.py
Traceback (most recent call last):
File "collisions.py", line 88, in <module>
intersected = LineIntersect(l1, l2)
File "collisions.py", line 81, in LineIntersect
return (a + t * r)
TypeError: unsupported operand type(s) for *: 'float' and 'Vector'
I'm more inclined with the C languages specifically C++... I've been learning Python for about a year now and I'm starting to get used to it, but things like this, I understand the error message, I just don't know how to resolve them... I'm used to a strongly typed and compiled language over an interpreted language like Python.
Here I'm assuming that I have the operator within the Vector class overloaded to be able to multiply vectors by scalars... Yet Python is yelling at me that it is an unsupported operand. What can I do to resolve this issue? As a side note if you notice any other potential bugs or issues with the code please don't hesitate to mention them in a comment. I'm still learning this language!
Related
I'm trying to coding a Point class to determine if a 3 given point can make a trainagle.
this is the Class I did:
import math
class Point(object):
def __init__(self, x1, y1):
self.x = x1
self.y = y1
def getX(self):
return int(self.x)
def getY(self):
return int(self.y)
def Distance(self):
return math.sqrt((self.x ** 2) + (self.y ** 2))
def PointToStr(self):
return '({}, {})'.format(self.x, self.y)
def DistanceFromPoint(self, pX):
dx = int(self.getX - pX.getX)
dy = int(self.getY - pX.getY)
return math.sqrt((dx * dx) + (dy * dy))
#classmethod
def FromString(cls, Point_str):
x, y = Point_str
return cls(x, y)
and this is my Pyhton file:
from Point import Point
def isTriangle(x1, y1, x2, y2, x3, y3):
return (y2 - y1) * (x3 - x2) != (y3 - y2) * (x2 - x1)
def isTriangle2(p1, p2, p3):
d1 = p1.DistanceFromPoint(p2)
d2 = p1.DistanceFromPoint(p3)
d3 = p2.DistanceFromPoint(p3)
if d1 + d2 > d3 and d1 + d3 > d2 and d2 + d3 > d1:
return True
else:
return False
def main():
p1 = Point(5, 10)
p2 = Point(7, 10)
p3 = Point(15, 10)
print(p1.PointToStr())
print(p2.PointToStr())
print(isTriangle(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY()))
print(isTriangle2(p1, p2, p3))
if __name__ == "__main__":
main()
when I'm trying to run isTriangle2 I get the following error:
TypeError: unsupported operand type(s) for -: 'method' and 'method'
this is the traceback:
Traceback (most recent call last):
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 28, in <module>
main()
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 25, in main
print(isTriangle2(p1, p2, p3))
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\lec_7+8.py", line 9, in isTriangle2
d1 = p1.DistanceFromPoint(p2)
File "C:\Users\barva\PycharmProjects\Giraffe\Ariel-notebook\Point.py", line 23, in DistanceFromPoint
dx = int(self.getX - pX.getX)
At first I tought isTriangle2 didnt transfer the given point to int when I used the getX() and getY() function so I did try to cast them but that didnt help as well.
than I tried to change the class a bit, I think the error is coming from DistanceFromPoint function in the Point class but I dont know how to fix that
in
dx = int(self.getX - pX.getX)
dy = int(self.getY - pX.getY)
The getters are functions and need to be called like functions (i.e add () when the getters are called)
One solution would be to use the #property decorator in the methods getX and getY:
#property
def getX(self):
return int(self.x)
#property
def getY(self):
return int(self.y)
This way the functions getX and getY will become properties of the class, so you will need to remove the "()" when using them:
print(isTriangle(p1.getX, p1.getY, p2.getX, p2.getY, p3.getX, p3.getY))
Now, in addition from my two previous posts ODE implements I try to refactro my code and fix some problems. And I decided, that logically create such classes: Solver,Problem.
So code for ODE_Solver and FE classes finally code and working.
# ODS.py
import numpy as np
class ODE_Solver(object):
def __init__(self, f):
if not callable(f):
raise TypeError('f is not %s, function' % type(f))
self.f = lambda u, x: np.asarray(f(u, x), float)
self.err_sch = None
def solver_st(self):
raise NotImplementedError
def err_st(self):
raise NotImplementedError
def set_initial_condition(self, u0):
if isinstance(u0, (float, int)):
self.neq = 1
u0 = float(u0)
else:
u0 = np.asarray(u0)
self.neq = u0.size
self.u0 = u0
try:
f0 = self.f(self.u0, 0)
except IndexError:
raise IndexError(
'index out of bounds f(u,x). correct index %s' % (str(range(self.neq))))
if f0.size != self.neq:
raise ValueError('f(u,x) returend %d elems, vector u has %d elems' % (f0.size, self.neq))
def solve(self, coord_points, terminate=None):
if terminate is None:
terminate = lambda u, x, step_no: False
if isinstance(coord_points, (float, int)):
raise TypeError('solve: x points not numpy array or numbers.')
self.x = np.asarray(coord_points)
if self.x.size <= 1:
raise ValueError('ODESolver.solve points of coords less than two')
n = self.x.size
if self.neq == 1: # ОДУ
self.u = np.zeros(n)
self.err_sch = np.zeros(n)
else:
self.u = np.zeros((n, self.neq))
self.err_sch = np.zeros((n, self.neq))
self.u[0] = self.u0
self.err_sch[0] = 0
for k in range(n - 1):
self.k = k
self.u[k + 1] = self.solver_st()
self.err_sch[k + 1] = self.err_st()
if terminate(self.u, self.x, self.k + 1):
break
return self.u[:k + 2], self.x[:k + 2]
# ES.py
from ODS import ODE_Solver
import numpy as np
class FE(ODE_Solver):
def solver_st(self):
u, f, k, x = self.u, self.f, self.k, self.x
dx = x[k + 1] - x[k]
u_new = u[k] + dx * f(u[k], x[k])
return u_new
def err_st(self):
u, f, k, x, err_sch = self.u, self.f, self.k, self.x, self.err_sch
dx = x[k + 1] - x[k]
err_sch = np.max(dx)**2
return err_sch
I try to implement class Problem (return ODE and get initial conditions)
import numpy as np
class Problem(object):
def __init__(self, u0, End):
self.u0 = np.asarray(u0)
self.End = End # end point of coords
def __call__(self, u, x):
return (u[1], u[2], u[3], u[4],
- 15 * u[4] - 90 * u[3] - 270 * u[2] - 405 * u[1] - 243 * u[0])
And code class Solver for call numerical scheme, plotting the final result, plot and evaluate error:
import numpy as np
import matplotlib as plt
import ES
import ODS
from ADS import ABM4
from ES import FE
from MLNS import MLN
from RKS import RK4
class Solver(object):
def __init__(self, problem, dx,
method=ES.FE): # choose FE scheme for tetsting
"""
"""
self.problem, self.dx = problem, dx
self.solver = method
#staticmethod
def choose_sch(type):
if type == 1:
method = FE
return method
elif type == 2:
method = RK4
return method
elif type == 3:
method = ABM4
return method
elif type == 4:
method = MLN
return method
else:
raise ValueError('not choose numerical scheme!')
def dsolve(self):
solver = self.method(self.problem)
solver.set_initial_condition(self.problem.u0)
n = int(round(self.problem.End / self.dx))
x_points = np.linspace(0, self.problem.End, n + 1)
self.u, self.x = solver.solve(x_points)
if solver.k + 1 == n:
self.plot()
raise ValueError('not converge this scheme,' % self.problem.End)
def plot(self):
plt.plot(self.x, self.u)
plt.show()
Now, when I call this Solver and Problem
import numpy as np
from ODE_Problem import Problem
from SLV_Prob import Solver
def test():
problem = Problem(u0=[0, 3, -9, -8, 0], End=5)
solver = Solver(problem, dx=0.1)
solver.dsolve()
solver.plot()
if __name__ == '__main__':
test()
I get the error:
Traceback (most recent call last):
File "C:\Fin_Proj_ODE\test2.py", line 14, in <module>
test()
File "C:\Fin_Proj_ODE\test2.py", line 9, in test
solver.dsolve()
File "C:\Fin_Proj_ODE\SLV_Prob.py", line 37, in dsolve
solver = self.method(self.problem)
AttributeError: 'Solver' object has no attribute 'method'
And I dont' understand and suppose what reason of this bug...
So, I have 2 questions for implement this Solver:
How to fix this bug?
How to correct rewrite def choose_sch(type):, that I could to call solver and send args type ( and depending on it, a specific numerical scheme will already be started)?
Question One:
Well, as the error states, your Solver class doesn't have an attribute called "method". Your attribute is actually "solver", so instead of calling
self.method(self.problem)
Try
self.solver(self.problem)
Question Two:
If I'm understanding you correctly, you want to know how you can call the choose_sch method from within the solver constructor and take in a type instead of a method directly. For that, simply do this:
class Solver(object):
def __init__(self, problem, dx, solver_type=1): # choose FE scheme for tetsting
"""
"""
self.problem, self.dx = problem, dx
self.solver = self._choose_sch(solver_type)
#staticmethod
def _choose_sch(solver_type):
methods = {1: FE, 2: RK4, 3: ABM4, 4: MLN}
if solver_type in methods:
return methods[solver_type]
else:
raise ValueError('not choose numerical scheme!')
The dictionary here is much better than the if statement for these kinds of tasks.
You can also alternatively not make _choose_ach a staticmethod if you don't need to call it from a static context and just make it set the solver directly.
I'm writing this code and there is a need to send objects as parameters in functions. My problem is one of the objects needs to be resued with its original values but as I need to return an object from the functions.
I don't know how I can send the answer and keep the original values in the object
safe for reuse. Is there any way to make an object from the class declaration itself?
import math
class Points(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __sub__(self, no):
no.x = no.x - self.x
no.y = no.y - self.y
no.z = no.z - self.z
return(no)
def dot(self, no):
ans = (self.x * no.x)+(self.y * no.y)+(self.z * no.z)
return ans
def cross(self, no):
x = (self.y * no.z)-(self.z * no.y)
y = (self.x * no.z)-(self.z * no.x)
z = (self.x * no.y)-(self.y * no.x)
self.x = x
self.y = y
self.z = z
return(self)
def absolute(self):
return pow((self.x ** 2 + self.y ** 2 + self.z ** 2), 0.5)
if __name__ == '__main__':
points = list()
for i in range(4):
a = list(map(float, input().split()))
points.append(a)
a, b, c, d = Points(*points[0]), Points(*points[1]), Points(*points[2]), Points(*points[3])
x = (b - a).cross(c - b)
y = (c - b).cross(d - c)
angle = math.acos(x.dot(y) / (x.absolute() * y.absolute()))
print("%.2f" % math.degrees(angle))
I want to do something like:
def function_name(self,other)
temp.x = self.x + other.x
temp.y = self.y + other.y
return temp
This way both input objects will have their original values but I don't know how to get that temp.
Thanks everyone who helped. I got the answer to what I was looking. I wanted an object to act as a container that can store the class variables,
and I didn't knew I can just make a new object of the class from within it!
import math
class Points(object):
def __init__(self, x, y, z):
self.x=x
self.y=y
self.z=z
def __sub__(self, no):
return Points((self.x-no.x),(self.y-no.y),(self.z-no.z))
def dot(self, no):
return (self.x*no.x)+(self.y*no.y)+(self.z*no.z)
def cross(self, no):
return Points((self.y*no.z-self.z*no.y),(self.z*no.x-self.x*no.z),(self.x*no.y-self.y*no.x))
def absolute(self):
return pow((self.x ** 2 + self.y ** 2 + self.z ** 2), 0.5)
As you can see using points, i.e the constructor for class Points, I can store the result of any operations and can return it as an object while not altering my input objects.
If what you're trying to do is reuse a variable that you have passed to a class object, you can just duplicate it in your __init__ statement, or in the function where you use it.
e.g
class Foo:
def __init__(self, my_var1, my_var2):
self.my_var1 = my_var1
self.my_var2 = my_var2
def bar(self):
bar_var1 = self.my_var1
bar_var2 = self.my_var2
bar_var1 = bar_var1 + bar_var2
return bar_var1
Although, I am a little confused by why you are attempting to return self in your cross function, as self is a class parameter, and you don't seem to be using it in its intended purpose. If you're confused about how you should be using self, a brief read through the python class tutorial might be helpful. However, barring that, I hope this answers your question.
I am having trouble creating a __div__ method in a Python class for complex numbers which should divide two complex numbers.
Here is my code:
class Complex(object):
def __init__(self, real = 0, imag = 0):
self.real = real
self.imag = imag
def __str__(self):
if self.imag > 0:
return str(self.real) + "+" + str(self.imag) + "i"
elif self.imag < 0:
return str(self.real) + str(self.imag) + "i"
def __div__(self, other):
x = self.real * other.real + self.imag * other.imag
y = self.imag * other.real - self.real * other.imag
z = other.real**2 + other.imag**2
real = x / z
imag = y / z
return Complex(real, imag)
no = Complex(2,-8)
no2 = Complex(3,7)
print(no/no2)
Unfortunately, my approach doesn't work. Any suggestions?
__div__ doesn't exist anymore in Python 3. It's been replaced by __truediv__ for / and __floordiv__ for //
Have a look at
https://docs.python.org/3/reference/datamodel.html
It's __truediv__, not __div__. __div__ was the name for the old Python 2 "floordiv for integer, truediv for non-integer" division.
While you're fixing things, you should probably add an else case in __str__.
you need to create a method __div__(self, other) where you divide the no and also a new method __opposite__(self) to change the sign when multipy,
also calling method how to devide ie no/no1 is not a god method
using #johnO solution, overwiting __truediv__
so OP can use no/no2 to division two complex numbers.
see code below
class Complex(object):
def init(self, real = 0, imag = 0):
self.real = real
self.imag = imag
def __str__(self):
if self.imag > 0:
return str(self.real) + "+" + str(self.imag) + "i"
elif self.imag < 0:
return str(self.real) + str(self.imag) + "i"
def __opposite__(self):
self.real =self.real
self.imag = self. imag if self.imag<0 else self.imag * -1
def __truediv__(self, other):
other.__opposite__()
x = self.real * other.real - self.imag * other.imag
y = self.imag * other.real + self.real * other.imag
z = other.real**2 + other.imag**2
self.new_real = x / z
self.new_imag = y / z
if self.new_imag>0:
result = "{} + {}i".format(self.new_real, self.new_imag)
else:
result = "{} {}i".format(self.new_real, self.new_imag)
return result
no = Complex(4,5)
no2 = Complex(2,6)
print(no/no2)
output
0.24 + 0.68i
I'm currently writing a code to perform Gaussian elimination in MATLAB and then write out the code needed to generate a LaTex file showing all the steps. A lot of the times when I do Gaussian elimination the answers start turning into Fractions. So I thought as a nice learning exercise for classes in Matlab that I would write a Fraction class. But I have no clue how to overload operators and frankly Mathwork's documentation wasn't helpful.
classdef Fraction
properties
numer
denom
end
methods
function a = Fraction(numer,denom)
a.denom = denom;
a.numer = numer;
end
function r = mtimes(a,b)
r = Fraction(a.numer*b.numer,a.denom*b.demon);
end
function r = plus(a,b)
c = a.numer*b.denom+a.denom*b.numer;
d = a.denom*b.denom;
r = Fraction(c,d);
function r = minus(a,b)
c = a.numer*b.denom-a.denom*b.numer;
d = a.denom*b.denom;
r = Fraction(c,d);
end
function r = mrdivide(a,b)
r = Fraction(a.numer*b.denom,a.denom*b.numer);
end
function b = reduceFrac(a)
x = a.numer;
y = b.denom;
while y ~= 0
x = y;
y = mod(x,y);
end
b =Fraction(a.numer/x, a.denom/x)
end
end
end
The plus operator works but the other three do not. Does any one have any ideas? Also how do I call my method reduceFrac?
Fraction.reduceFrac(Fraction(2.4))
I thought that the code above would work, but it didn't. Below is the python version of what I am trying to acheive.
Fraction.py
class Fraction(object):
"""Fraction class
Attributes:
numer: the numerator of the fraction.
denom: the denominator of the fraction.
"""
def __init__(self, numer, denom):
"""Initializes the Fraction class
Sets the inital numer and denom for the
fraction class.
Args:
numer: Top number of the Fraction
denom: Bottom number of the Fraction
Returns:
None
Raises:
None
"""
self.numer = numer
self.denom = denom
def __str__(self):
"""function call along with the print command
Args:
None
Returns:
String: numer / denom.
Raises:
None
"""
return str(self.numer) + '/' + str(self.denom)
def get_numer(self):
return self.numer
def set_numer(self, numer):
self.numer = numer
def get_denom(self):
return self.denom
def set_denom(self, denom):
self.denom = denom
def __add__(self, other):
numer = self.numer*other.denom+other.numer*self.denom
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def __div__(self, other):
numer = self.numer*other.denom
denom = self.denom*other.numer
return Fraction.reduceFrac(Fraction(numer,denom))
def __sub__(self, other):
numer = self.numer*other.denom-other.numer*self.denom
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def __mul__(self, other):
numer = self.numer*other.numer
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def reduceFrac(self):
x = self.numer
y = self.denom
while y != 0:
(x, y) = (y, x % y)
return Fraction(self.numer/x, self.denom/x)
if __name__ == "__main__":
v = Fraction(4,3)
g = Fraction(7,8)
r = Fraction(4,8)
a = v + g
print a
s = v - g
print s
d = v / g
print d
m = v * g
print m
f = Fraction.reduceFrac(r)
print f
Your plus function misses an end