def append_bike_backward(self, g: nx.MultiDiGraph, bss_node: NodeId, orig: NodeId, init_secs: float = 0, init_cost: float = 0):
        for end_node in g.adj[bss_node]:
            edge = g.adj[bss_node][end_node][0]

            secs = edge['length'] / self._bike_speed + init_secs
            cost = edge['length'] * (self._walking_speed / self._bike_speed) + init_cost
            sort_cost = cost + self._get_bike_heuristic_cost(g, end_node, orig)
            edge_status = self._edges_status_bike_backward[EdgeId(bss_node, end_node)]

            if edge_status.is_permanent():
                # if it's permanent is this edge has less cost?
                edge_label_idx = edge_status.edge_label_index
                lab = weakref.proxy(self._edge_labels_bike_backward[edge_status.edge_label_index])
                if lab.end_node == end_node:
                    if cost > lab.cost.cost:
                        continue
                    self._adjacency_list_bike_backward.insert(new_key=sort_cost,
                                                              item=edge_label_idx)
                    lab.pred_idx = -1
                    lab.end_node = end_node
                    lab.cost = Cost(cost, secs, init_cost, init_secs)
                    lab.is_origin = False
                    lab.is_destination = True
            else:
                idx = len(self._edge_labels_bike_backward)
                self._edge_labels_bike_backward.append(EdgeLabel(Cost(cost, secs, init_cost, init_secs),
                                                                 sort_cost,
                                                                 EdgeId(bss_node, end_node),
                                                                 -1,
                                                                 end_node,
                                                                 is_origin=False,
                                                                 is_destination=True))
                self._adjacency_list_bike_backward.insert(sort_cost, idx)
                self._edges_status_bike_backward[EdgeId(bss_node, end_node)] = EdgeStatus(idx).set_temporary()
Beispiel #2
0
    def append_bike(self, g: nx.MultiDiGraph, bss_node: NodeId, init_secs: float=0, init_cost: float=0):
        for end_node in g.adj[bss_node]:
            edge = g.adj[bss_node][end_node][0]

            secs = edge['length'] / self._bike_speed + init_secs
            cost = edge['length'] * (self._walking_speed / self._bike_speed) + init_cost

            # let's see if the edge has already been visited?
            edge_status = self._edges_status_bike[EdgeId(bss_node, end_node)]
            if not edge_status.is_unreached():
                # if it's visted, is this edge had less cost?
                edge_label_idx = edge_status.edge_label_index
                lab = weakref.proxy(self._edge_labels_bike[edge_status.edge_label_index])
                if lab.end_node == end_node:
                    if cost > lab.cost.cost:
                        continue
                    self._adjacency_list_bike.insert(new_key=cost,
                                                     item=edge_label_idx)
                    lab.pred_idx = -1
                    lab.end_node = end_node
                    lab.cost = Cost(cost, secs, init_cost, init_secs)
                    lab.is_origin = True
                    lab.is_destination = False

            else:
                idx = len(self._edge_labels_bike)
                self._edge_labels_bike.append(EdgeLabel(Cost(cost, secs, init_cost, init_secs),
                                                        cost,
                                                        EdgeId(bss_node, end_node),
                                                        -1,
                                                        end_node,
                                                        is_origin=True))
                self._adjacency_list_bike.insert(cost, idx)
                self._edges_status_bike[EdgeId(bss_node, end_node)] = EdgeStatus(idx).set_temporary()
Beispiel #3
0
    def init_backward(self,
                      g: nx.MultiDiGraph,
                      orig: NodeId,
                      dest: NodeId,
                      init_secs: float = 0,
                      init_cost: float = 0):
        for end_node in g.adj[dest]:
            edge = g.adj[dest][end_node][0]

            secs = edge['length'] / self._speed + init_secs
            cost = edge['length'] + init_cost
            sort_cost = cost + self._get_heuristic_cost(g, end_node, orig)

            idx = len(self._edge_labels_backward)
            self._edge_labels_backward.append(
                EdgeLabel(Cost(cost, secs, init_cost, init_secs),
                          sort_cost,
                          EdgeId(dest, end_node),
                          -1,
                          end_node,
                          is_origin=False,
                          is_destination=True))
            self._adjacency_list_backward.insert(sort_cost, idx)
            self._edges_status_backward[EdgeId(
                dest, end_node)] = EdgeStatus(idx).set_temporary()
