示例#1
0
    def update_anchors(self, custom=None):

        if custom:
            clusters = custom
        else:
            clusters = self.clusters

        if not self.hub.cells:
            for clust in clusters:
                clust.anchor = None
        else:
            for clust in clusters:
                if not clust.cells:
                    continue

                # Find node in the hub that is closest to one in the cluster
                _, anchor = closest_nodes(clust, self.hub)
                clust.anchor = anchor
示例#2
0
    def optimize_large_ec(self):

        for r in range(101):
            logger.debug("Starting round %d of Ec >> Em", r)

            if r > 100:
                raise LoafError("Optimization got lost")

            balance = self.energy_balance()
            logger.debug("Current energy balance is %f", balance)

            c_most = self.highest_energy_cluster(include_hub=False)

            # get the neighbors of c_most
            neighbors = [
                c for c in self.clusters
                if (abs(c.cluster_id - c_most.cluster_id) == 1) or (
                    abs(c.cluster_id -
                        c_most.cluster_id) == self.env.mdc_count - 2)
            ]

            assert (len(neighbors) <= 2) and (len(neighbors) > 0)

            # find the minimum energy neighbor
            neighbor = min(neighbors,
                           key=lambda x: self.total_cluster_energy(x))

            # find the cell in c_most nearest the neighbor
            c_out, _ = closest_nodes(c_most, neighbor)

            c_most.remove(c_out)
            neighbor.add(c_out)

            # emulate a do ... while loop
            stdev_new = self.energy_balance()
            logger.debug("Completed %d rounds of Ec >> Em", r + 1)

            # if this round didn't reduce balance, then revert the changes and
            # exit the loop
            if stdev_new >= balance:
                neighbor.remove(c_out)
                c_most.add(c_out)
                break
示例#3
0
    def optimization(self):

        for r in range(101):

            logger.debug("Starting round %d of optimization", r)

            if r > 100:
                raise LoafError("Optimization got lost")

            balance = self.energy_balance()
            c_least = self.lowest_energy_cluster()
            c_most = self.highest_energy_cluster()

            if self.hub == c_least:
                _, c_in = closest_nodes([c_most.anchor], c_most)

                c_most.remove(c_in)
                self.hub.add(c_in)

                # check the effects and revert if necessary
                self.update_anchors()
                new_balance = self.energy_balance()
                logger.debug("Completed %d rounds of 2b", r)

                # if this round didn't reduce stdev, then revert the changes
                # and exit the loop
                if new_balance >= balance:
                    self.hub.remove(c_in)
                    c_most.add(c_in)
                    self.update_anchors()
                    break

            elif self.hub == c_most:
                # shrink c_most
                c_out = c_least.anchor

                if len(self.hub.cells) > 1:
                    self.hub.remove(c_out)

                c_least.add(c_out)

                # check the effects and revert if necessary
                self.update_anchors()
                new_balance = self.energy_balance()
                logger.debug("Completed %d rounds of 2b", r)

                # if this round didn't reduce the energy balance, then revert
                # the changes and exit the loop.
                if new_balance >= balance:
                    c_least.remove(c_out)
                    self.hub.add(c_out)
                    self.update_anchors()
                    break

            else:
                # shrink c_most
                _, c_in = closest_nodes([c_most.anchor], c_most)

                c_most.remove(c_in)
                self.hub.add(c_in)

                # grow c_least
                c_out, _ = closest_nodes(self.hub, [c_least.anchor])
                self.hub.remove(c_out)
                c_least.add(c_out)

                # check the effects and revert if necessary
                self.update_anchors()
                new_balance = self.energy_balance()
                logger.debug("Completed %d rounds of 2b", r)

                # if this round didn't reduce stdev, then revert the changes
                # and exit the loop
                if new_balance >= balance:
                    c_least.remove(c_out)
                    self.hub.add(c_out)

                    self.hub.remove(c_in)
                    c_most.add(c_in)

                    self.update_anchors()
                    break
