# L-25 MCS 507 Wed 19 Oct 2011 : quaternion.py

class Quaternion:
   """
   Quaternions are hypercomplex numbers.
   """
   count = 0   # class data attributes
   who = []

   def __init__(self,a=0,b=0,c=0,d=0):
      """
      Constructs the Quaternion with 
      coefficients a,b,c,d.
      """
      self.a = a  # object data attributes
      self.b = b
      self.c = c
      self.d = d
      Quaternion.count += 1
      Quaternion.who.append(self)

   def __str__(self):
      "The string representation of a Quaternion"
      return '%.2f + %.2f i + %.2f j + %.2f k' \
             % (self.a,self.b,self.c,self.d)

   def __repr__(self):
      "Quaternion Representation as String"
      return str(self)

   def __eq__(self,other):
      "Defines Quaternion Equality"
      return self.a == other.a and \
             self.b == other.b and \
             self.c == other.c and \
             self.d == other.d 

   def __neg__(self):
      "The negation of a Quaternion"
      self.a = -self.a
      self.b = -self.b 
      self.c = -self.c
      self.d = -self.d

   def __add__(self,other):
      "Adding two Quaternions"
      return Quaternion(self.a+other.a,\
                        self.b+other.b,\
                        self.c+other.c,\
                        self.d+other.d)

   def __iadd__(self,other):
      "Inplace Adder of two Quaternions"
      # We have to create a new object!
      return Quaternion(self.a + other.a,\
                        self.b + other.b,\
                        self.c + other.c,\
                        self.d + other.d)

   def __abs__(self):
      "returns the magnitude of a Quaternion"
      from math import sqrt
      return sqrt(self.a**2+self.b**2+self.c**2+self.d**2)

   def conjugate(self):
      "Returns the conjugate of a Quaternion"
      return Quaternion(self.a,-self.b,-self.c,-self.d)

   def scamul(self,x):
      "Product of Quaternion with Scalar x"
      return Quaternion(self.a*x,self.b*x,self.c*x,self.d*x)

   def __invert__(self):
      "The Inverse of the Quaternion"
      return self.conjugate().scamul(1/abs(self))