Beispiel #4
0
    def expand_backward(self, g, node, pred_idx, origin):

        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]
            edge_status = self._get_edge_status_backward(EdgeId(
                node, end_node))

            if edge_status.is_permanent():
                continue

            pred = self._edge_labels_backward[pred_idx]

            new_cost = pred.cost + Cost(edge['length'],
                                        edge['length'] / self._speed)
            edge_id = EdgeId(node, end_node)

            sort_cost = new_cost.cost + self._get_heuristic_cost(
                g, end_node, origin)

            # the edge has been visited
            if edge_status.is_temporary():
                lab = weakref.proxy(
                    self._edge_labels_backward[edge_status.edge_label_index])
                if lab.end_node == end_node:
                    if new_cost < lab.cost:
                        self._adjacency_list_backward.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost

                # Hmmm, we are visiting the edge in the opposing direction of last visit
                elif lab.end_node == node:
                    if new_cost.cost < (lab.cost.cost - edge['length']):
                        self._adjacency_list_backward.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.edge_id = EdgeId(node, end_node)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost
                continue

            idx = len(self._edge_labels_backward)
            self._edge_labels_backward.append(
                EdgeLabel(new_cost, sort_cost, edge_id, pred_idx, end_node))

            self._edges_status_backward[edge_id] = EdgeStatus(
                idx).set_temporary()
            self._adjacency_list_backward.insert(sort_cost, idx)
Beispiel #5
0
    def append_walking(self, g, orig, can_change_mode: bool, init_secs: float=0, init_cost: float=0):
        # init origin
        for end_node in g.adj[orig]:
            edge = g.adj[orig][end_node][0]

            secs = edge['length'] / self._walking_speed + init_secs
            cost = edge['length'] + init_cost
            sort_cost = cost

            # let's see if the edge has already been visited?
            edge_status = self._edges_status_walking[EdgeId(orig, end_node, can_change_mode)]
            if not edge_status.is_unreached():
                # if it's visted, is this edge had less cost?
                edge_label_idx = edge_status.edge_label_index
                lab = weakref.proxy(self._edge_labels_walking[edge_label_idx])
                if lab.end_node == end_node:
                    if cost > lab.cost.cost:
                        continue
                    self._adjacency_list_walking.insert(new_key=cost,
                                                        item=edge_label_idx)
                    lab.pred_idx = -1
                    lab.end_node = end_node
                    lab.cost = Cost(cost, secs, init_cost, init_secs)
                    lab.is_origin = True
                    lab.is_destination = False

            else:
                idx = len(self._edge_labels_walking)
                self._edge_labels_walking.append(EdgeLabel(Cost(cost, secs, init_cost, init_secs),
                                                           sort_cost,
                                                           EdgeId(orig, end_node),
                                                           -1,
                                                           end_node,
                                                           is_origin=True,
                                                           can_change_mode=can_change_mode))
                self._adjacency_list_walking.insert(sort_cost, idx)
                self._edges_status_walking[EdgeId(orig, end_node, can_change_mode)] = EdgeStatus(idx).set_temporary()
Beispiel #6
0
    def expand_walking(self, g: nx.MultiDiGraph, node: NodeId, pred_idx: EdgeLabelIdx):
        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]

            pred = self._edge_labels_walking[pred_idx]

            edge_id = EdgeId(node, end_node, pred.can_change_mode)

            edge_status = self._edges_status_walking[edge_id]

            new_cost = pred.cost + Cost(edge['length'], edge['length'] / self._walking_speed)

            # the edge has been visited
            if not edge_status.is_unreached():
                lab = weakref.proxy(self._edge_labels_walking[edge_status.edge_label_index])
                if lab.end_node == end_node:
                    if new_cost < lab.cost:
                        self._adjacency_list_walking.insert(new_key=new_cost.cost,
                                                            item=edge_status.edge_label_index)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost
                        lab.can_change_mode = pred.can_change_mode

                # Hmmm, we are visiting the edge in the opposing direction of last visit
                elif lab.end_node == node:
                    if new_cost.cost < (lab.cost.cost - edge['length']):
                        self._adjacency_list_walking.insert(new_key=new_cost.cost,
                                                            item=edge_status.edge_label_index)
                        lab.edge_id = EdgeId(node, end_node)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost
                        lab.can_change_mode = pred.can_change_mode

                continue

            idx = len(self._edge_labels_walking)
            self._edge_labels_walking.append(EdgeLabel(new_cost,
                                                       new_cost.cost,
                                                       edge_id,
                                                       pred_idx,
                                                       end_node,
                                                       can_change_mode=pred.can_change_mode))

            self._edges_status_walking[edge_id] = EdgeStatus(idx).set_temporary()
            self._adjacency_list_walking.insert(new_cost.cost, idx)
