I need to make some functions that perform basic algebraic operations and a couple of other things on quaternions(these are basically complex numbers of the form a + xi + yj + z*k). I first created a class which contain some attributes, and whenever i create an instance with it I get a quaternion. However, when I tried implementing the functions I mentioned before I keep getting error messages. Anyway, here is my code in its full:
from math import *
class Quaternion(object):
def __init__(self, re, xc, yc, zc):
self.a = re
self.x = xc
self.y = yc
self.z = zc
def __str__(self):
return str(self.a) + "+" + str(self.x) + "i" + "+" + str(self.y) + "j" + "+" + str(self.z) + "k"
def add(self, q):
self.a = self.a + q.a
self.x = self.x + q.x
self.y = self.y + q.y
self.z = self.z + q.z
def mul(self, q):
self.a = self.a*q.a - self.x*q.x - self.y*q.y - self.z*q.z
self.x = self.a*q.x + self.x*q.a + self.y*q.z - self.z*q.y
self.y = self.a*q.y + self.y*q.a + self.z*q.x - self.x*q.z
self.z = self.a*q.z + self.z*q.a + self.x*q.y - self.y*q.x
def conjugate(self):
self.a = self.a
self.x = -1 * self.x
self.y = -1 * self.y
self.z = -1 * self.z
def norm(self):
return sqrt((self.a)**2+(self.x)**2+(self.y)**2+(self.z)**2)
def reciprocal(self):
p1 = self.conjugate()
self.a = p1.a * (1/(self.norm())**2)
self.x = p1.x * (1/(self.norm())**2)
self.y = p1.y * (1/(self.norm())**2)
self.z = p1.z * (1/(self.norm())**2)
def main():
p = Quaternion(2, 0, -3, 0)
q = Quaternion(0, 1, 1, -2)
print "p =", p
print "q =", q
print "p + q =", p.add(q)
print "p * q =", p.mul(q)
print "conjugate of p is", p.conjugate()
print "norm of p is", p.norm()
print "reciprocal of p is", p.reciprocal()
print "p x reciprocal(p) =", p.mul(p.reciprocal)
if __name__ == '__main__':
main()
Now, whenever I run the module(so it then executes the commands under the main function), I get this:
p = 2+0i+-3j+0k
q = 0+1i+1j+-2k
p + q = None
p * q = None
conjugate of p is None
norm of p is 9.11043357914
reciprocal of p is
The only thing it does right is printing out the two quaternions p and q, but none of the other functions/methods seem to be working properly(the norm does give a value, but it isnt the right one for some reason).
Before I forget, let me quickly say what each functions needs to do:
add(self, q) needs to add 2 quaternions together.
mul(self, q) needs to multiply 2 quaternions.
conjugate(self) needs to transform a given quaternion a + xi + yj + zk into this form: a - xi - yj - zk.
norm(self) and reciprocal(self) need to respectively return the norm and reciprocal of the quaternion
You are performing the math correctly in principle, but you are not returning a new object where you should be.
For example, let's look at add(). When you sum two objects, you are expecting the return value to be a third object of the same type, which you are printing. Your add() function does not return anything (in Python this is equivalent to returning None), and instead unexpectedly modifies the object it is called on. Instead, do this:
def add(self, q):
return Quaternion(self.a + q.a,
self.x + q.x,
self.y + q.y,
self.z + q.z)
Do the same for the other methods. If you want to use + and * operators in your code, change the method names to __add__ and __mul__. To do in-place addition and multiplication using += and *= operators, sort of like your current methods are doing, rename the current methods to __iadd__ and __imul__, but don't forget to return self at the end.
You get the None values because you did not specify a return value. Add a
return self
at the end of add, mul, conjugate and reciprocal. (If it is intended that these methods change the value of p, and do not just compute a new Quaternion while leaving p untouched.)
Related
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.
So far, finding the hypotenuse, "side c" works fine without problems, the problem is when I try to calculate the angle, I am pretty sure it's returning a wrong value for the angle.
import math
from math import sqrt
class Triangle:
def __init__(self, side_a, side_b, ):
self.side_a = side_a
self.side_b = side_b
def SidesCalculate(self, ):
side_c = sqrt(self.side_a ** 2 + self.side_b ** 2)
return side_c
def AnglesCalculate(self, side_c):
x = math.sin(self.side_a / side_c)
math.asin(x)
x = round(x * 180 / math.pi)
return x
g = Triangle(side_a=int(input("Enter side a: ")), side_b=int(input("Enter side b: ")))
print("side c =", + g.SidesCalculate())
print("angle is =", + g.AnglesCalculate(side_c=True), '°')
Here is a way to do what you want.
First when you compute side_c, save it as an attribute.
def SidesCalculate(self, ):
self.side_c = sqrt(self.side_a ** 2 + self.side_b ** 2)
return self.side_c
Secondly, give the parameter side_c a default value None. (You also have another math error in the following function pointed by CFLS)
def AnglesCalculate(self, side_c = None):
if side_c == None:
side_c = self.side_c
x = math.asin(self.side_a / side_c)
x = round(x * 180 / math.pi)
return x
Now, if you want the class to pick previously computed side_c, you can do this:
g = Triangle(side_a=int(input("Enter side a: ")), side_b=int(input("Enter side b: ")))
print("side c =", + g.SidesCalculate())
print("angle is =", + g.AnglesCalculate(), '°')
def AnglesCalculate(self, side_c):
x = math.asin(self.side_a / side_c)
x = round(x * 180 / math.pi)
return x
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
This is a simple problem that is hard for me to put into words because I'm not too familiar with Python's syntax. I have a class called "Quadrilateral" that takes 4 points, and I'm trying to make a method called "side_length" that I want to use to compute the length of the line between two of the vertices on the quadrilateral:
import math
class Point:
x = 0.0
y = 0.0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
print("Point Constructor")
def to_string(self):
return "{X: " + str(self.x) + ", Y: " + str(self.y) + "}"
class Quadrilateral:
p1 = 0
p2 = 0
p3 = 0
p4 = 0
def __init__(self, p1=Point(), p2=Point(), p3=Point(), p4=Point()):
self.p1 = p1
self.p2 = p2
self.p3 = p3
self.p4 = p4
print("Quadrilateral Constructor")
def to_string(self):
return "{P1: " + self.p1.ToString() + "}, " + "{P2: " + self.p2.ToString() + "}, " + \
"{P3: " + self.p3.ToString() + "}," + "{P4: " + self.p4.ToString() + "}"
def side_length(self, p1, p2):
vertex1 = p1
vertex2 = p2
return math.sqrt((vertex2.x - vertex1.x)**2 + (vertex2.y - vertex1.y)**2)
def perimeter(self):
side1 = self.side_length(self.p1, self.p2)
side2 = self.side_length(self.p2, self.p3)
side3 = self.side_length(self.p3, self.p4)
side4 = self.side_length(self.p4, self.p1)
return side1 + side2 + side3 + side4
Right now I'm calling the side_length method by explicitly telling it to use the quadrilateral's points, but is there a way to implicitly use just "p1" and "p2" without the need to tell it to use the quadrilateral's points (I'm using q.p1 and q.p2 when I just want to use p1 and p2 and imply python to use the quadrilateral's points)? I've realized it's basically a static method, and I want it to use the class fields rather than take in any point.
q = Quadrilateral(p1, p2, p3, p4)
print(q.to_string())
print("Side length between " + q.p1.to_string() + " and " + q.p2.to_string() + ": " + str(q.side_length(q.p1, q.p2)))
print("Perimeter is: " + str(q.perimeter()))
I also have other redundancy issues- like are there better ways to go about initially defining the points p1, p2, p3, p4 in the quadrilateral class, and is there a simpler way to compute the perimeter of the quadrilateral?
This looks like a nearly perfect question for https://codereview.stackexchange.com, but I'll put my edits anyway.
To note at start:
avoid classes until you can
try writing less junk/support/boilerplate code and more fun code
recylce whatever python has to offer before making something new
write at least a tiny test or an assert
skip the rules above while learning
Here is my edit of your code, hope you find some useful ideas/clues:
# not needed
#import math
class Point:
#FIXME: delete this and do some reading on class attributes
# x = 0.0
# y = 0.0
def __init__(self, x, y):
self.x = x
self.y = y
#FIXME: use __str__ method for this
# def to_string(self):
# return "{X: " + str(self.x) + ", Y: " + str(self.y) + "}"
def distance(self, p):
return ((self.x - p.x) ** 2 + (self.y - p.y) ** 2) ** .5
class Quadrilateral:
# FIXME: same as in class Point
# p1 = 0
# p2 = 0
# p3 = 0
# p4 = 0
# FIXED: you do not want anything undefined for constructor
# def __init__(self, p1=Point(), p2=Point(), p3=Point(), p4=Point()):
def __init__(self, p1, p2, p3, p4):
# saving some typing
self.points = [p1, p2, p3, p4]
# self.p2 = p2
# self.p3 = p3
# self.p4 = p4
# print("Quadrilateral Constructor")
# FIXME: please make some life easier
# def to_string(self):
# return "{P1: " + self.p1.ToString() + "}, " + "{P2: " + self.p2.ToString() + "}, " + \
# "{P3: " + self.p3.ToString() + "}," + "{P4: " + self.p4.ToString() + "}"
def side(self, vertex_n):
# TODO: elaborate some protection against wrong *vertex_n*
a, b = self.points[vertex_n], self.points[vertex_n-1]
return a.distance(b)
#property
def perimeter(self):
return sum([self.side(i) for i in range(4)])
# any duplicated code is a sign of danger: somehtign is going wrong!
#side1 = self.side_length(self.p1, self.p2)
#side2 = self.side_length(self.p2, self.p3)
#side3 = self.side_length(self.p3, self.p4)
#side4 = self.side_length(self.p4, self.p1)
#return side1 + side2 + side3 + side4
pts = [Point(x, y) for x, y in [(0,0), (1,0), (1,1), (0,1)]]
assert Quadrilateral(*pts).perimeter == 4
As an excercise you can make a parent class Polygon and inherit Quadrilateral from it.
Update: in the original answer I wrote:
# COMMENT: class Point better be a namedtuple, please google it and use it
That sounded too categorical to a respected reader, who noted:
Whether Point is mutable depends on what you want to do with points in your app. Usually go with immutable by default if you don't have any reason not to.
In other words, it is prudent not to rush into namedtuple unless you are sure the the data structure should not change. To me that sounds overly protective, but you cannot deny the logic your choice of data structure depends on how you plan to use it.
For converting something to namedtuple please see a nice example of refactoring at Raymond Hettinger - Beyond PEP 8 -- Best practices for beautiful intelligible code.
Other suggested direction for thought is using dataclass, available in standard library starting Python 3.7.
Is this what you mean?
def side_length(self, side):
if side == 1:
vertex1 = self.p1
vertex2 = self.p2
elif side == 2:
vertex1 = self.p2
vertex2 = self.p3
elif side == 3:
vertex1 = self.p3
vertex2 = self.p4
elif side == 4:
vertex1 = self.p4
vertex2 = self.p1
else:
print("Error! No side {}".format(side))
return None
return math.sqrt((vertex2.x - vertex1.x)**2 + (vertex2.y - vertex1.y)**2)
I'd suggest changing how you keep track of your points. Rather than having four separate attributes with numbers in the names, use a list. Then you can pass an index to your side_lengths method:
def __init__(self, p1, p2, p3, p4):
self.points = [p1, p2, p3, p4]
def side_length(self, n):
vertex1 = self.points[n]
vertex2 = self.points[n-1] # if the index becomes -1, that's ok, it will wrap around
return math.sqrt((vertex2.x - vertex1.x)**2 + (vertex2.y - vertex1.y)**2)
def perimeter(self):
return sum(side_length(i) for i in range(4))
I'd also suggest that you rename your to_string functions to __str__, as Python will call that method automatically for you in some cases (such as when you're printing an object).
I have written a class to work with three dimensional vectors as follows
class vector(object):
def __init__(self, x=None, y=None, z=None, angle=None):
if angle == None:
self.x, self.y, self.z = x, y, z
if angle != None:
if angle == "rad":
self.r, self.theta, self.phi = x, y, z
if angle == "deg":
self.r = x
self.theta = y * 2 * pi / 360.
self.phi = z * 2 * pi / 360.
self.x = self.r * sin(self.theta) * cos(self.phi)
self.y = self.r * sin(self.theta) * sin(self.phi)
self.z = self.r * cos(self.theta)
def write(self):
file.write("[" + str(self.x) + ",\t" + str(self.y) + ",\t" + str(self.z) + "]")
def write_sph(self):
file.write("[" + str(self.mag()) + ",\t" + str(self.gettheta()) + ",\t" + str(self.getphi()) + "]")
def getx(self):
return self.x
def gety(self):
return self.y
def getz(self):
return self.z
def setx(self, x):
self.x = x
def sety(self, y):
self.y = y
def setz(self, z):
self.z = z
def square(self):
return self.x*self.x + self.y*self.y + self.z*self.z
def mag(self):
return sqrt(self.square())
def gettheta(self):
return arccos(self.z / self.mag())
def getphi(self):
return arctan2(self.y, self.x) # sign depends on which quadrant the coordinates are in
def __add__(self, vector(other)):
v_sum = vector(other.gettx() + self.gettx(), other.getty() + self.getty(), other.getty() + self.getty())
return v_sum
In the last definition I am attempting to override the operator for addition. The definition works by calling a new vector named other and adding its x,y,z components to the corresponding components of self. When I run the code I'm told the syntax for the definition is invalid. How do I correctly define the vector argument for this overriding definition? Also what difference would changing the definition from def __ add __ to simply def add make? i.e what do the underscores denote?
You shouldn't have vector(other) in your parameter list - just say other. Also, you'll need to fix the typos in the add method:
def __add__(self, other):
v_sum = vector(other.getx() + self.getx(), other.gety() + self.gety(), other.getz() + self.getz())
return v_sum