docs: private boolean _decompose() {
          double h[] = QH.data;
  
          for( int k = 0; k < N-2; k++ ) { // k = column
              u[k*2] = 0;
              u[k*2+1] = 0;
              double max = QrHelperFunctions_ZDRM.extractColumnAndMax(QH,k+1,N,k,u,0);
  
              if( max > 0 ) {
                  // -------- set up the reflector Q_k
  
                  double gamma = QrHelperFunctions_ZDRM.computeTauGammaAndDivide(k+1,N,u,max,tau);
                  gammas[k] = gamma;
  
                  // divide u by u_0
                  double real_u_0 = u[(k+1)*2]   + tau.real;
                  double imag_u_0 = u[(k+1)*2+1] + tau.imaginary;
                  QrHelperFunctions_ZDRM.divideElements(k + 2, N, u, 0, real_u_0,imag_u_0 );
  
                  // write the reflector into the lower left column of the matrix
                  for (int i = k+2; i < N; i++) {
                      h[(i*N+k)*2]   = u[i*2];
                      h[(i*N+k)*2+1] = u[i*2+1];
                  }
  
                  u[(k+1)*2]   = 1;
                  u[(k+1)*2+1] = 0;
  
                  // ---------- multiply on the left by Q_k
                  QrHelperFunctions_ZDRM.rank1UpdateMultR(QH, u,0, gamma, k + 1, k + 1, N, b);
  
                  // ---------- multiply on the right by Q_k
                  QrHelperFunctions_ZDRM.rank1UpdateMultL(QH, u,0, gamma, 0, k + 1, N);
  
                  // since the first element in the householder vector is known to be 1
                  // store the full upper hessenberg
                  h[((k+1)*N+k)*2]   = -tau.real*max;
                  h[((k+1)*N+k)*2+1] = -tau.imaginary*max;
  
              } else {
                  gammas[k] = 0;
              }
  
          }
  
          return true;
      }