Beispiel #7
0
    def init_origin(self, g, orig, init_secs=0, init_cost=0):

        # init origin
        for end_node in g.adj[orig]:
            edge = g.adj[orig][end_node][0]

            secs = edge['length'] / self._speed + init_secs
            cost = edge['length'] + init_cost
            sort_cost = cost + self._get_heuristic_cost(
                g, end_node, self._dest)

            idx = len(self._edge_labels)
            self._edge_labels.append(
                EdgeLabel(Cost(cost, secs, init_cost, init_secs), sort_cost,
                          EdgeId(orig, end_node), -1, end_node, True))
            self._adjacency_list.insert(sort_cost, idx)
            self._edges_status[EdgeId(
                orig, end_node)] = EdgeStatus(idx).set_temporary()
    def expand_forward(self, g: nx.MultiDiGraph, node: NodeId, pred_idx: EdgeLabelIdx, dest: NodeId, bss_nodes: Set[NodeId]):

        def _get_speed(travel_mode: TravelMode):
            return (self._walking_speed, self._bike_speed)[travel_mode.value]

        def _normalize_factor(travel_mode: TravelMode):
            return self._walking_speed / (self._walking_speed, self._bike_speed)[travel_mode.value]

        def _get_heurestic_cost(travel_mode: TravelMode, *args, **kwargs):
            fun = (self._get_walking_heuristic_cost, self._get_bike_heuristic_cost)[travel_mode.value]
            return fun(*args, **kwargs)

        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]

            pred = self._edge_labels[pred_idx]

            edge_status = self._get_edge_status(EdgeId(node, end_node, mode=pred.edge_id.mode))

            if node not in bss_nodes and edge_status.is_permanent():
                continue

            if node not in bss_nodes and not edge_status.is_permanent():
                new_cost = pred.cost + Cost(edge['length'] * _normalize_factor(pred.edge_id.mode),
                                            edge['length'] / _get_speed(pred.edge_id.mode))
                edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                sort_cost = new_cost.cost + _get_heurestic_cost(pred.edge_id.mode, g, end_node, dest)
                # the edge has been visited
                if edge_status.is_temporary():
                    lab = weakref.proxy(self._edge_labels[edge_status.edge_label_index])
                    if lab.end_node == end_node:
                        if new_cost < lab.cost:
                            self._adjacency_list.insert(new_key=sort_cost,
                                                        item=edge_status.edge_label_index)
                            lab.edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                            lab.pred_idx = pred_idx
                            lab.end_node = end_node
                            lab.cost = new_cost

                    # Hmmm, we are visiting the edge in the opposing direction of last visit
                    elif lab.end_node == node:
                        if new_cost.cost < (lab.cost.cost - edge['length'] * _normalize_factor(pred.edge_id.mode)):
                            self._adjacency_list.insert(new_key=sort_cost,
                                                        item=edge_status.edge_label_index)
                            lab.edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                            lab.pred_idx = pred_idx
                            lab.end_node = end_node
                            lab.cost = new_cost
                    continue

                idx = len(self._edge_labels)
                self._edge_labels.append(EdgeLabel(new_cost,
                                                   sort_cost,
                                                   edge_id,
                                                   pred_idx,
                                                   end_node))
                self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()
                self._adjacency_list.insert(sort_cost, idx)

            if node in bss_nodes:
                for mode in TravelMode:
                    edge_status = self._get_edge_status(EdgeId(node, end_node, mode=mode))

                    if edge_status.is_permanent():
                        continue
                    new_cost = pred.cost + Cost(edge['length'] * _normalize_factor(mode),
                                                edge['length'] / _get_speed(mode))

                    edge_id = EdgeId(node, end_node, mode)
                    if mode == TravelMode.WALKING:
                        sort_cost = new_cost.cost + self._get_walking_heuristic_cost(g, end_node, dest)
                    else:
                        sort_cost = new_cost.cost + self._get_bike_heuristic_cost(g, end_node, dest)

                    # the edge has been visited
                    if edge_status.is_temporary():
                        lab = weakref.proxy(self._edge_labels[edge_status.edge_label_index])
                        if lab.end_node == end_node:
                            if new_cost < lab.cost:
                                self._adjacency_list.insert(new_key=sort_cost,
                                                            item=edge_status.edge_label_index)
                                # lab.edge_id = EdgeId(node, end_node, mode)
                                lab.pred_idx = pred_idx
                                lab.end_node = end_node
                                lab.cost = new_cost
                        # Hmmm, we are visiting the edge in the opposing direction of last visit
                        elif lab.end_node == node:
                            if new_cost.cost < (lab.cost.cost - edge['length'] * _normalize_factor(mode)):
                                self._adjacency_list.insert(new_key=sort_cost,
                                                            item=edge_status.edge_label_index)
                                # lab.edge_id = EdgeId(node, end_node, mode)
                                lab.pred_idx = pred_idx
                                lab.end_node = end_node
                                lab.cost = new_cost
                        continue

                    idx = len(self._edge_labels)
                    self._edge_labels.append(EdgeLabel(new_cost,
                                                       sort_cost,
                                                       edge_id,
                                                       pred_idx,
                                                       end_node))
                    self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()
                    self._adjacency_list.insert(sort_cost, idx)
