<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def ner_net(source, destinations, width, height, wrap_around=False, radius=10):
 """Produce a shortest path tree for a given net using NER. This is the kernel of the NER algorithm. Parameters source : (x, y) The coordinate of the source vertex. The coordinates of destination vertices. width : int Width of the system (nodes) height : int Height of the system (nodes) wrap_around : bool True if wrap-around links should be used, false if they should be avoided. radius : int Radius of area to search from each node. 20 is arbitrarily selected in the paper and shown to be acceptable in practice. Returns ------- (:py:class:`~.rig.place_and_route.routing_tree.RoutingTree`, A RoutingTree is produced rooted at the source and visiting all destinations but which does not contain any vertices etc. For convenience, a dictionarry mapping from destination (x, y) coordinates to the associated RoutingTree is provided to allow the caller to insert these items. """

    # Map from (x, y) to RoutingTree objects
    route = {source: RoutingTree(source)}

    # Handle each destination, sorted by distance from the source, closest
    # first.
    for destination in sorted(destinations,
                              key=(lambda destination:
                                   shortest_mesh_path_length(
                                       to_xyz(source), to_xyz(destination))
                                   if not wrap_around else
                                   shortest_torus_path_length(
                                       to_xyz(source), to_xyz(destination),
                                       width, height))):
        # We shall attempt to find our nearest neighbouring placed node.
        neighbour = None

        # Try to find a nearby (within radius hops) node in the routing tree
        # that we can route to (falling back on just routing to the source).
        #
        # In an implementation according to the algorithm's original
        # specification looks for nodes at each point in a growing set of rings
        # of concentric hexagons. If it doesn't find any destinations this
        # means an awful lot of checks: 1261 for the default radius of 20.
        #
        # An alternative (but behaviourally identical) implementation scans the
        # list of all route nodes created so far and finds the closest node
        # which is < radius hops (falling back on the origin if no node is
        # closer than radius hops).  This implementation requires one check per
        # existing route node. In most routes this is probably a lot less than
        # 1261 since most routes will probably have at most a few hundred route
        # nodes by the time the last destination is being routed.
        #
        # Which implementation is best is a difficult question to answer:
        # * In principle nets with quite localised connections (e.g.
        #   nearest-neighbour or centroids traffic) may route slightly more
        #   quickly with the original algorithm since it may very quickly find
        #   a neighbour.
        # * In nets which connect very spaced-out destinations the second
        #   implementation may be quicker since in such a scenario it is
        #   unlikely that a neighbour will be found.
        # * In extremely high-fan-out nets (e.g. broadcasts), the original
        #   method is very likely to perform *far* better than the alternative
        #   method since most iterations will complete immediately while the
        #   alternative method must scan *all* the route vertices.
        # As such, it should be clear that neither method alone is 'best' and
        # both have degenerate performance in certain completely reasonable
        # styles of net. As a result, a simple heuristic is used to decide
        # which technique to use.
        #
        # The following micro-benchmarks are crude estimate of the
        # runtime-per-iteration of each approach (at least in the case of a
        # torus topology)::
        #
        #     $ # Original approach
        #     $ python -m timeit --setup 'x, y, w, h, r = 1, 2, 5, 10, \
        #                                     {x:None for x in range(10)}' \
        #                        'x += 1; y += 1; x %= w; y %= h; (x, y) in r'
        #     1000000 loops, best of 3: 0.207 usec per loop
        #     $ # Alternative approach
        #     $ python -m timeit --setup 'from rig.geometry import \
        #                                 shortest_torus_path_length' \
        #                        'shortest_torus_path_length( \
        #                             (0, 1, 2), (3, 2, 1), 10, 10)'
        #     1000000 loops, best of 3: 0.666 usec per loop
        #
        # From this we can approximately suggest that the alternative approach
        # is 3x more expensive per iteration. A very crude heuristic is to use
        # the original approach when the number of route nodes is more than
        # 1/3rd of the number of routes checked by the original method.
        concentric_hexagons = memoized_concentric_hexagons(radius)
        if len(concentric_hexagons) < len(route) / 3:
            # Original approach: Start looking for route nodes in a concentric
            # spiral pattern out from the destination node.
            for x, y in concentric_hexagons:
                x += destination[0]
                y += destination[1]
                if wrap_around:
                    x %= width
                    y %= height
                if (x, y) in route:
                    neighbour = (x, y)
                    break
        else:
            # Alternative approach: Scan over every route node and check to see
            # if any are < radius, picking the closest one if so.
            neighbour = None
            neighbour_distance = None
            for candidate_neighbour in route:
                if wrap_around:
                    distance = shortest_torus_path_length(
                        to_xyz(candidate_neighbour), to_xyz(destination),
                        width, height)
                else:
                    distance = shortest_mesh_path_length(
                        to_xyz(candidate_neighbour), to_xyz(destination))

                if distance <= radius and (neighbour is None or
                                           distance < neighbour_distance):
                    neighbour = candidate_neighbour
                    neighbour_distance = distance

        # Fall back on routing directly to the source if no nodes within radius
        # hops of the destination was found.
        if neighbour is None:
            neighbour = source

        # Find the shortest vector from the neighbour to this destination
        if wrap_around:
            vector = shortest_torus_path(to_xyz(neighbour),
                                         to_xyz(destination),
                                         width, height)
        else:
            vector = shortest_mesh_path(to_xyz(neighbour), to_xyz(destination))

        # The longest-dimension-first route may inadvertently pass through an
        # already connected node. If the route is allowed to pass through that
        # node it would create a cycle in the route which would be VeryBad(TM).
        # As a result, we work backward through the route and truncate it at
        # the first point where the route intersects with a connected node.
        ldf = longest_dimension_first(vector, neighbour, width, height)
        i = len(ldf)
        for direction, (x, y) in reversed(ldf):
            i -= 1
            if (x, y) in route:
                # We've just bumped into a node which is already part of the
                # route, this becomes our new neighbour and we truncate the LDF
                # route. (Note ldf list is truncated just after the current
                # position since it gives (direction, destination) pairs).
                neighbour = (x, y)
                ldf = ldf[i + 1:]
                break

        # Take the longest dimension first route.
        last_node = route[neighbour]
        for direction, (x, y) in ldf:
            this_node = RoutingTree((x, y))
            route[(x, y)] = this_node

            last_node.children.append((Routes(direction), this_node))
            last_node = this_node

    return (route[source], route)