code: def qr(X, ip_B=None, reorthos=1):
      
      if ip_B is None and X.shape[1] > 0:
          return scipy.linalg.qr(X, mode='economic')
      else:
          (N, k) = X.shape
          Q = X.copy()
          R = numpy.zeros((k, k), dtype=X.dtype)
          for i in range(k):
              for reortho in range(reorthos+1):
                  for j in range(i):
                      alpha = inner(Q[:, [j]], Q[:, [i]], ip_B=ip_B)[0, 0]
                      R[j, i] += alpha
                      Q[:, [i]] -= alpha * Q[:, [j]]
              R[i, i] = norm(Q[:, [i]], ip_B=ip_B)
              if R[i, i] >= 1e-15:
                  Q[:, [i]] /= R[i, i]
          return Q, R
docs: QR factorization with customizable inner product.
  
      :param X: array with ``shape==(N,k)``
      :param ip_B: (optional) inner product, see :py:meth:`inner`.
      :param reorthos: (optional) numer of reorthogonalizations. Defaults to
        1 (i.e. 2 runs of modified Gram-Schmidt) which should be enough in most
        cases (TODO: add reference).
  
      :return: Q, R where :math:`X=QR` with :math:`\\langle Q,Q \\rangle=I_k` and
        R upper triangular.