<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def plot_similarity(ensemble, ax=None, jitter=0.1, scatter_kw=dict(), line_kw=dict()):
 """Plots similarity across optimization runs as a function of model rank. Parameters ensemble : Ensemble object holds optimization results across a range of model ranks ax : matplotlib axis (optional) axis to plot on (defaults to current axis object) jitter : float (optional) amount of horizontal jitter added to scatterpoints (default=0.1) scatter_kw : dict (optional) keyword arguments for styling the scatterpoints line_kw : dict (optional) keyword arguments for styling the line References Ulrike von Luxburg (2010). Clustering Stability: An Overview. Foundations and Trends in Machine Learning. https://arxiv.org/abs/1007.1075 """


    if ax is None:
        ax = plt.gca()

    # compile statistics for plotting
    x, sim, mean_sim = [], [], []
    for rank in sorted(ensemble.results):
        # reconstruction errors for rank-r models
        s = ensemble.similarities(rank)[1:]
        sim.extend(s)
        x.extend(np.full(len(s), rank))
        mean_sim.append(np.mean(s))

    # add horizontal jitter
    ux = np.unique(x)
    x = np.array(x) + (np.random.rand(len(x))-0.5)*jitter

    # make plot
    ax.scatter(x, sim, **scatter_kw)
    ax.plot(ux, mean_sim, **line_kw)

    ax.set_xlabel('model rank')
    ax.set_ylabel('model similarity')
    ax.set_ylim([0, 1.1])

    return ax