class MultiModalDoubleExpansionAStarOneQueue(object):

    _edge_labels: List[EdgeLabel] = field(default_factory=list)
    _adjacency_list: PriorityQueue = PriorityQueue()
    _edges_status: Dict[EdgeId, EdgeStatus] = field(default_factory=lambda: defaultdict(EdgeStatus))

    _cost_factor: float = 0

    _walking_speed: float = WALKING_SPEED
    _bike_speed: float = BIKE_SPEED

    _threshold: float = float('inf')

    _destinations: Dict[EdgeId, BestPath] = field(default_factory=dict)

    _best_path: BestPath = BestPath(-1, Cost(0, 0))

    @staticmethod
    def _get_heuristic_cost_impl(g: nx.MultiDiGraph, start_node: NodeId, end_node: NodeId, cost_factor: float) -> float:
        if cost_factor == 0 or end_node is None:
            return 0
        start_ll = utils.osm_to_pointll(g, start_node)
        end_ll = utils.osm_to_pointll(g, end_node)
        return start_ll.distance_to(end_ll) * cost_factor

    def _get_walking_heuristic_cost(self, g: nx.MultiDiGraph, start_node: NodeId, end_node: NodeId) -> float:
        return self._get_heuristic_cost_impl(g, start_node, end_node, self._cost_factor)

    def _get_bike_heuristic_cost(self, g: nx.MultiDiGraph, start_node: NodeId, end_node: NodeId) -> float:
        return self._get_heuristic_cost_impl(g, start_node, end_node, self._cost_factor) * 1.2 * (self._walking_speed / self._bike_speed)

    @staticmethod
    def _get_edge_status_impl(container: Dict[EdgeId, EdgeStatus], edge_id: EdgeId) -> EdgeStatus:
        s = container.get(edge_id)
        if not s:
            return container[edge_id].set_unreached()
        return s

    def _get_edge_status(self, edge_id: EdgeId) -> EdgeStatus:
        return self._get_edge_status_impl(self._edges_status, edge_id)

    def init_origin(self, g: nx.MultiDiGraph, orig: NodeId, dest: NodeId, init_secs: float = 0, init_cost: float = 0):
        for end_node in g.adj[orig]:
            edge = g.adj[orig][end_node][0]

            secs = edge['length'] / self._walking_speed + init_secs
            cost = edge['length'] + init_cost
            sort_cost = cost + self._get_walking_heuristic_cost(g, end_node, dest)

            idx = len(self._edge_labels)
            self._edge_labels.append(EdgeLabel(Cost(cost, secs, init_cost, init_secs),
                                               sort_cost,
                                               EdgeId(orig, end_node),
                                               -1,
                                               end_node,
                                               is_origin=True,
                                               is_destination=False))
            self._adjacency_list.insert(sort_cost, idx)
            self._edges_status[EdgeId(orig, end_node)] = EdgeStatus(idx).set_temporary()

    def init_destination(self,  g: nx.MultiDiGraph, dest: NodeId):
        # init destination
        for end_node in g.adj[dest]:
            edge = g.adj[dest][end_node][0]
            self._destinations[EdgeId(dest, end_node, mode=TravelMode.WALKING)] = edge['length']

    def expand_forward(self, g: nx.MultiDiGraph, node: NodeId, pred_idx: EdgeLabelIdx, dest: NodeId, bss_nodes: Set[NodeId]):

        def _get_speed(travel_mode: TravelMode):
            return (self._walking_speed, self._bike_speed)[travel_mode.value]

        def _normalize_factor(travel_mode: TravelMode):
            return self._walking_speed / (self._walking_speed, self._bike_speed)[travel_mode.value]

        def _get_heurestic_cost(travel_mode: TravelMode, *args, **kwargs):
            fun = (self._get_walking_heuristic_cost, self._get_bike_heuristic_cost)[travel_mode.value]
            return fun(*args, **kwargs)

        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]

            pred = self._edge_labels[pred_idx]

            edge_status = self._get_edge_status(EdgeId(node, end_node, mode=pred.edge_id.mode))

            if node not in bss_nodes and edge_status.is_permanent():
                continue

            if node not in bss_nodes and not edge_status.is_permanent():
                new_cost = pred.cost + Cost(edge['length'] * _normalize_factor(pred.edge_id.mode),
                                            edge['length'] / _get_speed(pred.edge_id.mode))
                edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                sort_cost = new_cost.cost + _get_heurestic_cost(pred.edge_id.mode, g, end_node, dest)
                # the edge has been visited
                if edge_status.is_temporary():
                    lab = weakref.proxy(self._edge_labels[edge_status.edge_label_index])
                    if lab.end_node == end_node:
                        if new_cost < lab.cost:
                            self._adjacency_list.insert(new_key=sort_cost,
                                                        item=edge_status.edge_label_index)
                            lab.edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                            lab.pred_idx = pred_idx
                            lab.end_node = end_node
                            lab.cost = new_cost

                    # Hmmm, we are visiting the edge in the opposing direction of last visit
                    elif lab.end_node == node:
                        if new_cost.cost < (lab.cost.cost - edge['length'] * _normalize_factor(pred.edge_id.mode)):
                            self._adjacency_list.insert(new_key=sort_cost,
                                                        item=edge_status.edge_label_index)
                            lab.edge_id = EdgeId(node, end_node, pred.edge_id.mode)
                            lab.pred_idx = pred_idx
                            lab.end_node = end_node
                            lab.cost = new_cost
                    continue

                idx = len(self._edge_labels)
                self._edge_labels.append(EdgeLabel(new_cost,
                                                   sort_cost,
                                                   edge_id,
                                                   pred_idx,
                                                   end_node))
                self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()
                self._adjacency_list.insert(sort_cost, idx)

            if node in bss_nodes:
                for mode in TravelMode:
                    edge_status = self._get_edge_status(EdgeId(node, end_node, mode=mode))

                    if edge_status.is_permanent():
                        continue
                    new_cost = pred.cost + Cost(edge['length'] * _normalize_factor(mode),
                                                edge['length'] / _get_speed(mode))

                    edge_id = EdgeId(node, end_node, mode)
                    if mode == TravelMode.WALKING:
                        sort_cost = new_cost.cost + self._get_walking_heuristic_cost(g, end_node, dest)
                    else:
                        sort_cost = new_cost.cost + self._get_bike_heuristic_cost(g, end_node, dest)

                    # the edge has been visited
                    if edge_status.is_temporary():
                        lab = weakref.proxy(self._edge_labels[edge_status.edge_label_index])
                        if lab.end_node == end_node:
                            if new_cost < lab.cost:
                                self._adjacency_list.insert(new_key=sort_cost,
                                                            item=edge_status.edge_label_index)
                                # lab.edge_id = EdgeId(node, end_node, mode)
                                lab.pred_idx = pred_idx
                                lab.end_node = end_node
                                lab.cost = new_cost
                        # Hmmm, we are visiting the edge in the opposing direction of last visit
                        elif lab.end_node == node:
                            if new_cost.cost < (lab.cost.cost - edge['length'] * _normalize_factor(mode)):
                                self._adjacency_list.insert(new_key=sort_cost,
                                                            item=edge_status.edge_label_index)
                                # lab.edge_id = EdgeId(node, end_node, mode)
                                lab.pred_idx = pred_idx
                                lab.end_node = end_node
                                lab.cost = new_cost
                        continue

                    idx = len(self._edge_labels)
                    self._edge_labels.append(EdgeLabel(new_cost,
                                                       sort_cost,
                                                       edge_id,
                                                       pred_idx,
                                                       end_node))
                    self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()
                    self._adjacency_list.insert(sort_cost, idx)

    def make_osm_path(self) -> Tuple[List[List[NodeId]], float]:
        # build path from the last walking

        second_walking = []
        bike = []
        first_walking = []

        edge_label_idx = self._best_path.edge_label_index
        edge_label = self._edge_labels[edge_label_idx]
        second_walking.append(edge_label.end_node)

        changed_mode = 0
        old_mode = edge_label.edge_id.mode

        while not edge_label.is_origin:

            edge_label_idx = edge_label.pred_idx
            edge_label = self._edge_labels[edge_label_idx]

            if old_mode != edge_label.edge_id.mode:
                changed_mode += 1
                old_mode = edge_label.edge_id.mode

            if changed_mode == 0:
                second_walking.append(edge_label.end_node)
            elif changed_mode == 1:
                if not bike:
                    second_walking.append(edge_label.end_node)
                bike.append(edge_label.end_node)
            elif changed_mode == 2:
                if not first_walking:
                    bike.append(edge_label.end_node)
                first_walking.append(edge_label.end_node)

        first_walking.append(edge_label.edge_id.start)

        first_walking = first_walking[::-1]
        bike = bike[::-1]

        second_walking = second_walking[::-1]

        res = []

        if first_walking and bike:
            res.append(first_walking)
            res.append(bike)

        res.append(second_walking)
        return res, self._best_path.cost.secs

    def get_best_path(self,
                      g: nx.MultiDiGraph,
                      orig: NodeId,
                      dest: NodeId,
                      bss_nodes: Set[NodeId],
                      callback: Callable = lambda *args, **kwargs: None) -> Tuple[List[List[NodeId]], float]:

        self.init_origin(g, orig, dest)
        self.init_destination(g, dest)

        i = 0
        a = 0
        # begin search
        while True:
            if i % 10 == 0 and 0:
                callback(g, orig, dest, bss_nodes, self._edges_status, self._edge_labels, str(a).zfill(4))
                a += 1
            i += 1

            current_labels = len(self._edge_labels)

            if current_labels > PriorityQueue.QUEUE_MAX_SIZE:
                return []

            _, pred_index = self._adjacency_list.pop()
            pred_edge_label = self._edge_labels[pred_index]

            # Do we touch the destination?
            d = self._destinations.get(pred_edge_label.edge_id)
            if d:
                if self._best_path.edge_label_index is -1:
                    self._best_path.edge_label_index = pred_index
                    self._best_path.cost = pred_edge_label.cost
                return self.make_osm_path()

            if not pred_edge_label.is_origin:
                self._edges_status[pred_edge_label.edge_id].set_permanent()

            self.expand_forward(g, pred_edge_label.end_node, pred_index, dest, bss_nodes)
