Beispiel #1
0
def plot_plane(ax, normal_vector, point_on_plane, l_vert=1, color='w', line_color='black', alpha=0.15, linewidth=0.5,
               **kwargs):
    """
    Plot a plane in R3.
    Based on the function of riepybdlib (https://gitlab.martijnzeestraten.nl/martijn/riepybdlib)

    Parameters
    ----------
    :param ax: figure axes
    :param normal_vector: normal vector of the plane
    :param point_on_plane: point lying on the plane

    Optional parameters
    -------------------
    :param l_vert: length/width of the displayed plane
    :param color: color of the plane
    :param line_color: color of the contour of the plane
    :param alpha: transparency index
    :param linewidth: linewidth of the border of the plane
    :param kwargs:

    Returns
    -------
    :return: -
    """
    # Tangent axis at 0 rotation:
    T0 = np.array([[1, 0], [0, 1], [0, 0]])

    # Rotation matrix with respect to zero:
    (axis, ang) = get_axisangle(normal_vector)
    R = rotation_matrix_from_axis_angle(axis, -ang)

    # Tangent axis in new plane:
    T = R.T.dot(T0)

    # Compute vertices of tangent plane at g
    hl = 0.5 * l_vert
    X = [[hl, hl],  # p0
         [hl, -hl],  # p1
         [-hl, hl],  # p2
         [-hl, -hl]]  # p3
    X = np.array(X).T
    points = (T.dot(X).T + point_on_plane).T
    psurf = points.reshape((-1, 2, 2))

    ax.plot_surface(psurf[0, :], psurf[1, :], psurf[2, :], color=color, alpha=alpha, linewidth=0, **kwargs)

    # Plot contours of the tangent space
    points_lines = points[:, [0, 1, 3, 2, 0]]
    ax.plot(points_lines[0], points_lines[1], points_lines[2], color=line_color, linewidth=linewidth)
Beispiel #2
0
def bo_plot_acquisition_spd(ax,
                            acq_fct,
                            r_cone,
                            xs=None,
                            ys=None,
                            opt_x=None,
                            true_opt_x=None,
                            chol=False,
                            alpha=0.3,
                            elev=10,
                            azim=-20,
                            n_elems=100,
                            n_elems_h=10):
    """
    Plot an acquisition function in the SPD cone

    Parameters
    ----------
    :param ax: figure axis
    :param acq_fct: acquisition function
    :param r_cone: cone radius

    Optional parameters
    -------------------
    :param xs: samples of the BO                        [n x 3]
    :param ys: value of the samples of the BO
    :param opt_x: current best optimizer of the BO      [1 x 3]
    :param true_opt_x: true minimum point               [1 x 3]
    :param chol: if True, the Cholesky decomposition is used
    :param alpha: transparency
    :param elev: axis elevation
    :param azim: axis azimut
    :param n_elems: number of elements to plot in a slice of the cone
    :param n_elems_h: number of slices of the cone to plot

    Returns
    -------
    :return: -
    """
    # Make the panes transparent
    ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))

    # Make the grid lines transparent
    ax.xaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)
    ax.yaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)
    ax.zaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)

    # Remove axis
    ax._axis3don = False

    # Initial view
    ax.view_init(elev=elev, azim=azim)

    # Plot SPD cone
    plot_spd_cone(ax, r=r_cone, lim_fact=0.8)

    # Values of test function for points on the manifold
    phi = np.linspace(0, 2 * np.pi, n_elems)

    # Matrix for rotation of 45° of the cone
    dir = np.cross(np.array([1, 0, 0]), np.array([1., 1., 0.]))
    R = rotation_matrix_from_axis_angle(dir, np.pi / 4.)

    # Points of the cone
    h = np.linspace(0.01, r_cone, n_elems_h)
    x_cone = np.zeros((n_elems_h, n_elems, n_elems))
    y_cone = np.zeros((n_elems_h, n_elems, n_elems))
    z_cone = np.zeros((n_elems_h, n_elems, n_elems))
    colors = np.zeros((n_elems_h, n_elems, n_elems))
    for k in range(n_elems_h):
        r = np.linspace(0, h[k] - 0.01, n_elems)
        for i in range(n_elems):
            # Points on a plane cutting the cone
            xyz = np.vstack((h[k] * np.ones(n_elems), r[i] * np.sin(phi),
                             r[i] / np.sqrt(2) * np.cos(phi)))

            # Rotation
            xyz = R.dot(xyz)

            # Coordinates
            x_cone[k, i] = xyz[0]
            y_cone[k, i] = xyz[1]
            z_cone[k, i] = xyz[2]

        for i in range(n_elems):
            for j in range(n_elems):
                if not chol:
                    data_tmp = torch.tensor([[
                        x_cone[k, i, j], y_cone[k, i, j],
                        z_cone[k, i, j] * np.sqrt(2)
                    ]]).double()
                    colors[k, i, j] = acq_fct(data_tmp).detach().numpy()
                else:
                    indices = np.tril_indices(2)
                    data_tmp = np.array([[x_cone[k, i, j], z_cone[k, i, j]],
                                         [z_cone[k, i, j], y_cone[k, i, j]]])
                    data_chol_tmp = torch.tensor(np.linalg.cholesky(data_tmp),
                                                 dtype=torch.float64)
                    colors[k, i, j] = acq_fct(
                        data_chol_tmp[indices][None]).detach().numpy()

    min_colors = np.min(colors)
    colors = (colors - min_colors)
    max_colors = np.max(colors)
    colors = np.min([max_colors * np.ones(colors.shape), colors], axis=0)
    colors = colors / max_colors

    if ys is not None:
        colors_ys = pl.cm.inferno(
            np.ones(ys.shape) - (ys - min_colors) / max_colors)

    for k in range(n_elems_h):
        colors_plot = pl.cm.inferno(np.ones((n_elems, n_elems)) - colors[k])
        ax.plot_surface(x_cone[k],
                        y_cone[k],
                        z_cone[k],
                        rstride=4,
                        cstride=4,
                        facecolors=colors_plot,
                        linewidth=0.,
                        alpha=alpha)

    # Plots xs
    if xs is not None and ys is not None:
        for n in range(xs.shape[0]):
            ax.scatter(xs[n, 0], xs[n, 1], xs[n, 2] / np.sqrt(2), s=30, c='k')
            # ax.scatter(xs[n, 0], xs[n, 1], xs[n, 2] / np.sqrt(2), s=30, c=colors_ys[n])

    # Plot opt x
    if opt_x is not None:
        ax.scatter(opt_x[0, 0],
                   opt_x[0, 1],
                   opt_x[0, 2] / np.sqrt(2),
                   s=60,
                   c='deepskyblue',
                   marker='D')

    # Plot true minimum
    if true_opt_x is not None:
        ax.scatter(true_opt_x[0, 0],
                   true_opt_x[0, 1],
                   true_opt_x[0, 2] / np.sqrt(2),
                   s=100,
                   c='g',
                   marker='*')
