docs: def inverse_kinematics(self, end_effector_transformation,
                             q=None,
                             max_iter=1000, tolerance=0.05,
                             mask=numpy.ones(6),
                             use_pinv=False):
          """ Computes the joint angles corresponding to the end effector transformation.
  
          :param end_effector_transformation: the end effector homogeneous transformation matrix
          :param vector q: initial estimate of the joint angles
          :param int max_iter: maximum number of iteration
          :param float tolerance: tolerance before convergence
          :param mask: specify the cartesian DOF that will be ignore (in the case of a chain with less than 6 joints).
          :rtype: vector of the joint angles (theta 1, theta 2, ..., theta n)
  
          """
          if q is None:
              q = numpy.zeros((len(self.links), 1))
          q = numpy.matrix(q.reshape(-1, 1))
  
          best_e = numpy.ones(6) * numpy.inf
          best_q = None
          alpha = 1.0
  
          for _ in range(max_iter):
              e = numpy.multiply(transform_difference(self.forward_kinematics(q)[0], end_effector_transformation), mask)
              d = numpy.linalg.norm(e)
  
              if d < numpy.linalg.norm(best_e):
                  best_e = e.copy()
                  best_q = q.copy()
                  alpha *= 2.0 ** (1.0 / 8.0)
              else:
                  q = best_q.copy()
                  e = best_e.copy()
                  alpha *= 0.5
  
              if use_pinv:
                  dq = numpy.linalg.pinv(self._jacob0(q)) * e.reshape((-1, 1))
              else:
                  dq = self._jacob0(q).T * e.reshape((-1, 1))
              q += alpha * dq
  
              # d = numpy.linalg.norm(dq)
              if d < tolerance:
                  return q
  
          else:
              raise ValueError('could not converge d={}'.format(numpy.linalg.norm(best_e)))