Beispiel #10
0
    def expand_forward(self, g, node, pred_idx, dest):

        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]
            edge_status = self._get_edge_status(EdgeId(node, end_node))

            if edge_status.is_permanent():
                continue

            pred = self._edge_labels[pred_idx]

            new_cost = pred.cost + Cost(edge['length'],
                                        edge['length'] / self._speed)

            edge_id = EdgeId(node, end_node)

            d = self._destinations.get(edge_id)
            if d is not None:
                if self._best_path.edge_label_index is -1 or new_cost < self._best_path.cost:
                    self._best_path.edge_label_index = edge_status.edge_label_index if edge_status.is_temporary() \
                                                                              else len(self._edge_labels)
                    self._best_path.cost = new_cost

            sort_cost = new_cost.cost + self._get_heuristic_cost(
                g, end_node, self._dest)

            # the edge has been visited
            if edge_status.is_temporary():
                lab = weakref.proxy(
                    self._edge_labels[edge_status.edge_label_index])
                #   Edge:
                #             4242   -------------  4141
                #              start       ->        end
                #                         or
                #               end        <-       start

                # the edge may have been visited either from its start or end,
                # let's find out in this case which one is "cheaper"

                # OK, we are visiting the edge at the same direction of last visit, nothing
                # to be done
                if lab.end_node == end_node:
                    if new_cost < lab.cost:
                        self._adjacency_list.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost

                # Hmmm, we are visiting the edge in the opposing direction of last visit
                elif lab.end_node == node:
                    if new_cost.cost < (lab.cost.cost - edge['length']):
                        self._adjacency_list.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.edge_id = EdgeId(node, end_node)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost

                continue

            idx = len(self._edge_labels)
            self._edge_labels.append(
                EdgeLabel(new_cost, sort_cost, edge_id, pred_idx, end_node))

            self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()

            self._adjacency_list.insert(sort_cost, idx)
