//  [python]
def test_obstacle_gradient_descent(visualize=False, savefig=False):
    n_gmms = 2
    dimension = 2

    gmm_ellipse = GmmObstacle(n_gmms=1)
    gmm_ellipse._gmm = mixture.GaussianMixture(n_components=n_gmms)
    gmm_ellipse._gmm.means_ = np.zeros((n_gmms, dimension))
    gmm_ellipse._gmm.means_[0, :] = [4.4, 0]
    gmm_ellipse._gmm.means_[1, :] = [0, 4.0]

    gmm_ellipse._gmm.covariances_ = np.zeros((n_gmms, dimension, dimension))
    gmm_ellipse._gmm.covariances_[0, :, :] = [[0.6, 0], [0, 4.2]]
    gmm_ellipse._gmm.covariances_[1, :, :] = [[3.7, 0], [0, 0.9]]

    gmm_ellipse._gmm.precisions_cholesky_ = np.zeros((n_gmms, dimension, dimension))
    for ii in range(n_gmms):
        gmm_ellipse._gmm.precisions_cholesky_[ii, :, :] = LA.pinv(
            gmm_ellipse._gmm.covariances_[ii, :, :]
        )
    gmm_ellipse._gmm.weights = 0.5 * np.ones(n_gmms)

    pos_intersection = gmm_ellipse.get_intersection_of_ellipses(
        indices=[0, 1], it_max=100
    )

    # assert (
    #     LA.norm(pos_intersection - np.mean(gmm_ellipse._gmm.means_, axis=0)) < 0.4
    # ), "Intersection position diverged."

    if visualize:
        n_resolution = 30
        x_lim = [-8, 8]
        y_lim = [-8, 8]

        nx = ny = n_resolution
        x_vals, y_vals = np.meshgrid(
            np.linspace(x_lim[0], x_lim[1], nx),
            np.linspace(y_lim[0], y_lim[1], ny),
        )
        positions = np.vstack((x_vals.reshape(1, -1), y_vals.reshape(1, -1)))
        gamma_vals_gmm_prop = np.zeros((n_gmms, positions.shape[1]))

        gradient_field = np.zeros(positions.shape)

        for ii in range(positions.shape[1]):
            for it_gmm in range(n_gmms):
                gamma_vals_gmm_prop[it_gmm, ii] = gmm_ellipse.get_gamma_proportional(
                    positions[:, ii], index=it_gmm
                )

                gradient_field[:, ii] += (-1) * gmm_ellipse.get_gamma_derivative(
                    positions[:, ii],
                    index=it_gmm,
                    powerfactor=10,
                )

        gamma_min = np.min(gamma_vals_gmm_prop, axis=0)

        fig, ax = plt.subplots(1, 1, figsize=(7, 6))
        levels = np.linspace(1.0, 10.0, 10)

        cs0 = ax.contourf(
            x_vals,
            y_vals,
            gamma_min.reshape(x_vals.shape),
            levels=levels,
            # cmap=cmap
        )

        grad_scale = LA.norm(gradient_field, axis=0)
        ind_nonzero = grad_scale > 0

        gradient_field[:, ind_nonzero] = gradient_field[:, ind_nonzero] * np.tile(
            (grad_scale[ind_nonzero] ** 0.1 / grad_scale[ind_nonzero]), (2, 1)
        )

        ax.quiver(
            positions[0, :],
            positions[1, :],
            gradient_field[0, :],
            gradient_field[1, :],
            # scale=grad_scale,
            color="k",
        )

        # gmm_ellipse.plot_obstacle(ax=ax)

        ax.set_aspect("equal", adjustable="box")
        ax.set_xlim(x_lim)
        ax.set_ylim(x_lim)

        ax.grid()

        # fig.tight_layout()
        plt.colorbar(cs0, ax=ax)

        for it_max in [0, 1, 5, 10, 20, 50]:
            # for it_max in [20]:
            pos_intersection = gmm_ellipse.get_intersection_of_ellipses(
                indices=[0, 1],
                it_max=it_max,
            )

            ax.plot(pos_intersection[0], pos_intersection[1], "o", color="#FF6062")

        # Plot last one special
        ax.plot(pos_intersection[0], pos_intersection[1], "ro")

        if savefig:
            figname = "gradient_descent_direction"
            plt.savefig("figures/" + figname + ".pdf", bbox_inches="tight")