class NormalizeRows extends SingleParentVariable<Matrix> {

    @Override
    public Matrix gradient(Variable<?> parent, ComputationContext ctx) {
        double[] parentData = ctx.data(parent).data();
        double[] gradientData = ctx.gradient(this).data();
        double[] result = new double[parentData.length];
        int rows = this.rows;
        int cols = this.cols;
        for (int row = 0; row < rows; row++) {
            double l2Squared = 0;
            for (int col = 0; col < cols; col++) {
                int elementIndex = row * cols + col;
                l2Squared += parentData[elementIndex] * parentData[elementIndex];
            }
            double l2 = Math.sqrt(l2Squared);
            double l2Cubed = l2 * l2Squared;
            for (int col = 0; col < cols; col++) {
                int elementIndex = row * cols + col;
                for (int gradCol = 0; gradCol < cols; gradCol++) {
                    if (col == gradCol) {
                        result[elementIndex] +=
                            gradientData[elementIndex] *
                            (l2Squared - parentData[elementIndex] * parentData[elementIndex]) / l2Cubed;
                    } else {
                        result[elementIndex] -=
                            gradientData[row * cols + gradCol] *
                            (parentData[elementIndex] * parentData[row * cols + gradCol]) / l2Cubed;
                    }
                }
            }
        }
        return new Matrix(result, this.rows, this.cols);
    }

    public  NormalizeRows(Variable<Matrix> matrix);

}