Beispiel #11
0
 def init(self):
     self._edge_labels = []
     self._destinations = defaultdict(Cost)
     self._adjacency_list = PriorityQueue()
     self._edges_status = defaultdict(EdgeStatus)
     self._best_path = BestPath(-1, Cost(0, 0))
Beispiel #12
0
class AStar(object):
    _edge_labels: List[EdgeLabel]
    _destinations: Dict[EdgeId, Cost]
    _adjacency_list: PriorityQueue
    _edges_status: Dict[EdgeId, EdgeStatus]
    _orig: NodeId = -1
    _dest: NodeId = -1
    _cost_factor: float = 0.4
    _best_path: BestPath = BestPath(-1, Cost(0, 0))
    _speed: float = 1.4

    def init(self):
        self._edge_labels = []
        self._destinations = defaultdict(Cost)
        self._adjacency_list = PriorityQueue()
        self._edges_status = defaultdict(EdgeStatus)
        self._best_path = BestPath(-1, Cost(0, 0))

    def __init__(self, speed=1.4, cost_factor=0.4):
        self.init()
        self._speed = speed
        self._cost_factor = cost_factor

    def _get_edge_cost(self, label):
        return self._edge_labels[label]

    def _get_edge_status(self, edge_id: EdgeId) -> EdgeStatus:
        s = self._edges_status.get(edge_id)
        if not s:
            return self._edges_status[edge_id].set_unreached()
        return s

    def _get_heuristic_cost(self, g: nx.MultiDiGraph, start_node: NodeId,
                            end_node: NodeId) -> float:
        if self._cost_factor == 0 or end_node is None:
            return 0
        start_ll = osm_to_pointll(g, start_node)
        end_ll = osm_to_pointll(g, end_node)
        return start_ll.distance_to(end_ll) * self._cost_factor

    def expand_forward(self, g, node, pred_idx, dest):

        for end_node in g.adj[node]:
            edge = g.adj[node][end_node][0]
            edge_status = self._get_edge_status(EdgeId(node, end_node))

            if edge_status.is_permanent():
                continue

            pred = self._edge_labels[pred_idx]

            new_cost = pred.cost + Cost(edge['length'],
                                        edge['length'] / self._speed)

            edge_id = EdgeId(node, end_node)

            d = self._destinations.get(edge_id)
            if d is not None:
                if self._best_path.edge_label_index is -1 or new_cost < self._best_path.cost:
                    self._best_path.edge_label_index = edge_status.edge_label_index if edge_status.is_temporary() \
                                                                              else len(self._edge_labels)
                    self._best_path.cost = new_cost

            sort_cost = new_cost.cost + self._get_heuristic_cost(
                g, end_node, self._dest)

            # the edge has been visited
            if edge_status.is_temporary():
                lab = weakref.proxy(
                    self._edge_labels[edge_status.edge_label_index])
                #   Edge:
                #             4242   -------------  4141
                #              start       ->        end
                #                         or
                #               end        <-       start

                # the edge may have been visited either from its start or end,
                # let's find out in this case which one is "cheaper"

                # OK, we are visiting the edge at the same direction of last visit, nothing
                # to be done
                if lab.end_node == end_node:
                    if new_cost < lab.cost:
                        self._adjacency_list.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost

                # Hmmm, we are visiting the edge in the opposing direction of last visit
                elif lab.end_node == node:
                    if new_cost.cost < (lab.cost.cost - edge['length']):
                        self._adjacency_list.insert(
                            new_key=sort_cost,
                            item=edge_status.edge_label_index)
                        lab.edge_id = EdgeId(node, end_node)
                        lab.pred_idx = pred_idx
                        lab.end_node = end_node
                        lab.cost = new_cost

                continue

            idx = len(self._edge_labels)
            self._edge_labels.append(
                EdgeLabel(new_cost, sort_cost, edge_id, pred_idx, end_node))

            self._edges_status[edge_id] = EdgeStatus(idx).set_temporary()

            self._adjacency_list.insert(sort_cost, idx)

    def make_osm_path(self):
        res = []

        edge_label_idx = self._best_path.edge_label_index
        edge_label = self._edge_labels[edge_label_idx]
        res.append(edge_label.end_node)

        while not edge_label.is_origin:
            edge_label_idx = edge_label.pred_idx
            edge_label = self._edge_labels[edge_label_idx]
            res.append(edge_label.end_node)

        res.append(edge_label.edge_id.start)

        res = res[::-1]
        return res, self._best_path.cost.secs

    def init_origin(self, g, orig, init_secs=0, init_cost=0):

        # init origin
        for end_node in g.adj[orig]:
            edge = g.adj[orig][end_node][0]

            secs = edge['length'] / self._speed + init_secs
            cost = edge['length'] + init_cost
            sort_cost = cost + self._get_heuristic_cost(
                g, end_node, self._dest)

            idx = len(self._edge_labels)
            self._edge_labels.append(
                EdgeLabel(Cost(cost, secs, init_cost, init_secs), sort_cost,
                          EdgeId(orig, end_node), -1, end_node, True))
            self._adjacency_list.insert(sort_cost, idx)
            self._edges_status[EdgeId(
                orig, end_node)] = EdgeStatus(idx).set_temporary()

    def get_best_path(
        self,
        g: nx.MultiDiGraph,
        orig: NodeId,
        dest: NodeId,
        callback: Callable = lambda *args, **kwargs: None
    ) -> Tuple[List[NodeId], float]:

        self._orig = orig
        self._dest = dest

        self.init()

        self.init_origin(g, orig)

        # init destination
        for end_node in g.adj[dest]:
            edge = g.adj[dest][end_node][0]
            self._destinations[EdgeId(dest, end_node)] = edge['length']

        i = 0
        a = 0
        # begin search
        while True:
            if i % 200 == 0:
                callback(g, orig, dest, self._edges_status, self._edge_labels,
                         str(a).zfill(4))
                a += 1
            i += 1

            current_labels = len(self._edge_labels)

            if current_labels > PriorityQueue.QUEUE_MAX_SIZE:
                return []

            _, pred_index = self._adjacency_list.pop()
            pred_edge_label = self._edge_labels[pred_index]

            # Do we touch the destination?
            d = self._destinations.get(pred_edge_label.edge_id)
            if d:
                if self._best_path.edge_label_index is -1:
                    self._best_path.edge_label_index = pred_index
                    self._best_path.cost = pred_edge_label.cost

                return self.make_osm_path()

            if not pred_edge_label.is_origin:
                self._edges_status[pred_edge_label.edge_id].set_permanent()

            self.expand_forward(g, pred_edge_label.end_node, pred_index, dest)