Exemplo n.º 1
0
def factory(cli_arg: str, main_config: tp.Dict[str, str],
            batch_input_root: str, **kwargs) -> BlockConstantDensity:
    """
    Factory to create :class:`BlockConstantDensity` derived classes from the command line definition
    of batch criteria.

    """
    attr = cd.Parser()(cli_arg)
    kw = sgp.ScenarioGeneratorParser.reparse_str(kwargs['scenario'])

    if kw['dist_type'] == "SS" or kw['dist_type'] == "DS":
        r = range(kw['arena_x'],
                  kw['arena_x'] + attr['cardinality'] * attr['arena_size_inc'],
                  attr['arena_size_inc'])
        dims = [core.utils.ArenaExtent(Vector3D(x, x / 2.0, 0)) for x in r]
    elif kw['dist_type'] == "PL" or kw['dist_type'] == "RN":
        r = range(kw['arena_x'],
                  kw['arena_x'] + attr['cardinality'] * attr['arena_size_inc'],
                  attr['arena_size_inc'])
        dims = [core.utils.ArenaExtent(Vector3D(x, x, 0)) for x in r]
    else:
        raise NotImplementedError(
            "Unsupported block dstribution '{0}': Only SS,DS,QS,RN supported".
            format(kw['dist_type']))

    def __init__(self) -> None:
        BlockConstantDensity.__init__(self, cli_arg, main_config,
                                      batch_input_root, attr["target_density"],
                                      dims, kw['dist_type'])

    return type(
        cli_arg,  # type: ignore
        (BlockConstantDensity, ),
        {"__init__": __init__})
Exemplo n.º 2
0
    def at_point(self, x: float = None, y: float = None):
        r"""
        Calculate the block acquisition probability density at an (X,Y) point within the arena.

        .. math::
           \frac{1}{{\sqrt{z + -\log{\rho_b ^ {\rho_b / 2}}}}

        where :math:`z` is the distance of the (X,Y) point to the center of the nest, and
        :math:`\rho_b` is the block density at (X,Y).
        """

        if x is None and y is not None:  # Calculating marginal PDF of X
            pt = Vector3D(self.cluster.extent.center.x, y)
        elif x is not None and y is None:  # Calculating marginal PDF of Y
            pt = Vector3D(x, self.cluster.extent.center.y)
        else:  # Normal case
            assert x is not None and y is not None
            pt = Vector3D(x, y)

        # assert not self.nest.extent.contains(pt), "{0} inside nest@{1}".format(str(pt),
        #                                                                        str(self.nest.extent))

        # No acquisitions possible if the cluster never had any blocks in it during simulation.
        if self.rho is None:
            return 0.0

        z = self.dist_measure.to_nest(pt)
        if z < 0:
            z = 0
        return 1.0 / ((math.sqrt(z) + self.rho)**2) * self.norm_factor