Beispiel #3
0
def bo_plot_function_spd(ax,
                         function,
                         r_cone,
                         true_opt_x=None,
                         true_opt_y=None,
                         chol=False,
                         max_colors=None,
                         alpha=0.3,
                         elev=10,
                         azim=-20,
                         n_elems=100,
                         n_elems_h=10):
    """
    Plot a function in the SPD cone

    Parameters
    ----------
    :param ax: figure axis
    :param function: function
    :param r_cone: cone radius

    Optional parameters
    -------------------
    :param true_opt_x: true minimum point on the manifold                 [1 x 3]
    :param true_opt_y: true minimum value
    :param chol: if True, the Cholesky decomposition is used
    :param max_colors: maximum value (to bound the colors)
    :param alpha: transparency
    :param elev: axis elevation
    :param azim: axis azimut
    :param n_elems: number of elements to plot in a slice of the cone
    :param n_elems_h: number of slices of the cone to plot

    Returns
    -------
    :return: max_colors
    """
    # Make the panes transparent
    ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))

    # Make the grid lines transparent
    ax.xaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)
    ax.yaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)
    ax.zaxis._axinfo["grid"]['color'] = (1, 1, 1, 0)

    # Remove axis
    ax._axis3don = False

    # Initial view
    ax.view_init(elev=elev, azim=azim)
    # ax.view_init(elev=10, azim=50.)

    # Plot SPD cone
    plot_spd_cone(ax, r=r_cone, lim_fact=0.8)

    # Values of test function for points on the manifold
    phi = np.linspace(0, 2 * np.pi, n_elems)

    # Matrix for rotation of 45° of the cone
    dir = np.cross(np.array([1, 0, 0]), np.array([1., 1., 0.]))
    R = rotation_matrix_from_axis_angle(dir, np.pi / 4.)

    # Points of the cone
    h = np.linspace(0.01, r_cone, n_elems_h)
    x_cone = np.zeros((n_elems_h, n_elems, n_elems))
    y_cone = np.zeros((n_elems_h, n_elems, n_elems))
    z_cone = np.zeros((n_elems_h, n_elems, n_elems))
    colors = np.zeros((n_elems_h, n_elems, n_elems))
    for k in range(n_elems_h):
        r = np.linspace(0, h[k] - 0.01, n_elems)
        for i in range(n_elems):
            # Points on a plane cutting the cone
            xyz = np.vstack((h[k] * np.ones(n_elems), r[i] * np.sin(phi),
                             r[i] / np.sqrt(2) * np.cos(phi)))

            # Rotation
            xyz = R.dot(xyz)

            # Coordinates
            x_cone[k, i] = xyz[0]
            y_cone[k, i] = xyz[1]
            z_cone[k, i] = xyz[2]

        # Compute the function values at given points
        for i in range(n_elems):
            for j in range(n_elems):
                if not chol:
                    data_tmp = torch.tensor([[
                        x_cone[k, i, j], y_cone[k, i, j],
                        z_cone[k, i, j] * np.sqrt(2)
                    ]]).double()
                    colors[k, i, j] = function(data_tmp).detach().numpy()
                else:
                    indices = np.tril_indices(2)
                    data_tmp = np.array([[x_cone[k, i, j], z_cone[k, i, j]],
                                         [z_cone[k, i, j], y_cone[k, i, j]]])
                    data_chol_tmp = torch.tensor(np.linalg.cholesky(data_tmp),
                                                 dtype=torch.float64)
                    colors[k, i, j] = function(
                        data_chol_tmp[indices]).detach().numpy()

    # Rescale the colors
    if true_opt_y is not None:
        min_colors = true_opt_y
    else:
        min_colors = np.min(colors)
    colors = (colors - min_colors)
    if max_colors is None:
        max_colors = np.max(colors)
    else:
        np.min([colors, max_colors * np.ones(colors.shape)], axis=0)
    colors = colors / max_colors

    # Plot surfaces
    for k in range(n_elems_h):
        colors_plot = pl.cm.inferno(np.ones((n_elems, n_elems)) - colors[k])

        ax.plot_surface(x_cone[k],
                        y_cone[k],
                        z_cone[k],
                        rstride=4,
                        cstride=4,
                        facecolors=colors_plot,
                        linewidth=0.,
                        alpha=alpha)

    # Plot optimal point
    if true_opt_x is not None:
        ax.scatter(true_opt_x[0, 0],
                   true_opt_x[1, 1],
                   true_opt_x[0, 1],
                   s=100,
                   c='g',
                   marker='*')

    return max_colors
