human
Can you provide a the Python code you requested given the following:
I am working on the file "LinearAlgebra.ipynb".
The first task is:
QR blocking
Applying the orthogonal factor $Q$, both during factorization and on each iteration, is sequential.  For matrix-matrix multiplication, we found that blocking was extremely important for performance.  The same is true here, but we will need a transform.  We would like to represent a sequence of elementary reflectors as a single block reflector:
$$\begin{gather} (I - v_0 \tau_0 v_0^T) (I - v_1 \tau_1 v_1^T) &= I - v_0 \tau_0 v_0^T + v_0 \tau_0 v_0^T v_1 \tau_1 v_1^T - v_1 \tau_1 v_1^T \
&= I - V \begin{bmatrix} \tau_0 & \tau_{01} \ 0 & \tau_1 \end{bmatrix} V^T \end{gather} $$
where $V = [ v_0 | v_1 ]$ is an $m\times 2$ matrix and $\tau_{01} = -\tau_0 v_0^T v_1 \tau_1$. This representation can be created recursively and is called the "compact WY" representation of $Q$ and can be computed using LAPACK's dgeqrt2.
Can you write Python code for it?
assistant
#Here is the Python code you requested.

class QRT:
    def __init__(self, F, T):
        self.F = F
        self.T = T
        self.shape = self.F.shape
    def R(self):
        n = len(self.T)
        return numpy.triu(self.F[:n,:])
    def Qdot(self, x):
        m, n = self.shape
        k = x.shape[1] if len(x.shape) == 2 else 1
        if x.shape[0] not in {n, m}:
            raise ValueError("operands could not be multiplied with shapes", self.shape, x.shape)
        y = numpy.zeros((m, k))
        y[:x.shape[0]] = x
        D = numpy.tril(self.F[:n])
        numpy.fill_diagonal(D, 1)
        tmp = D.T.dot(x[:n])
        if x.shape[0] > n:
            tmp += self.F[n:].T.dot(x[n:])
        tmp = self.T.dot(tmp)
        y[:n] -= D.dot(tmp)
        y[n:] -= self.F[n:].dot(tmp)
        return y
    
def qr_householder_wy(A):
    "Compute QR factorization using blocked Householder reflection, result in compact WY"
    m, n = A.shape
    F = A.copy()
    T = numpy.zeros((n, n))
    for i in range(n):
        v = F[i:,i] # in-place
        d = v[1:].dot(v[1:])
        norm = numpy.sqrt(v[0]**2 + d)
        Rii = -numpy.copysign(norm, v[0]) # Choose the further of the two reflections
        v[0] -= Rii
        tau = 2 * v[0]**2 / (v[0]**2 + d)
        v /= v[0]
        # Update the remaining panel
        F[i:,i+1:] -= tau * numpy.outer(v, v.dot(F[i:,i+1:]))
        T[i,i] = tau
        if i > 0: # Add this column to T
            T[:i,i] = -tau * T[:i,:i].dot(F[i:,:i].T.dot(v))
        F[i,i] = Rii
    return QRT(F, T)

m, n = 5, 4
A = vander_cheb(cosspace(-1,1,m), n)
qrt = qr_householder_wy(A)
qr = qr_householder_inplace(A)
I = numpy.eye(n,n)
print(numpy.linalg.norm(qrt.R() - qr.R()), numpy.linalg.norm(qrt.Qdot(I) - qr.Qdot(I)))