Exemplo n.º 3
0
    def __init__(self, scenario: str, nest: Nest):
        self.scenario = scenario
        self.nest = nest

        if 'RN' in self.scenario or 'PL' in self.scenario:
            # Our model assumes all robots finish foraging EXACTLY at the nest center, and the
            # implementation has robots pick a random point between where they enter the nest and
            # the center, in order to reduce congestion.
            #
            # This has the effect of making the expected distance the robots travel after entering
            # the nest but before dropping their object LESS than the distance the model
            # assumes. So, we calculate the average distance from any point in the square defined by
            # HALF the nest span in X,Y (HALF being a result of uniform random choice in X,Y) to the
            # nest center:
            # https://math.stackexchange.com/questions/15580/what-is-average-distance-from-center-of-square-to-some-point
            edge = nest.extent.xsize() / 2.0
            self.nest_factor = edge / 6.0 * (math.sqrt(2.0) +
                                             math.log(1 + math.sqrt(2.0)))
        elif 'SS' in self.scenario:
            res, _ = si.nquad(
                lambda x, y:
                (self.nest.extent.center - Vector3D(x, y)).length(),
                [[
                    self.nest.extent.center.x,
                    self.nest.extent.center.x + self.nest.extent.xsize() / 2.0
                ],
                 [
                     self.nest.extent.center.y -
                     self.nest.extent.ysize() / 4.0,
                     self.nest.extent.center.y +
                     self.nest.extent.ysize() / 4.0,
                 ]],
                opts={'limit': 100})
            self.nest_factor = res / (nest.extent.area())
        elif 'DS' in self.scenario:
            res, _ = si.nquad(
                lambda x, y:
                (self.nest.extent.center - Vector3D(x, y)).length(),
                [[
                    self.nest.extent.center.x - self.nest.extent.xsize() / 4.0,
                    self.nest.extent.center.x + self.nest.extent.xsize() / 4.0
                ],
                 [
                     self.nest.extent.center.y -
                     self.nest.extent.ysize() / 8.0,
                     self.nest.extent.center.y +
                     self.nest.extent.ysize() / 8.0,
                 ]],
                opts={'limit': 100})
            eff_area = nest.extent.xsize() / 2.0 * nest.extent.ysize() / 4.0
            self.nest_factor = res / eff_area
    def from_df(cls, clusters_df: pd.DataFrame,
                cluster_id: int) -> 'BlockCluster':
        col_stem = 'cluster' + str(cluster_id)

        xmin = clusters_df.filter(regex=col_stem + '_xmin').iloc[-1].values[0]
        xmax = clusters_df.filter(regex=col_stem + '_xmax').iloc[-1].values[0]
        ymin = clusters_df.filter(regex=col_stem + '_ymin').iloc[-1].values[0]
        ymax = clusters_df.filter(regex=col_stem + '_ymax').iloc[-1].values[0]

        avg_blocks = clusters_df.filter(regex='cum_avg_' + col_stem +
                                        '_block_count').iloc[-1].values[0]
        return BlockCluster(ll=Vector3D(xmin, ymin),
                            ur=Vector3D(xmax, ymax),
                            cluster_id=cluster_id,
                            avg_blocks=avg_blocks)
Exemplo n.º 5
0
    def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]:
        """
        Generate list of sets of changes to input file to set the # blocks for a set of arena
        sizes such that the blocks density is constant. Blocks are approximated as point masses.
        """
        if not self.already_added:
            for changeset in self.attr_changes:
                for c in changeset:
                    if c.path == ".//arena" and c.attr == "size":
                        x, y, z = c.value.split(',')
                        dims = Vector3D(float(x), float(y), float(z))
                        extent = core.utils.ArenaExtent(dims)

                        # Always need at least 1 block
                        n_blocks = max(
                            2,
                            extent.area() * (self.target_density / 100.0))

                        changeset.add(
                            XMLAttrChange(
                                ".//arena_map/blocks/distribution/manifest",
                                "n_cube", "{0}".format(int(n_blocks / 2.0))))
                        changeset.add(
                            XMLAttrChange(
                                ".//arena_map/blocks/distribution/manifest",
                                "n_ramp", "{0}".format(int(n_blocks / 2.0))))
                        break
            self.already_added = True

        return self.attr_changes
    def __init__(self, cmdopts: dict, criteria: bc.IConcreteBatchCriteria,
                 exp_num: int):
        # Get nest position
        spec = ExperimentSpec(criteria, exp_num, cmdopts)
        res = sgp.ScenarioGeneratorParser.reparse_str(cmdopts['scenario'])
        pose = np.NestPose(res['dist_type'], [spec.arena_dim])

        for path, attr, val in pose.gen_attr_changelist()[0]:
            if 'nest' in path and 'center' in attr:
                x, y = val.split(',')
                center = Vector3D(float(x), float(y), 0.0)
            if 'nest' in path and 'dims' in attr:
                x, y = val.split(',')
                dims = Vector3D(float(x), float(y), 0.0)

        self.extent = ArenaExtent(dims, center - dims / 2.0)