Beispiel #4
0
def plot_spd_cone(ax,
                  r=1.,
                  color=[0.8, 0.8, 0.8],
                  n_elems=50,
                  linewidth=2.,
                  linewidth_axes=1.,
                  alpha=0.3,
                  lim_fact=0.6,
                  l1=47,
                  l2=30):
    """
    Plot the 2x2 SPD cone

    Parameters
    ----------
    :param ax: figure acis
    :param r: radius of the cone
    :param color: color of the surface of the cone
    :param n_elems: number of elements used to plot the cone
    :param linewidth: linewidth of the borders of the cone
    :param linewidth_axes: linewidth of the axis of the symmetric space (plotted at the origin)
    :param alpha: transparency factor
    :param lim_fact: factor for the axis length
    :param l1: index of the first line plotted to represent the border of the cone
    :param l2: index of the second line plotted to represent the border of the cone

    Returns
    -------
    :return: -
    """

    phi = np.linspace(0, 2 * np.pi, n_elems)

    # Rotation of 45° of the cone
    dir = np.cross(np.array([1, 0, 0]), np.array([1., 1., 0.]))
    R = rotation_matrix_from_axis_angle(dir, np.pi / 4.)

    # Points of the cone
    xyz = np.vstack(
        (r * np.ones(n_elems), r * np.sin(phi), r / np.sqrt(2) * np.cos(phi)))

    xyz = R.dot(xyz)

    x = np.vstack((np.zeros(n_elems), xyz[0]))
    y = np.vstack((np.zeros(n_elems), xyz[1]))
    z = np.vstack((np.zeros(n_elems), xyz[2]))

    # Draw cone
    ax.plot_surface(x,
                    y,
                    z,
                    rstride=4,
                    cstride=4,
                    color=color,
                    linewidth=linewidth,
                    alpha=alpha)

    ax.plot(xyz[0], xyz[1], xyz[2], color='k', linewidth=linewidth)
    ax.plot(x[:, l1], y[:, l1], z[:, l1], color='k', linewidth=linewidth)
    ax.plot(x[:, l2], y[:, l2], z[:, l2], color='k', linewidth=linewidth)

    # Draw axis
    lim = lim_fact * r
    x_axis = np.array([[0, lim / 2], [0, 0], [0, 0]])
    y_axis = np.array([[0, 0], [0, lim / 2], [0, 0]])
    z_axis = np.array([[0, 0], [0, 0], [0, lim / 2]])

    ax.plot(x_axis[0],
            x_axis[1],
            x_axis[2],
            color='k',
            linewidth=linewidth_axes)
    ax.plot(y_axis[0],
            y_axis[1],
            y_axis[2],
            color='k',
            linewidth=linewidth_axes)
    ax.plot(z_axis[0],
            z_axis[1],
            z_axis[2],
            color='k',
            linewidth=linewidth_axes)

    # Set limits
    ax.set_xlim([-lim / 2, 3. * lim / 2])
    ax.set_ylim([-lim / 2, 3 * lim / 2])
    ax.set_zlim([-lim, lim])