<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def uniform_partition_fromgrid(grid, min_pt=None, max_pt=None):
 """Return a partition of an interval product based on a given grid. This method is complementary to `uniform_partition_fromintv` in that it infers the set to be partitioned from a given grid and optional parameters for ``min_pt`` and ``max_pt`` of the set. Parameters grid : `RectGrid` Grid on which the partition is based min_pt, max_pt : float, sequence of floats, or dict, optional Spatial points defining the lower/upper limits of the intervals to be partitioned. The points can be specified in two ways: float or sequence: The values are used directly as ``min_pt`` and/or ``max_pt``. dict: Index-value pairs specifying an axis and a spatial coordinate to be used in that axis. In axes which are not a key in the dictionary, the coordinate for the vector is calculated as:: min_pt = x[0] - (x[1] - x[0]) / 2 max_pt = x[-1] + (x[-1] - x[-2]) / 2 See ``Examples`` below. In general, ``min_pt`` may not be larger than ``grid.min_pt``, and ``max_pt`` not smaller than ``grid.max_pt`` in any component. ``None`` is equivalent to an empty dictionary, i.e. the values are calculated in each dimension. See Also -------- uniform_partition_fromintv Examples -------- Have ``min_pt`` and ``max_pt`` of the bounding box automatically calculated: (array([ 0. , 0.5, 1. ]),) (array([-0.25, 0.25, 0.75, 1.25]),) ``min_pt`` and ``max_pt`` can be given explicitly: (array([ 0. , 0.25, 0.75, 1. ]),) Using dictionaries, selective axes can be explicitly set. The keys refer to axes, the values to the coordinates to use: array([-1. , 0.25, 0.75, 1.25]) array([-0.25, 0.25, 0.75, 3. ]) """

    # Make dictionaries from `min_pt` and `max_pt` and fill with `None` where
    # no value is given (taking negative indices into account)
    if min_pt is None:
        min_pt = {i: None for i in range(grid.ndim)}
    elif not hasattr(min_pt, 'items'):  # array-like
        min_pt = np.atleast_1d(min_pt)
        min_pt = {i: float(v) for i, v in enumerate(min_pt)}
    else:
        min_pt.update({i: None for i in range(grid.ndim)
                       if i not in min_pt and i - grid.ndim not in min_pt})

    if max_pt is None:
        max_pt = {i: None for i in range(grid.ndim)}
    elif not hasattr(max_pt, 'items'):
        max_pt = np.atleast_1d(max_pt)
        max_pt = {i: float(v) for i, v in enumerate(max_pt)}
    else:
        max_pt.update({i: None for i in range(grid.ndim)
                      if i not in max_pt and i - grid.ndim not in max_pt})

    # Set the values in the vectors by computing (None) or directly from the
    # given vectors (otherwise).
    min_pt_vec = np.empty(grid.ndim)
    for ax, xmin in min_pt.items():
        if xmin is None:
            cvec = grid.coord_vectors[ax]
            if len(cvec) == 1:
                raise ValueError('in axis {}: cannot calculate `min_pt` with '
                                 'only 1 grid point'.format(ax))
            min_pt_vec[ax] = cvec[0] - (cvec[1] - cvec[0]) / 2
        else:
            min_pt_vec[ax] = xmin

    max_pt_vec = np.empty(grid.ndim)
    for ax, xmax in max_pt.items():
        if xmax is None:
            cvec = grid.coord_vectors[ax]
            if len(cvec) == 1:
                raise ValueError('in axis {}: cannot calculate `max_pt` with '
                                 'only 1 grid point'.format(ax))
            max_pt_vec[ax] = cvec[-1] + (cvec[-1] - cvec[-2]) / 2
        else:
            max_pt_vec[ax] = xmax

    return RectPartition(IntervalProd(min_pt_vec, max_pt_vec), grid)