<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def posterior_marginal(self, idx_param=0, res=100, smoothing=0, range_min=None, range_max=None):
 """ Returns an estimate of the marginal distribution of a given model parameter, based on taking the derivative of the interpolated cdf. :param int idx_param: Index of parameter to be marginalized. :param int res1: Resolution of of the axis. :param float smoothing: Standard deviation of the Gaussian kernel used to smooth; same units as parameter. :param float range_min: Minimum range of the output axis. :param float range_max: Maximum range of the output axis. .. seealso:: :meth:`SMCUpdater.plot_posterior_marginal` """


        # We need to sort the particles to get cumsum to make sense.
        # interp1d would  do it anyways (using argsort, too), so it's not a waste
        s = np.argsort(self.particle_locations[:,idx_param])
        locs = self.particle_locations[s,idx_param]

        # relevant axis discretization
        r_min = np.min(locs) if range_min is None else range_min
        r_max = np.max(locs) if range_max is None else range_max
        ps = np.linspace(r_min, r_max, res)

        # interpolate the cdf of the marginal distribution using cumsum
        interp = scipy.interpolate.interp1d(
            np.append(locs, r_max + np.abs(r_max-r_min)),
            np.append(np.cumsum(self.particle_weights[s]), 1),
            #kind='cubic',
            bounds_error=False,
            fill_value=0,
            assume_sorted=True
        )

        # get distribution from derivative of cdf, and smooth it
        pr = np.gradient(interp(ps), ps[1]-ps[0])
        if smoothing > 0:
            gaussian_filter1d(pr, res*smoothing/(np.abs(r_max-r_min)), output=pr)

        del interp

        return ps, pr