<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def rdp(M, epsilon=0, dist=pldist, algo="iter", return_mask=False):
 """ Simplifies a given array of points using the Ramer-Douglas-Peucker algorithm. Example: [[1, 1], [4, 4]] This is a convenience wrapper around both :func:`rdp.rdp_iter` and :func:`rdp.rdp_rec` that detects if the input is a numpy array in order to adapt the output accordingly. This means that when it is called using a Python list as argument, a Python list is returned, and in case of an invocation using a numpy array, a NumPy array is returned. The parameter ``return_mask=True`` can be used in conjunction with ``algo="iter"`` to return only the mask of points to keep. Example: array([[1, 1], [2, 2], [3, 3], [4, 4]]) array([ True, False, False, True], dtype=bool) array([[1, 1], [4, 4]]) :param M: a series of points :type M: numpy array with shape ``(n,d)`` where ``n`` is the number of points and ``d`` their dimension :param epsilon: epsilon in the rdp algorithm :type epsilon: float :param dist: distance function :type dist: function with signature ``f(point, start, end)`` -- see :func:`rdp.pldist` :param algo: either ``iter`` for an iterative algorithm or ``rec`` for a recursive algorithm :type algo: string :param return_mask: return mask instead of simplified array :type return_mask: bool """


    if algo == "iter":
        algo = partial(rdp_iter, return_mask=return_mask)
    elif algo == "rec":
        if return_mask:
            raise NotImplementedError("return_mask=True not supported with algo=\"rec\"")
        algo = rdp_rec
        
    if "numpy" in str(type(M)):
        return algo(M, epsilon, dist)

    return algo(np.array(M), epsilon, dist).tolist()