static paintMatrix(painter,
                       matrix,
                       drawArea,
                       amplitudeCircleFillColor,
                       amplitudeCircleStrokeColor,
                       amplitudeProbabilityFillColor,
                       backColor = Config.DISPLAY_GATE_BACK_COLOR,
                       amplitudePhaseStrokeColor = undefined,
                       logCircleStrokeColor = '#AAA') {
        let numCols = matrix.width();
        let numRows = matrix.height();
        let buf = matrix.rawBuffer();
        let diam = Math.min(drawArea.w / numCols, drawArea.h / numRows);
        drawArea = drawArea.withW(diam * numCols).withH(diam*numRows);
        let {x, y} = drawArea;
        let hasNaN = matrix.hasNaN();
        amplitudePhaseStrokeColor = amplitudePhaseStrokeColor || amplitudeCircleStrokeColor;

        painter.fillRect(drawArea, backColor);

        let traceCellsWith = cellTraceFunc => painter.trace(trace => {
            for (let row = 0; row < numRows; row++) {
                for (let col = 0; col < numCols; col++) {
                    let k = (row * numCols + col) * 2;
                    cellTraceFunc(
                        trace,
                        buf[k],
                        buf[k + 1],
                        x + diam * col,
                        y + diam * row,
                        diam);
                }
            }
        });

        if (!hasNaN) {
            // Squared magnitude levels.
            if (amplitudeProbabilityFillColor !== undefined) {
                traceCellsWith(MathPainter._traceAmplitudeProbabilitySquare).
                    thenFill(amplitudeProbabilityFillColor).
                    thenStroke('lightgray', 0.5);
            }

            // Circles.
            if (amplitudeCircleFillColor !== undefined) {
                traceCellsWith(MathPainter._traceAmplitudeProbabilityCircle).
                    thenFill(amplitudeCircleFillColor).
                    thenStroke(amplitudeCircleStrokeColor, 0.5);

                traceCellsWith(MathPainter._traceAmplitudeLogarithmCircle).
                    thenStroke(logCircleStrokeColor, 0.5);
            }
        }

        // Dividers.
        painter.trace(trace => trace.grid(x, y, drawArea.w, drawArea.h, numCols, numRows)).
            thenStroke('lightgray');

        if (!hasNaN) {
            // Phase lines.
            if (logCircleStrokeColor !== undefined) {
                traceCellsWith(MathPainter._traceAmplitudePhaseDirection).
                    thenStroke(amplitudePhaseStrokeColor);
            }
        }

        // Error text.
        if (hasNaN) {
            painter.print(
                'NaN',
                drawArea.x + drawArea.w/2,
                drawArea.y + drawArea.h/2,
                'center',
                'middle',
                'red',
                '16px sans-serif',
                drawArea.w,
                drawArea.h);
        }
    }
Draws a visual representation of a complex matrix.
@param {!Painter} painter
@param {!Matrix} matrix The matrix to draw.
@param {!Rect} drawArea The rectangle to draw the matrix within.
@param {undefined|!string} amplitudeCircleFillColor
@param {!string} amplitudeCircleStrokeColor
@param {undefined|!string} amplitudeProbabilityFillColor
@param {undefined|!string=} backColor
@param {undefined|!string=} amplitudePhaseStrokeColor
@param {undefined|!string=} logCircleStrokeColor