Performs a certain number of Metropolis steps. 

        Parameters
        ----------
        compute_target: function 
            computes the target density for the proposed values
        mh_options: dict 
            + 'type_prop': {'random_walk', 'independent'}
              type of proposal: either Gaussian random walk, or independent Gaussian 
            + 'adaptive': bool
              If True, the covariance matrix of the random walk proposal is
              set to a `rw_scale` times the weighted cov matrix of the particle
              sample (ignored if proposal is independent)
            + 'rw_scale': float (default=None)
              see above (ignored if proposal is independent)
            + 'indep_scale': float (default=1.1) 
              for an independent proposal, the proposal distribution is
              Gaussian with mean set to the particle mean, cov set to
              `indep_scale` times particle covariance
            + 'nsteps': int (default: 0)
              number of steps; if 0, the number of steps is chosen adaptively
              as follows: we stop when the average distance between the
              starting points and the stopping points increase less than a
              certain fraction
            + 'delta_dist': float (default: 0.1)
              threshold for when nsteps = 0

def Metropolis(self, compute_target, mh_options):
        """Performs a certain number of Metropolis steps. 

        Parameters
        ----------
        compute_target: function 
            computes the target density for the proposed values
        mh_options: dict 
            + 'type_prop': {'random_walk', 'independent'}
              type of proposal: either Gaussian random walk, or independent Gaussian 
            + 'adaptive': bool
              If True, the covariance matrix of the random walk proposal is
              set to a `rw_scale` times the weighted cov matrix of the particle
              sample (ignored if proposal is independent)
            + 'rw_scale': float (default=None)
              see above (ignored if proposal is independent)
            + 'indep_scale': float (default=1.1) 
              for an independent proposal, the proposal distribution is
              Gaussian with mean set to the particle mean, cov set to
              `indep_scale` times particle covariance
            + 'nsteps': int (default: 0)
              number of steps; if 0, the number of steps is chosen adaptively
              as follows: we stop when the average distance between the
              starting points and the stopping points increase less than a
              certain fraction
            + 'delta_dist': float (default: 0.1)
              threshold for when nsteps = 0
        """
        opts = mh_options.copy()
        nsteps = opts.pop('nsteps', 0)
        delta_dist = opts.pop('delta_dist', 0.1)
        proposal = self.choose_proposal(**opts)
        xout = self.copy()
        xp = self.__class__(theta=np.empty_like(self.theta))
        step_ars = []
        for _ in self.mcmc_iterate(nsteps, self.arr, xout.arr, delta_dist):
            xp.arr[:, :], delta_lp = proposal.step(xout.arr)
            compute_target(xp)
            lp_acc = xp.lpost - xout.lpost + delta_lp
            accept = (np.log(stats.uniform.rvs(size=self.N)) < lp_acc)
            xout.copyto(xp, where=accept)
            step_ars.append(np.mean(accept))
        xout.acc_rates = self.acc_rates + [step_ars]
        return xout