qrDecomposition() {
        if (this._width !== this._height) {
            throw new DetailedError("Expected a square matrix.", this);
        }
        let Q = Matrix.identity(this._width);
        let R = this._clone();
        for (let row = 0; row < this._height; row++) {
            for (let col = 0; col < row && col < this._width; col++) {
                // We're going to cancel out the value below the diagonal with a Givens rotation.

                let belowDiag = R.cell(col, row); // Zero this.
                let onDiag = R.cell(col, col); // With this.

                // Determine how much to rotate.
                let mag1 = onDiag.abs();
                let mag2 = belowDiag.abs();
                if (mag2 === 0) {
                    continue; // Already zero'd.
                }
                let theta = -Math.atan2(mag2, mag1);
                let cos = Math.cos(theta);
                let sin = Math.sin(theta);

                // Need to cancel phases before rotating.
                let phase1 = onDiag.unit().conjugate();
                let phase2 = belowDiag.unit().conjugate();

                // Apply the rotation to R (and cancel it with Q).
                let op = Matrix.square(
                    phase1.times(cos), phase2.times(-sin),
                    phase1.times(sin), phase2.times(cos));
                R._inline_rowMix_preMultiply(col, row, op);
                Q._inline_colMix_postMultiply(col, row, op.adjoint());
            }

            // Cancel imaginary factors on diagonal.
            let u = R.cell(row, row).unit();
            R._inline_rowScale_preMultiply(row, u.conjugate());
            Q._inline_colScale_postMultiply(row, u);
        }
        return {Q, R};
    }
Factors the receiving square matrix into a unitary matrix Q times an upper diagonal matrix R.
@returns {!{Q: !Matrix, R: !Matrix}} where Q.times(R).isEqualTo(this) && Q.isUnitary() && R.isUpperTriangular()