code: def log(cls, q):
          
          v_norm = np.linalg.norm(q.vector)
          q_norm = q.norm
          tolerance = 1e-17
          if q_norm < tolerance:
              # 0 quaternion - undefined
              return Quaternion(scalar=-float('inf'), vector=float('nan')*q.vector)
          if v_norm < tolerance:
              # real quaternions - no imaginary part
              return Quaternion(scalar=log(q_norm), vector=[0,0,0])
          vec = q.vector / v_norm
          return Quaternion(scalar=log(q_norm), vector=acos(q.scalar/q_norm)*vec)
docs: Quaternion Logarithm.
  
          Find the logarithm of a quaternion amount.
  
          Params:
               q: the input quaternion/argument as a Quaternion object.
  
          Returns:
               A quaternion amount representing log(q) := (log(|q|), v/|v|acos(w/|q|)).
  
          Note:
              The method computes the logarithm of general quaternions. See [Source](https://math.stackexchange.com/questions/2552/the-logarithm-of-quaternion/2554#2554) for more details.