Exemplo n.º 7
0
    def at_point(self, x: float = None, y: float = None):
        r"""
        Calculate the block density at an (X,Y) point within the extent of the block cluster.
        """
        assert x is not None and y is not None

        pt = Vector3D(x, y)

        # No density outside cluster extent
        if not self.cluster.extent.contains(pt):
            return 0.0
        # No density inside nest
        elif self.nest.extent.contains(pt):
            return 0.0

        return self.rho_b * self.norm_factor
Exemplo n.º 8
0
    def _nest_to_cluster(self, cluster: rep.BlockCluster,
                         nest: core.utils.ArenaExtent, scenario: str) -> float:
        dist_measure = DistanceMeasure2D(scenario, nest=nest)

        density = BlockAcqDensity(nest=nest,
                                  cluster=cluster,
                                  dist_measure=dist_measure)

        # Compute expected value of X coordinate of average distance from nest to acquisition
        # location.
        ll = cluster.extent.ll
        ur = cluster.extent.ur
        evx = density.evx_for_region(ll=ll, ur=ur)

        # Compute expected value of Y coordinate of average distance from nest to acquisition
        # location.
        evy = density.evy_for_region(ll=ll, ur=ur)

        # Compute expected distance from nest to block acquisitions
        dist = dist_measure.to_nest(Vector3D(evx, evy))
        return dist
    def __init__(self, cmdopts: dict, nest: Nest, sim_opath: str) -> None:

        clusters_df = core.utils.pd_csv_read(
            os.path.join(sim_opath, 'block-clusters.csv'))
        n_clusters = len([c for c in clusters_df.columns if 'xmin' in c])

        # Create extents from clusters
        self.clusters = set()

        # RN block distribution has a single cluster, but the nest is in the middle of it, which
        # makes density calculations much trickier when integrating across/up to the nest (modeled
        # as a single point). We break it into an equivalent set of 4 smaller clusters ringing the
        # nest to avoid computational issues.
        if 'RN' in cmdopts['scenario']:
            cluster = BlockCluster.from_df(clusters_df, 0)

            ll1 = cluster.extent.ll
            ur1 = Vector3D(nest.extent.ll.x, cluster.extent.ur.y)
            c1 = BlockCluster(ll=ll1,
                              ur=ur1,
                              cluster_id=0,
                              avg_blocks=cluster.avg_blocks / 4.0)

            ll2 = Vector3D(nest.extent.ll.x, cluster.extent.ll.y)
            ur2 = Vector3D(nest.extent.ur.x, nest.extent.ll.y)
            c2 = BlockCluster(ll=ll2,
                              ur=ur2,
                              cluster_id=1,
                              avg_blocks=cluster.avg_blocks / 4.0)

            ll3 = Vector3D(nest.extent.ll.x, nest.extent.ur.y)
            ur3 = Vector3D(nest.extent.ur.x, cluster.extent.ur.y)
            c3 = BlockCluster(ll=ll3,
                              ur=ur3,
                              cluster_id=2,
                              avg_blocks=cluster.avg_blocks / 4.0)

            ll4 = Vector3D(nest.extent.ur.x, cluster.extent.ll.y)
            ur4 = cluster.extent.ur
            c4 = BlockCluster(ll=ll4,
                              ur=ur4,
                              cluster_id=3,
                              avg_blocks=cluster.avg_blocks / 4.0)
            self.clusters = set([c1, c2, c3, c4])

        else:  # General case
            for c in range(0, n_clusters):
                self.clusters |= set([BlockCluster.from_df(clusters_df, c)])
Exemplo n.º 10
0
 def __init__(self, x_range: range, y_range: range, z: int,
              dist_type: str) -> None:
     super().__init__(
         [ArenaExtent(Vector3D(x, y, z)) for x in x_range for y in y_range],
         dist_type=dist_type)
Exemplo n.º 11
0
 def __init__(self, sqrange: range, z: int, dist_type: str) -> None:
     super().__init__([ArenaExtent(Vector3D(x, x, z)) for x in sqrange],
                      dist_type=dist_type)