示例#4
0
    def greedy_expansion(self):

        # First round (initial cell setup and energy calculation)

        for c in self.cells:
            c.cluster_id = -1

        for vc in self.virtual_clusters:
            c = LoafCluster(self.env)
            c.cluster_id = vc.cluster_id
            c.anchor = self.damaged

            closest_cell, _ = closest_nodes(vc, self.hub)
            c.add(closest_cell)
            self.clusters.append(c)

        assert self.energy_model.total_movement_energy(self.hub) == 0.

        # Rounds 2 through N
        r = 1
        while any(not c.completed for c in self.clusters):

            r += 1

            # Determine the minimum-cost cluster by first filtering out all
            # non-completed clusters. Then find the the cluster with the lowest
            # total cost.
            candidates = self.clusters + [self.hub]
            candidates = [c for c in candidates if not c.completed]
            c_least = min(candidates,
                          key=lambda x: self.total_cluster_energy(x))

            # In general, only consider cells that have not already been added
            # to a cluster. There is an exception to this when expanding the
            # hub cluster.
            cells = [c for c in self.cells if c.cluster_id == -1]

            # If there are no more cells to assign, then we mark this cluster
            # as "completed"
            if not cells:
                c_least.completed = True
                logger.debug("All cells assigned. Marking %s as completed",
                             c_least)
                continue

            if c_least == self.hub:

                # This logic handles the case where the hub cluster is has the
                # fewest energy requirements. Either the cluster will be moved
                # (initialization) or it will be grown.
                #
                # If the hub cluster is still in its original location at the
                # center of the damaged area, we need to move it to an actual
                # cell. If the hub has already been moved, then we expand it by
                # finding the cell nearest to the center of the damaged area,
                # and that itself hasn't already been added to the hub cluster.

                if c_least.cells == [self.damaged]:
                    # Find the nearest cell to the center of the damaged area
                    # and move the hub to it. This is equivalent to finding the
                    # cell with the lowest proximity.
                    best_cell = min(cells, key=lambda x: x.proximity)

                    # As the hub only currently has the virtual center cell in
                    # it, we can just "move" the hub to the nearest real cell
                    # by replacing the virtual cell with it.
                    self.hub.remove(self.damaged)
                    self.hub.add(best_cell)

                    # Just for proper bookkeeping, reset the virtual cell's ID
                    # to NOT_CLUSTERED
                    self.damaged.cluster_id = -1
                    self.damaged.virtual_cluster_id = -1
                    logger.debug("ROUND %d: Moved %s to %s", r, self.hub,
                                 best_cell)

                else:
                    # Find the set of cells that are not already in the hub
                    # cluster
                    available_cells = list(set(cells) - set(self.hub.cells))

                    # Out of those cells, find the one that is closest to the
                    # damaged area
                    best_cell, _ = closest_nodes(available_cells,
                                                 [self.hub.recent])

                    # Add that cell to the hub cluster
                    self.hub.add(best_cell)

                    logger.debug("ROUND %d: Added %s to %s", r, best_cell,
                                 self.hub)

                self.update_anchors()

            else:

                # In this case, the cluster with the lowest energy requirements
                # is one of the non-hub clusters.

                best_cell = None

                # Find the VC that corresponds to the current cluster
                vci = next(vc for vc in self.virtual_clusters
                           if vc.cluster_id == c_least.cluster_id)

                # Get a list of the cells that have not yet been added to a
                # cluster
                candidates = [c for c in vci.cells if c.cluster_id == -1]

                if candidates:

                    # Find the cell that is closest to the cluster's recent
                    # cell
                    best_cell, _ = closest_nodes(candidates, [c_least.recent])

                else:
                    for i in range(1, max(self.grid.cols, self.grid.rows) + 1):
                        recent = c_least.recent
                        nbrs = self.grid.cell_neighbors(recent, radius=i)

                        for nbr in nbrs:
                            # filter out cells that are not part of a virtual
                            # cluster
                            if nbr.virtual_cluster_id == -1:
                                continue

                            # filter out cells that are not in neighboring VCs
                            dist = abs(nbr.virtual_cluster_id - vci.cluster_id)
                            if dist != 1:
                                continue

                            # if the cell we find is already clustered, we are
                            # done working on this cluster
                            if nbr.cluster_id != -1:
                                c_least.completed = True
                                break

                            best_cell = nbr
                            break

                        if best_cell or c_least.completed:
                            break

                if best_cell:
                    logger.debug("ROUND %d: Added %s to %s", r, best_cell,
                                 c_least)
                    c_least.add(best_cell)

                else:
                    c_least.completed = True
                    logger.debug(
                        "ROUND %d: No best cell found. Marking %s completed",
                        r, c_least)