<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def cone_beam_geometry(space, src_radius, det_radius, num_angles=None, short_scan=False, det_shape=None):
 r"""Create a default fan or cone beam geometry from ``space``. This function is intended for simple test cases where users do not need the full flexibility of the geometries, but simply wants a geometry that works. The geometry returned by this function has equidistant angles that lie (strictly) between 0 and either ``2 * pi`` (full scan) or ``pi + fan_angle`` (short scan). The detector is centered around 0, and its size is chosen such that the whole ``space`` is covered with lines. The number of angles and detector elements is chosen such that the resulting sinogram is fully sampled according to the Nyquist criterion, which in general results in a very large number of samples. In particular, a ``space`` that is not centered at the origin can result in very large detectors since the latter is always origin-centered. Parameters space : `DiscreteLp` Reconstruction space, the space of the volumetric data to be projected. Must be 2- or 3-dimensional. src_radius : nonnegative float Radius of the source circle. Must be larger than the radius of the smallest vertical cylinder containing ``space.domain``, i.e., the source must be outside the volume for all rotations. det_radius : nonnegative float Radius of the detector circle. short_scan : bool, optional Use the minimum required angular range ``[0, pi + fan_angle]``. For ``True``, the `parker_weighting` should be used in FBP. By default, the range ``[0, 2 * pi]`` is used. num_angles : int, optional Number of angles. Default: Enough to fully sample the data, see Notes. det_shape : int or sequence of ints, optional Number of detector pixels. Default: Enough to fully sample the data, see Notes. Returns ------- geometry : `DivergentBeamGeometry` Projection geometry with equidistant angles and zero-centered detector as determined by sampling criteria. - If ``space`` is 2D, the result is a `FanBeamGeometry`. - If ``space`` is 3D, the result is a `ConeFlatGeometry`. Examples -------- Create a fan beam geometry from a 2d space: 78 57 For a short scan geometry (from 0 to ``pi + fan_angle``), the ``short_scan`` flag can be set, resulting in a smaller number of angles: 46 If the source is close to the object, the detector becomes larger due to more magnification: 80 105 Notes ----- According to [NW2001]_, pages 75--76, a function :math:`f : \mathbb{R}^2 \to \mathbb{R}` that has compact support .. math:: \| x \| > \rho \implies f(x) = 0, and is essentially bandlimited .. math:: \| \xi \| > \Omega \implies \hat{f}(\xi) \approx 0, can be fully reconstructed from a fan beam ray transform with source-detector distance :math:`r` (assuming all detector points have the same distance to the source) if (1) the projection angles are sampled with a spacing of :math:`\Delta \psi` such that .. math:: \Delta \psi \leq \frac{r + \rho}{r}\, \frac{\pi}{\rho \Omega}, and (2) the detector is sampled with an angular interval :math:`\Delta \alpha` that satisfies .. math:: \Delta \alpha \leq \frac{\pi}{r \Omega}. For a flat detector, the angular interval is smallest in the center of the fan and largest at the boundaries. The worst-case relation between the linear and angular sampling intervals are .. math:: \Delta s = R \Delta \alpha, \quad R^2 = r^2 + (w / 2)^2, where :math:`w` is the width of the detector. Thus, to satisfy the angular detector condition one can choose .. math:: \Delta s \leq \frac{\pi \sqrt{r^2 + (w / 2)^2}}{r \Omega}. The geometry returned by this function satisfies these conditions exactly. If the domain is 3-dimensional, a circular cone beam geometry is created with the third coordinate axis as rotation axis. This does, of course, not yield complete data, but is equivalent to the 2D fan beam case in the :math:`z = 0` slice. The vertical size of the detector is chosen such that it covers the object vertically with rays, using a containing cuboid :math:`[-\rho, \rho]^2 \times [z_{\mathrm{min}}, z_{\mathrm{min}}]` to compute the cone angle. References .. [NW2001] Natterer, F and Wuebbeling, F. *Mathematical Methods in Image Reconstruction*. SIAM, 2001. https://dx.doi.org/10.1137/1.9780898718324 """

    # Find maximum distance from rotation axis
    corners = space.domain.corners()[:, :2]
    rho = np.max(np.linalg.norm(corners, axis=1))

    # Find default values according to Nyquist criterion.

    # We assume that the function is bandlimited by a wave along the x or y
    # axis. The highest frequency we can measure is then a standing wave with
    # period of twice the inter-node distance.
    min_side = min(space.partition.cell_sides[:2])
    omega = np.pi / min_side

    # Compute minimum width of the detector to cover the object. The relation
    # used here is (w/2)/(rs+rd) = rho/rs since both are equal to tan(alpha),
    # where alpha is the half fan angle.
    rs = float(src_radius)
    if (rs <= rho):
        raise ValueError('source too close to the object, resulting in '
                         'infinite detector for full coverage')
    rd = float(det_radius)
    r = src_radius + det_radius
    w = 2 * rho * (rs + rd) / rs

    # Compute minimum number of pixels given the constraint on the
    # sampling interval and the computed width
    rb = np.hypot(r, w / 2)  # length of the boundary ray to the flat detector
    num_px_horiz = 2 * int(np.ceil(w * omega * r / (2 * np.pi * rb))) + 1

    if space.ndim == 2:
        det_min_pt = -w / 2
        det_max_pt = w / 2
        if det_shape is None:
            det_shape = num_px_horiz
    elif space.ndim == 3:
        # Compute number of vertical pixels required to cover the object,
        # using the same sampling interval vertically as horizontally.
        # The reasoning is the same as for the computation of w.

        # Minimum distance of the containing cuboid edges to the source
        dist = rs - rho
        # Take angle of the rays going through the top and bottom corners
        # in that edge
        half_cone_angle = max(np.arctan(abs(space.partition.min_pt[2]) / dist),
                              np.arctan(abs(space.partition.max_pt[2]) / dist))
        h = 2 * np.sin(half_cone_angle) * (rs + rd)

        # Use the vertical spacing from the reco space, corrected for
        # magnification at the "back" of the object, i.e., where it is
        # minimal
        min_mag = (rs + rd) / (rs + rho)
        delta_h = min_mag * space.cell_sides[2]
        num_px_vert = int(np.ceil(h / delta_h))
        h = num_px_vert * delta_h  # make multiple of spacing

        det_min_pt = [-w / 2, -h / 2]
        det_max_pt = [w / 2, h / 2]
        if det_shape is None:
            det_shape = [num_px_horiz, num_px_vert]

    fan_angle = 2 * np.arctan(rho / rs)
    if short_scan:
        max_angle = min(np.pi + fan_angle, 2 * np.pi)
    else:
        max_angle = 2 * np.pi

    if num_angles is None:
        num_angles = int(np.ceil(max_angle * omega * rho / np.pi
                                 * r / (r + rho)))

    angle_partition = uniform_partition(0, max_angle, num_angles)
    det_partition = uniform_partition(det_min_pt, det_max_pt, det_shape)

    if space.ndim == 2:
        return FanBeamGeometry(angle_partition, det_partition,
                               src_radius, det_radius)
    elif space.ndim == 3:
        return ConeFlatGeometry(angle_partition, det_partition,
                                src_radius, det_radius)
    else:
        raise ValueError('``space.ndim`` must be 2 or 3.')