class TestBoundingBox(unittest.TestCase):
    def setUp(self):
        self.left    = -0.1
        self.bottom  = -0.2
        self.right   =  0.3
        self.top     =  0.4
        self.lbrt = (self.left,self.bottom,self.right,self.top)

        self.region = BoundingBox(points = ((self.left,self.bottom),(self.right,self.top)))
        self.xc,self.yc = self.region.aarect().centroid()

    def test_way_inside(self):
        self.assert_(self.region.contains(0,0))
    def test_above(self):
        self.failIf(self.region.contains(0,1))
    def test_below(self):
        self.failIf(self.region.contains(0,-1))
    def test_left_of(self):
        self.failIf(self.region.contains(-1,0))
    def test_right_of(self):
        self.failIf(self.region.contains(1,0))

    def test_centroid_x(self):
        self.assertEqual(self.xc, (self.left+self.right)/2.0)
    def test_centroid_y(self):
        self.assertEqual(self.yc, (self.bottom+self.top)/2.0)

    def test_left_boundary(self):
        self.assert_(self.region.contains(self.left,self.yc))
    def test_right_boundary(self):
        self.assert_(self.region.contains(self.right,self.yc))
    def test_bottom_boundary(self):
        self.assert_(self.region.contains(self.xc, self.bottom))
    def test_top_boundary(self):
        self.assert_(self.region.contains(self.xc, self.top))
 def test_bounds_unequal_lbrt(self):
     try:
         self.assertEqual(BoundingBox(points=((-1, -1), (3, 4.5))),
                          BoundingBox(points=((-1, -1), (3, 5.0))))
     except AssertionError as e:
         msg = 'BoundingBox(points=((-1,-1),(3,4.5))) != BoundingBox(points=((-1,-1),(3,5.0)))'
         self.assertEqual(str(e), msg)
    def setUp(self):
        self.left = -0.1
        self.bottom = -0.2
        self.right = 0.3
        self.top = 0.4
        self.lbrt = (self.left, self.bottom, self.right, self.top)

        self.region = BoundingBox(points=((self.left, self.bottom),
                                          (self.right, self.top)))
        self.xc, self.yc = self.region.aarect().centroid()
Example #4
0
 def setUp(self):
     self.arr1 = np.array([[1,2], [3,4]])
     self.arr2 = np.array([[10,2], [3,4]])
     self.arr3 = np.array([[10,2], [3,40]])
     # Varying arrays, default bounds
     self.mat1 = Image(self.arr1, BoundingBox())
     self.mat2 = Image(self.arr2, BoundingBox())
     self.mat3 = Image(self.arr3, BoundingBox())
     # Varying arrays, different bounds
     self.mat4 = Image(self.arr1, BoundingBox(radius=0.3))
     self.mat5 = Image(self.arr2, BoundingBox(radius=0.3))
Example #5
0
class PatternGenerator(param.Parameterized):
    __abstract = True

    bounds = BoundingBox(points=((-0.5, -0.5), (0.5, 0.5)))
    xdensity = 256
    ydensity = 256
    x = 0.0
    y = 0.0
    z = None
    group = 'Pattern'
    position = param.Composite(attribs=['x', 'y'])
    orientation = 0.0
    size = 1.0
    scale = 1.0
    offset = 0.0
    output_fns = []

    def __init__(self, **params):
        super(PatternGenerator, self).__init__(**params)

    def __call__(self, **kwargs):
        pass

    def channels(self, **params):
        pass

    def num_channels(self):
        return 1

    def function(self, p):
        pass
    def setUp(self):
        self.left    = -0.1
        self.bottom  = -0.2
        self.right   =  0.3
        self.top     =  0.4
        self.lbrt = (self.left,self.bottom,self.right,self.top)

        self.region = BoundingBox(points = ((self.left,self.bottom),(self.right,self.top)))
        self.xc,self.yc = self.region.aarect().centroid()
class TestBoundingBox(unittest.TestCase):
    def setUp(self):
        self.left = -0.1
        self.bottom = -0.2
        self.right = 0.3
        self.top = 0.4
        self.lbrt = (self.left, self.bottom, self.right, self.top)

        self.region = BoundingBox(points=((self.left, self.bottom),
                                          (self.right, self.top)))
        self.xc, self.yc = self.region.aarect().centroid()

    def test_way_inside(self):
        self.assert_(self.region.contains(0, 0))

    def test_above(self):
        self.failIf(self.region.contains(0, 1))

    def test_below(self):
        self.failIf(self.region.contains(0, -1))

    def test_left_of(self):
        self.failIf(self.region.contains(-1, 0))

    def test_right_of(self):
        self.failIf(self.region.contains(1, 0))

    def test_centroid_x(self):
        self.assertEqual(self.xc, (self.left + self.right) / 2.0)

    def test_centroid_y(self):
        self.assertEqual(self.yc, (self.bottom + self.top) / 2.0)

    def test_left_boundary(self):
        self.assert_(self.region.contains(self.left, self.yc))

    def test_right_boundary(self):
        self.assert_(self.region.contains(self.right, self.yc))

    def test_bottom_boundary(self):
        self.assert_(self.region.contains(self.xc, self.bottom))

    def test_top_boundary(self):
        self.assert_(self.region.contains(self.xc, self.top))
Example #8
0
File: image.py Project: fcr/imagen
    def _set_image(self, image):
        # Stores a SheetCoordinateSystem with an activity matrix
        # representing the image
        if not isinstance(image, np.ndarray):
            image = np.array(image, np.float)

        rows, cols = image.shape
        self.scs = SheetCoordinateSystem(
            xdensity=1.0,
            ydensity=1.0,
            bounds=BoundingBox(points=((-cols / 2.0, -rows / 2.0),
                                       (cols / 2.0, rows / 2.0))))
        self.scs.activity = image
 def test_bounds_unequal(self):
     try:
         self.assertEqual(BoundingBox(radius=0.5), BoundingBox(radius=0.7))
     except AssertionError as e:
         self.assertEqual(
             str(e), "BoundingBox(radius=0.5) != BoundingBox(radius=0.7)")
 def test_bounds_equal(self):
     self.assertEqual(BoundingBox(radius=0.5), BoundingBox(radius=0.5))
                                        size=p[1], orientation=p[0], phase=p[3], xdensity=x, ydensity=y)()
            if BlackBackground:
                assert T[idx_proto][idx_shift].max() <= 1.0 and T[idx_proto][idx_shift].min() >= 0
                T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift]
            idx_shift += 1
        idx_proto += 1

    return T



if __name__ == '__main__':
    # image size
    x = 800/1.2
    y = 800/1.2
    Bound = BoundingBox(radius=0.6)
    BlackBackground = True  # convert image to black background
    phase_shift = False  # generate different phases
    f = 4

    SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    sio.savemat('SpG_b.mat', {'imgs': SpG})

    # ############ waves
    # SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    # SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    # T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=f)
    # HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    # RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    #
    # ############## save images to .mat file
Example #12
0
class CFProjection(Projection):
    """
    A projection composed of ConnectionFields from a Sheet into a ProjectionSheet.

    CFProjection computes its activity using a response_fn of type
    CFPResponseFn (typically a CF-aware version of mdot) and output_fns
    (typically none).  The initial contents of the
    ConnectionFields mapping from the input Sheet into the target
    ProjectionSheet are controlled by the weights_generator, cf_shape,
    and weights_output_fn parameters, while the location of the
    ConnectionField is controlled by the coord_mapper parameter.

    Any subclass has to implement the interface
    activate(self,input_activity) that computes the response from the
    input and stores it in the activity array.
    """

    response_fn = param.ClassSelector(
        CFPResponseFn,
        default=CFPRF_Plugin(),
        doc=
        'Function for computing the Projection response to an input pattern.')

    cf_type = param.Parameter(
        default=ConnectionField,
        constant=True,
        doc="Type of ConnectionField to use when creating individual CFs.")

    # JPHACKALERT: Not all support for null CFs has been implemented.
    # CF plotting and C-optimized CFPxF_ functions need
    # to be fixed to support null CFs without crashing.
    allow_null_cfs = param.Boolean(
        default=False,
        doc="Whether or not the projection can have entirely empty CFs")

    nominal_bounds_template = BoundingRegionParameter(
        default=BoundingBox(radius=0.1),
        doc="""
        Bounds defining the Sheet area covered by a prototypical ConnectionField.
        The true bounds will differ depending on the density (see create_slice_template())."""
    )

    weights_generator = param.ClassSelector(
        PatternGenerator,
        default=patterngenerator.Constant(),
        constant=True,
        doc="Generate initial weights values.")

    cf_shape = param.ClassSelector(
        PatternGenerator,
        default=patterngenerator.Constant(),
        constant=True,
        doc="Mask pattern to define the shape of the connection fields.")

    same_cf_shape_for_all_cfs = param.Boolean(default=True,
                                              doc="""
        Whether or not to share a single cf_shape mask for all CFs.
        If True, the cf_shape is evaluated only once and shared for
        all CFs, which saves computation time and memory.  If False,
        the cf_shape is evaluated once for each CF, allowing each to
        have its own shape.""")

    learning_fn = param.ClassSelector(
        CFPLearningFn,
        default=CFPLF_Plugin(),
        doc=
        'Function for computing changes to the weights based on one activation step.'
    )

    # JABALERT: Shouldn't learning_rate be owned by the learning_fn?
    learning_rate = param.Number(default=0.0,
                                 softbounds=(0, 100),
                                 doc="""
        Amount of learning at each step for this projection, specified
        in units that are independent of the density of each Sheet.""")

    weights_output_fns = param.HookList(
        default=[CFPOF_Plugin()],
        class_=CFPOutputFn,
        doc='Functions applied to each CF after learning.')

    strength = param.Number(default=1.0,
                            doc="""
        Global multiplicative scaling applied to the Activity of this Sheet."""
                            )

    coord_mapper = param.ClassSelector(
        CoordinateMapperFn,
        default=IdentityMF(),
        doc='Function to map a projected coordinate into the target sheet.')

    # CEBALERT: this is temporary (allows c++ matching in certain
    # cases).  We will allow the user to override the mask size, but
    # by offering a scaling parameter.
    autosize_mask = param.Boolean(default=True,
                                  constant=True,
                                  precedence=-1,
                                  doc="""
        Topographica sets the mask size so that it is the same as the connection field's
        size, unless this parameter is False - in which case the user-specified size of
        the cf_shape is used. In normal usage of Topographica, this parameter should
        remain True.""")

    mask_threshold = param.Number(default=0.5,
                                  constant=True,
                                  doc="""
        If a unit is above this value in the cf_shape mask, it is
        included; otherwise it is excluded from the mask.""")

    apply_output_fns_init = param.Boolean(default=True,
                                          doc="""
        Whether to apply the output function to connection fields (e.g. for
        normalization) when the CFs are first created.""")

    min_matrix_radius = param.Integer(default=1,
                                      bounds=(0, None),
                                      doc="""
        Enforced minimum for radius of weights matrix.
        The default of 1 gives a minimum matrix of 3x3. 0 would
        allow a 1x1 matrix.""")

    hash_format = param.String(default="{name}-{src}-{dest}",
                               doc="""
       Format string to determine the hash value used to initialize
       random weight generation. Format keys available include {name}
       {src} and {dest}.""")

    seed = param.Integer(default=None,
                         allow_None=True,
                         doc="""
       The random seed used to determine the randomized weight
       initialization stream. If not None, equivalent to appending the
       chosen integer to the hash_format.""")

    precedence = param.Number(default=0.8)

    def __init__(self, initialize_cfs=True, **params):
        """
        Initialize the Projection with a set of cf_type objects
        (typically ConnectionFields), each located at the location
        in the source sheet corresponding to the unit in the target
        sheet. The cf_type objects are stored in the 'cfs' array.

        The nominal_bounds_template specified may be altered: the
        bounds must be fitted to the Sheet's matrix, and the weights
        matrix must have odd dimensions. These altered bounds are
        passed to the individual connection fields.

        A mask for the weights matrix is constructed. The shape is
        specified by cf_shape; the size defaults to the size
        of the nominal_bounds_template.
        """
        super(CFProjection, self).__init__(**params)

        self.weights_generator.set_dynamic_time_fn(None,
                                                   sublistattr='generators')
        # get the actual bounds_template by adjusting a copy of the
        # nominal_bounds_template to ensure an odd slice, and to be
        # cropped to sheet if necessary
        self._slice_template = Slice(copy(self.nominal_bounds_template),
                                     self.src,
                                     force_odd=True,
                                     min_matrix_radius=self.min_matrix_radius)

        self.bounds_template = self._slice_template.compute_bounds(self.src)

        self.mask_template = _create_mask(self.cf_shape, self.bounds_template,
                                          self.src, self.autosize_mask,
                                          self.mask_threshold)

        self.n_units = self._calc_n_units()

        if initialize_cfs:
            self._create_cfs()

        if self.apply_output_fns_init:
            self.apply_learn_output_fns(active_units_mask=False)

        ### JCALERT! We might want to change the default value of the
        ### input value to self.src.activity; but it fails, raising a
        ### type error. It probably has to be clarified why this is
        ### happening
        self.input_buffer = None
        self.activity = np.array(self.dest.activity)
        if 'cfs' not in self.dest.views:
            self.dest.views.CFs = Layout()
        self.dest.views.CFs[self.name] = self._cf_grid()

    def _cf_grid(self, shape=None, **kwargs):
        "Create GridSpace with the correct metadata."
        grid = GridSpace({})
        grid.metadata = AttrDict(timestamp=self.src.simulation.time(),
                                 info=self.name,
                                 proj_src_name=self.src.name,
                                 proj_dest_name=self.dest.name,
                                 **kwargs)
        return grid

    def _generate_coords(self):
        X, Y = self.dest.sheetcoords_of_idx_grid()
        vectorized_coord_mapper = simple_vectorize(
            self.coord_mapper,
            num_outputs=2,
            # CB: could switch to float32?
            output_type=float)
        return vectorized_coord_mapper(X, Y)

    # CB: should be _initialize_cfs() since we already have 'initialize_cfs' flag?
    def _create_cfs(self):
        vectorized_create_cf = simple_vectorize(self._create_cf)
        self.cfs = vectorized_create_cf(*self._generate_coords())
        self.flatcfs = list(self.cfs.flat)

    def _create_cf(self, x, y):
        """
        Create a ConnectionField at x,y in the src sheet.
        """
        # (to restore would need to have an r,c counter)
        # self.debug("Creating CF(%d,%d) from src (%.3f,%.3f) to  dest (%.3f,%.3f)"%(r,c,x_cf,y_cf,x,y))

        label = self.hash_format.format(name=self.name,
                                        src=self.src.name,
                                        dest=self.dest.name)

        label = label + ('-%d' % self.seed if self.seed is not None else '')
        name = "%s_CF (%.5f, %.5f)" % ('' if label is None else label, x, y)
        try:
            if self.same_cf_shape_for_all_cfs:
                mask_template = self.mask_template
            else:
                mask_template = _create_mask(self.cf_shape,
                                             self.bounds_template,
                                             self.src,
                                             self.autosize_mask,
                                             self.mask_threshold,
                                             name=name)

            CF = self.cf_type(self.src,
                              x=x,
                              y=y,
                              template=self._slice_template,
                              weights_generator=self.weights_generator,
                              mask=mask_template,
                              min_matrix_radius=self.min_matrix_radius,
                              label=label)
        except NullCFError:
            if self.allow_null_cfs:
                CF = None
            else:
                raise

        return CF

    def _calc_n_units(self):
        """Return the number of unmasked units in a typical ConnectionField."""

        return min(
            len(self.mask_template.ravel().nonzero()[0]),
            # CEBALERT: if the mask_template is bigger than the
            # src sheet (e.g.  conn radius bigger than src
            # radius), return the size of the source sheet
            self.src.shape[0] * self.src.shape[1])

    def cf(self, r, c):
        """Return the specified ConnectionField"""
        # CB: should we offer convenience cf(x,y) (i.e. sheetcoords) method instead?
        self.warning(
            "CFProjection.cf(r,c) is deprecated: use cfs[r,c] instead")
        return self.cfs[r, c]

    def cf_bounds(self, r, c):
        """Return the bounds of the specified ConnectionField."""
        return self.cfs[r, c].get_bounds(self.src)

    def grid(self, rows=11, cols=11, lbrt=None, situated=False, **kwargs):
        xdensity, ydensity = self.dest.xdensity, self.dest.ydensity
        l, b, r, t = self.dest.bounds.lbrt()
        half_x_unit = ((r - l) / xdensity) / 2.
        half_y_unit = ((t - b) / ydensity) / 2.
        if lbrt is None:
            l, b, r, t = (l + half_x_unit, b + half_y_unit, r - half_x_unit,
                          t - half_y_unit)
        else:
            l, b = self.dest.closest_cell_center(lbrt[0], lbrt[1])
            r, t = self.dest.closest_cell_center(lbrt[2], lbrt[3])
        x, y = np.meshgrid(np.linspace(l, r, cols), np.linspace(b, t, rows))
        coords = zip(x.flat, y.flat)

        grid_items = {}
        for x, y in coords:
            grid_items[x, y] = self.view(x, y, situated=situated, **kwargs)

        grid = GridSpace(grid_items,
                         label=' '.join([self.dest.name, self.name]),
                         group='CFs')
        grid.metadata = AttrDict(info=self.name,
                                 proj_src_name=self.src.name,
                                 proj_dest_name=self.dest.name,
                                 timestamp=self.src.simulation.time(),
                                 **kwargs)
        return grid

    def view(self, sheet_x, sheet_y, timestamp=None, situated=False, **kwargs):
        """
        Return a single connection field Image, for the unit
        located nearest to sheet coordinate (sheet_x,sheet_y).
        """
        if timestamp is None:
            timestamp = self.src.simulation.time()
        time_dim = Dimension("Time", type=param.Dynamic.time_fn.time_type)
        (r, c) = self.dest.sheet2matrixidx(sheet_x, sheet_y)
        cf = self.cfs[r, c]
        r1, r2, c1, c2 = cf.input_sheet_slice
        situated_shape = self.src.activity.shape
        situated_bounds = self.src.bounds
        roi_bounds = cf.get_bounds(self.src)
        if situated:
            matrix_data = np.zeros(situated_shape, dtype=np.float64)
            matrix_data[r1:r2, c1:c2] = cf.weights.copy()
            bounds = situated_bounds
        else:
            matrix_data = cf.weights.copy()
            bounds = roi_bounds

        sv = CFView(matrix_data,
                    bounds,
                    situated_bounds=situated_bounds,
                    input_sheet_slice=(r1, r2, c1, c2),
                    roi_bounds=roi_bounds,
                    label=self.name,
                    group='CF Weight')
        sv.metadata = AttrDict(timestamp=timestamp)

        viewmap = HoloMap((timestamp, sv), kdims=[time_dim])
        viewmap.metadata = AttrDict(coords=(sheet_x, sheet_y),
                                    dest_name=self.dest.name,
                                    precedence=self.src.precedence,
                                    proj_name=self.name,
                                    src_name=self.src.name,
                                    row_precedence=self.src.row_precedence,
                                    timestamp=timestamp,
                                    **kwargs)
        return viewmap

    def get_view(self, sheet_x, sheet_y, timestamp=None):
        self.warning("Deprecated, call 'view' method instead.")
        return self.view(sheet_x, sheet_y, timestamp)

    def activate(self, input_activity):
        """Activate using the specified response_fn and output_fn."""
        if self.input_fns:
            input_activity = input_activity.copy()
        for iaf in self.input_fns:
            iaf(input_activity)
        self.input_buffer = input_activity
        self.activity *= 0.0
        self.response_fn(CFIter(self), input_activity, self.activity,
                         self.strength)
        for of in self.output_fns:
            of(self.activity)

    # CEBALERT: should add active_units_mask to match
    # apply_learn_output_fns.
    def learn(self):
        """
        For a CFProjection, learn consists of calling the learning_fn.
        """
        # Learning is performed if the input_buffer has already been set,
        # i.e. there is an input to the Projection.
        if self.input_buffer is not None:
            self.learning_fn(CFIter(self), self.input_buffer,
                             self.dest.activity, self.learning_rate)

    # CEBALERT: called 'learn' output fns here, but called 'weights' output fns
    # elsewhere (mostly). Change all to 'learn'?
    def apply_learn_output_fns(self, active_units_mask=True):
        """
        Apply the weights_output_fns to each unit.

        If active_units_mask is True, inactive units will be skipped.
        """
        for of in self.weights_output_fns:
            of(CFIter(self, active_units_mask=active_units_mask))

    # CEBALERT: see gc alert in simulation.__new__
    def _cleanup(self):
        for cf in self.cfs.flat:
            # cf could be None or maybe something else
            if hasattr(cf, 'input_sheet'):
                cf.input_sheet = None
            if hasattr(cf, 'input_sheet_slice'):
                cf.input_sheet_slice = None
            if hasattr(cf, 'weights_slice'):
                cf.weights_slice = None

    def n_bytes(self):
        # Could also count the input_sheet_slice
        rows, cols = self.cfs.shape
        return super(CFProjection,self).n_bytes() + \
               sum([cf.weights.nbytes +
                    cf.mask.nbytes
                    for cf,i in CFIter(self,ignore_sheet_mask=True)()])

    def n_conns(self):
        # Counts non-masked values, if mask is available; otherwise counts
        # weights as connections if nonzero
        rows, cols = self.cfs.shape
        return np.sum([
            len((cf.mask
                 if cf.mask is not None else cf.weights).ravel().nonzero()[0])
            for cf, i in CFIter(self)()
        ])
Example #13
0
    def __init__(self,
                 input_sheet,
                 x=0.0,
                 y=0.0,
                 template=BoundingBox(radius=0.1),
                 weights_generator=patterngenerator.Constant(),
                 mask=patterngenerator.Constant(),
                 output_fns=None,
                 min_matrix_radius=1,
                 label=None):
        """
        Create weights at the specified (x,y) location on the
        specified input_sheet.

        The supplied template (if a BoundingRegion) is converted to a
        Slice, moved to the specified (x,y) location, and then the
        weights pattern is drawn inside by the weights_generator.

        Note that if the appropriate template Slice is already known,
        then it can be passed in instead of a BoundingRegion template.
        This slice will then be used directly, instead of converting
        the template into a Slice.

        The supplied template object itself will not be modified (it
        is copied before use).

        The mask allows the weights to be limited to being non-zero in
        a subset of the rectangular weights area.  The actual mask
        used is a view of the given mask created by cropping to the
        boundaries of the input_sheet, so that the weights all
        correspond to actual locations in the input sheet.  For
        instance, if a circular pattern of weights is desired, the
        mask should have a disk-shaped pattern of elements with value
        1, surrounded by elements with the value 0.  If the CF extends
        over the edge of the input sheet then the weights will
        actually be half-moon (or similar) rather than circular.
        """
        #print "Create CF",input_sheet.name,x,y,"template=",template,"wg=",weights_generator,"m=",mask,"ofs=",output_fns,"min r=",min_matrix_radius

        template = copy(template)

        if not isinstance(template, Slice):
            template = Slice(template,
                             input_sheet,
                             force_odd=True,
                             min_matrix_radius=min_matrix_radius)

        # Note: if passed in, mask is shared between CFs (but not if created here)
        if not hasattr(mask, 'view'):
            mask = _create_mask(
                mask,
                template.compute_bounds(input_sheet),
                # CEBALERT: it's not really worth adding more ALERTs on this
                # topic, but...there's no way for the CF to control autosize
                # and threshold.
                input_sheet,
                True,
                0.5)

        # CB: has to be set for C code. Can't be initialized at the
        # class level, or it would become a read-only class attribute
        # (because it's a slot:
        # http://docs.python.org/reference/datamodel.html). Can we
        # somehow avoid having to think about _has_norm_total in the
        # python code? Could the C code initialize this value?
        self._has_norm_total = np.array([0], dtype=np.int32)
        self._norm_total = np.array([0.0], dtype=np.float64)

        if output_fns is None:
            output_fns = []

        # CEBALERT: now even more confusing; weights_slice is
        # different from input_sheet_slice. At least need to rename.
        weights_slice = self._create_input_sheet_slice(input_sheet, x, y,
                                                       template,
                                                       min_matrix_radius)

        # CBNOTE: this would be clearer (but not perfect, and probably slower)
        # m = mask_template[self.weights_slice()]
        self.mask = weights_slice.submatrix(mask)  # view of original mask
        self.mask = np.array(self.mask,
                             copy=1)  # CEBALERT: why is this necessary?

        # (without it, optimized learning function creates artifacts in CFs at
        # left and right edges of sheet, at some densities)

        # CBENHANCEMENT: might want to do something about a size
        # that's specified (right now the size is assumed to be that
        # of the bounds)
        # shouldn't be extra computation of boundingbox because it's gone from Slice.__init__; could avoid extra lookups by getting straight from slice

        pattern_params = dict(x=x,
                              y=y,
                              bounds=self.get_bounds(input_sheet),
                              xdensity=input_sheet.xdensity,
                              ydensity=input_sheet.ydensity,
                              mask=self.mask)

        controlled_weights = (param.Dynamic.time_dependent
                              and isinstance(param.Dynamic.time_fn, param.Time)
                              and self.independent_weight_generation)

        if controlled_weights:
            with param.Dynamic.time_fn as t:
                t(0)  # Initialize weights at time zero.
                # Controls random streams
                name = "%s_CF (%.5f, %.5f)" % ('' if label is None else label,
                                               x, y)
                w = weights_generator(**dict(pattern_params, name=name))
        else:
            w = weights_generator(**pattern_params)

        # CEBALERT: unnecessary copy! Pass type to PG & have it draw
        # in that.  (Should be simple, except making it work for all
        # the PG subclasses that override array creation in various
        # ways (producing or using inconsistent types) turned out to
        # be too painful.)
        self.weights = w.astype(weight_type)

        # CEBHACKALERT: the system of masking through multiplication
        # by 0 works for now, while the output_fns are all
        # multiplicative.  But in the long run we need a better way to
        # apply the mask.  The same applies anywhere the mask is used,
        # including in learningfn/. We should investigate masked
        # arrays (from numpy).
        for of in output_fns:
            of(self.weights)
Example #14
0
                                                          ydensity=y)()
                if BlackBackground:
                    assert SpG[idx_proto][idx_shift].max(
                    ) <= 1.0 and SpG[idx_proto][idx_shift].min() >= 0
                    SpG[idx_proto][idx_shift] = 1 - SpG[idx_proto][idx_shift]
                idx_shift += 1
        idx_proto += 1

    return SpG


if __name__ == '__main__':
    # image size
    x = 192
    y = 192
    Bound = BoundingBox(radius=1)
    BlackBackground = True  # convert image to black background
    phase_shift = False  # generate different phases
    f = 4

    ############ waves
    SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f)

    ############## save images to .mat file
    if phase_shift:
        if BlackBackground:
            sio.savemat('SpG_shift_b.mat', {'imgs': SpG})
        else:
            sio.savemat('SpG_shift_w.mat', {'imgs': SpG})
    else:
        if BlackBackground:
class PatternGenerator(param.Parameterized):
    """
    A class hierarchy for callable objects that can generate 2D patterns.

    Once initialized, PatternGenerators can be called to generate a
    value or a matrix of values from a 2D function, typically
    accepting at least x and y.

    A PatternGenerator's Parameters can make use of Parameter's
    precedence attribute to specify the order in which they should
    appear, e.g. in a GUI. The precedence attribute has a nominal
    range of 0.0 to 1.0, with ordering going from 0.0 (first) to 1.0
    (last), but any value is allowed.

    The orientation and layout of the pattern matrices is defined by
    the SheetCoordinateSystem class, which see.

    Note that not every parameter defined for a PatternGenerator will
    be used by every subclass.  For instance, a Constant pattern will
    ignore the x, y, orientation, and size parameters, because the
    pattern does not vary with any of those parameters.  However,
    those parameters are still defined for all PatternGenerators, even
    Constant patterns, to allow PatternGenerators to be scaled, rotated,
    translated, etc. uniformly.
    """
    __abstract = True

    bounds = BoundingRegionParameter(
        default=BoundingBox(points=((-0.5, -0.5), (0.5, 0.5))),
        precedence=-1,
        doc="BoundingBox of the area in which the pattern is generated.")

    xdensity = param.Number(default=256,
                            bounds=(0, None),
                            precedence=-1,
                            doc="""
        Density (number of samples per 1.0 length) in the x direction.""")

    ydensity = param.Number(default=256,
                            bounds=(0, None),
                            precedence=-1,
                            doc="""
        Density (number of samples per 1.0 length) in the y direction.
        Typically the same as the xdensity.""")

    x = param.Number(default=0.0,
                     softbounds=(-1.0, 1.0),
                     precedence=0.20,
                     doc="""
        X-coordinate location of pattern center.""")

    y = param.Number(default=0.0,
                     softbounds=(-1.0, 1.0),
                     precedence=0.21,
                     doc="""
        Y-coordinate location of pattern center.""")

    z = param.ClassSelector(default=None,
                            precedence=-1,
                            class_=Dimension,
                            doc="""
        The Dimension object associated with the z-values generated by
        the PatternGenerator . If None, uses the default set by
        HoloViews.Image.""")

    group = param.String(default='Pattern',
                         precedence=-1,
                         doc="""
       The group name assigned to the returned HoloViews object.""")

    position = param.Composite(attribs=['x', 'y'],
                               precedence=-1,
                               doc="""
        Coordinates of location of pattern center.
        Provides a convenient way to set the x and y parameters together
        as a tuple (x,y), but shares the same actual storage as x and y
        (and thus only position OR x and y need to be specified).""")

    orientation = param.Number(default=0.0,
                               softbounds=(0.0, 2 * pi),
                               precedence=0.40,
                               doc="""
        Polar angle of pattern, i.e., the orientation in the Cartesian coordinate
        system, with zero at 3 o'clock and increasing counterclockwise.""")

    size = param.Number(default=1.0,
                        bounds=(0.0, None),
                        softbounds=(0.0, 6.0),
                        precedence=0.30,
                        doc="""Determines the overall size of the pattern.""")

    scale = param.Number(default=1.0,
                         softbounds=(0.0, 2.0),
                         precedence=0.10,
                         doc="""
        Multiplicative strength of input pattern, defaulting to 1.0""")

    offset = param.Number(default=0.0,
                          softbounds=(-1.0, 1.0),
                          precedence=0.11,
                          doc="""
        Additive offset to input pattern, defaulting to 0.0""")

    mask = param.Parameter(default=None,
                           precedence=-1,
                           doc="""
        Optional object (expected to be an array) with which to multiply the
        pattern array after it has been created, before any output_fns are
        applied. This can be used to shape the pattern.""")

    # Note that the class type is overridden to PatternGenerator below
    mask_shape = param.ClassSelector(param.Parameterized,
                                     default=None,
                                     precedence=0.06,
                                     doc="""
        Optional PatternGenerator used to construct a mask to be applied to
        the pattern.""")

    output_fns = param.HookList(default=[],
                                precedence=0.08,
                                doc="""
        Optional function(s) to apply to the pattern array after it has been created.
        Can be used for normalization, thresholding, etc.""")

    def __init__(self, **params):
        super(PatternGenerator, self).__init__(**params)
        self.set_matrix_dimensions(self.bounds, self.xdensity, self.ydensity)

    def __call__(self, **params_to_override):
        """
        Call the subclass's 'function' method on a rotated and scaled
        coordinate system.

        Creates and fills an array with the requested pattern.  If
        called without any params, uses the values for the Parameters
        as currently set on the object. Otherwise, any params
        specified override those currently set on the object.
        """
        if 'output_fns' in params_to_override:
            self.warning(
                "Output functions specified through the call method will be ignored."
            )

        p = ParamOverrides(self, params_to_override)

        # CEBERRORALERT: position parameter is not currently
        # supported. We should delete the position parameter or fix
        # this.
        #
        # position=params_to_override.get('position',None) if position
        # is not None: x,y = position

        self._setup_xy(p.bounds, p.xdensity, p.ydensity, p.x, p.y,
                       p.orientation)
        fn_result = self.function(p)
        self._apply_mask(p, fn_result)
        if p.scale != 1.0:
            result = p.scale * fn_result
        else:
            result = fn_result
        if p.offset != 0.0:
            result += p.offset

        for of in p.output_fns:
            of(result)

        return result

    def __getitem__(self, coords):
        value_dims = {}
        if self.num_channels() in [0, 1]:
            raster, data = Image, self()
            value_dims = {
                'value_dimensions': [self.z]
            } if self.z else value_dims
        elif self.num_channels() in [3, 4]:
            raster = RGB
            data = np.dstack(self.channels().values()[1:])

        image = raster(data,
                       bounds=self.bounds,
                       **dict(group=self.group,
                              label=self.__class__.__name__,
                              **value_dims))
        # Works round a bug fixed shortly after HoloViews 1.0.0 release
        return image if isinstance(coords,
                                   slice) else image.__getitem__(coords)

    def channels(self, use_cached=False, **params_to_override):
        """
        Channels() adds a shared interface for single channel and
        multichannel structures.  It will always return an ordered
        dict: its first element is the single channel of the pattern
        (if single-channel) or the channel average (if multichannel);
        the successive elements are the individual channels' arrays
        (key: 0,1,..N-1).
        """
        return collections.OrderedDict(
            {'default': self.__call__(**params_to_override)})

    def num_channels(self):
        """
        Query the number of channels implemented by the
        PatternGenerator. In case of single-channel generators this
        will return 1; in case of multichannel, it will return the
        number of channels (eg, in the case of RGB images it would
        return '3', Red-Green-Blue, even though the OrderedDict
        returned by channels() will have 4 elements -- the 3 channels
        + their average).
        """
        return 1

    def _setup_xy(self, bounds, xdensity, ydensity, x, y, orientation):
        """
        Produce pattern coordinate matrices from the bounds and
        density (or rows and cols), and transforms them according to
        x, y, and orientation.
        """
        self.debug(
            "bounds=%s, xdensity=%s, ydensity=%s, x=%s, y=%s, orientation=%s",
            bounds, xdensity, ydensity, x, y, orientation)
        # Generate vectors representing coordinates at which the pattern
        # will be sampled.

        # CB: note to myself - use slice_._scs if supplied?
        x_points, y_points = SheetCoordinateSystem(
            bounds, xdensity, ydensity).sheetcoordinates_of_matrixidx()

        # Generate matrices of x and y sheet coordinates at which to
        # sample pattern, at the correct orientation
        self.pattern_x, self.pattern_y = self._create_and_rotate_coordinate_arrays(
            x_points - x, y_points - y, orientation)

    def function(self, p):
        """
        Function to draw a pattern that will then be scaled and rotated.

        Instead of implementing __call__ directly, PatternGenerator
        subclasses will typically implement this helper function used
        by __call__, because that way they can let __call__ handle the
        scaling and rotation for them.  Alternatively, __call__ itself
        can be reimplemented entirely by a subclass (e.g. if it does
        not need to do any scaling or rotation), in which case this
        function will be ignored.
        """
        raise NotImplementedError

    def _create_and_rotate_coordinate_arrays(self, x, y, orientation):
        """
        Create pattern matrices from x and y vectors, and rotate them
        to the specified orientation.
        """
        # Using this two-liner requires that x increase from left to
        # right and y decrease from left to right; I don't think it
        # can be rewritten in so little code otherwise - but please
        # prove me wrong.
        pattern_y = np.subtract.outer(
            np.cos(orientation) * y,
            np.sin(orientation) * x)
        pattern_x = np.add.outer(
            np.sin(orientation) * y,
            np.cos(orientation) * x)
        return pattern_x, pattern_y

    def _apply_mask(self, p, mat):
        """Create (if necessary) and apply the mask to the given matrix mat."""
        mask = p.mask
        ms = p.mask_shape
        if ms is not None:
            mask = ms(
                x=p.x + p.size *
                (ms.x * np.cos(p.orientation) - ms.y * np.sin(p.orientation)),
                y=p.y + p.size *
                (ms.x * np.sin(p.orientation) + ms.y * np.cos(p.orientation)),
                orientation=ms.orientation + p.orientation,
                size=ms.size * p.size,
                bounds=p.bounds,
                ydensity=p.ydensity,
                xdensity=p.xdensity)
        if mask is not None:
            mat *= mask

    def set_matrix_dimensions(self, bounds, xdensity, ydensity):
        """
        Change the dimensions of the matrix into which the pattern
        will be drawn.  Users of this class should call this method
        rather than changing the bounds, xdensity, and ydensity
        parameters directly.  Subclasses can override this method to
        update any internal data structures that may depend on the
        matrix dimensions.
        """
        self.bounds = bounds
        self.xdensity = xdensity
        self.ydensity = ydensity
        scs = SheetCoordinateSystem(bounds, xdensity, ydensity)
        for of in self.output_fns:
            if isinstance(of, TransferFn):
                of.initialize(SCS=scs, shape=scs.shape)

    def state_push(self):
        "Save the state of the output functions, to be restored with state_pop."
        for of in self.output_fns:
            if hasattr(of, 'state_push'):
                of.state_push()
        super(PatternGenerator, self).state_push()

    def state_pop(self):
        "Restore the state of the output functions saved by state_push."
        for of in self.output_fns:
            if hasattr(of, 'state_pop'):
                of.state_pop()
        super(PatternGenerator, self).state_pop()

    def anim(self,
             duration,
             offset=0,
             timestep=1,
             label=None,
             unit=None,
             time_fn=param.Dynamic.time_fn):
        """
        duration: The temporal duration to animate in the units
        defined on the global time function.

        offset: The temporal offset from which the animation is
        generated given the supplied pattern

        timestep: The time interval between successive frames. The
        duration must be an exact multiple of the timestep.

        label: A label string to override the label of the global time
        function (if not None).

        unit: The unit string to override the unit value of the global
        time function (if not None).

        time_fn: The global time function object that is shared across
        the time-varying objects that are being sampled.

        Note that the offset, timestep and time_fn only affect
        patterns parameterized by time-dependent number
        generators. Otherwise, the frames are generated by successive
        call to the pattern which may or may not be varying (e.g to
        view the patterns contained within a Selector).
        """
        frames = (duration // timestep) + 1
        if duration % timestep != 0:
            raise ValueError(
                "The duration value must be an exact multiple of the timestep."
            )

        if label is None:
            label = time_fn.label if hasattr(time_fn, 'label') else 'Time'

        unit = time_fn.unit if (not unit
                                and hasattr(time_fn, 'unit')) else unit
        vmap = HoloMap(
            key_dimensions=[Dimension(label, unit=unit if unit else '')])

        self.state_push()
        with time_fn as t:
            t(offset)
            for i in range(frames):
                vmap[t()] = self[:]
                t += timestep
        self.state_pop()
        return vmap

    ## Support for compositional expressions of PatternGenerator objects
    def _promote(self, other):
        if not isinstance(other, PatternGenerator):
            other = Constant(scale=other, offset=0)
        return [self, other]

    def _rpromote(self, other):
        if not isinstance(other, PatternGenerator):
            other = Constant(scale=other, offset=0)
        return [other, self]

    # Could define any of Python's operators here, esp. if they have operator or ufunc equivalents
    def __add__(self, other):
        return Composite(generators=self._promote(other), operator=np.add)

    def __sub__(self, other):
        return Composite(generators=self._promote(other), operator=np.subtract)

    def __mul__(self, other):
        return Composite(generators=self._promote(other), operator=np.multiply)

    def __mod__(self, other):
        return Composite(generators=self._promote(other), operator=np.mod)

    def __pow__(self, other):
        return Composite(generators=self._promote(other), operator=np.power)

    def __div__(self, other):
        return Composite(generators=self._promote(other), operator=np.divide)

    def __and__(self, other):
        return Composite(generators=self._promote(other), operator=np.minimum)

    def __or__(self, other):
        return Composite(generators=self._promote(other), operator=np.maximum)

    def __radd__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.add)

    def __rsub__(self, other):
        return Composite(generators=self._rpromote(other),
                         operator=np.subtract)

    def __rmul__(self, other):
        return Composite(generators=self._rpromote(other),
                         operator=np.multiply)

    def __rmod__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.mod)

    def __rpow__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.power)

    def __rdiv__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.divide)

    def __rand__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.minimum)

    def __ror__(self, other):
        return Composite(generators=self._rpromote(other), operator=np.maximum)

    def __neg__(self):
        return Composite(generators=[Constant(scale=0), self],
                         operator=np.subtract)

    class abs_first(object):
        @staticmethod
        def reduce(x):
            return np.abs(x[0])

    def __abs__(self):
        return Composite(generators=[self], operator=self.abs_first)

    def pil(self, **params_to_override):
        """Returns a PIL image for this pattern, overriding parameters if provided."""
        from PIL.Image import fromarray
        nchans = self.num_channels()

        if nchans in [0, 1]:
            mode, arr = None, self(**params_to_override)
            arr = (255.0 / arr.max() * (arr - arr.min())).astype(np.uint8)

        elif nchans in [3, 4]:
            mode = 'RGB' if nchans == 3 else 'RGBA'
            arr = np.dstack(self.channels(**params_to_override).values()[1:])
            arr = (255.0 * arr).astype(np.uint8)

        else:
            raise ValueError("Unsupported number of channels")

        return fromarray(arr, mode)
Example #16
0
class Sheet(EventProcessor,
            SheetCoordinateSystem):  # pylint: disable-msg=W0223
    """
    The generic base class for neural sheets.

    See SheetCoordinateSystem for how Sheet represents space, and
    EventProcessor for how Sheet handles time.

    output_fns are functions that take an activity matrix and produce
    an identically shaped output matrix. The default is having no
    output_fns.
    """
    __abstract = True

    nominal_bounds = BoundingRegionParameter(BoundingBox(radius=0.5),
                                             constant=True,
                                             doc="""
            User-specified BoundingBox of the Sheet coordinate area
            covered by this Sheet.  The left and right bounds--if
            specified--will always be observed, but the top and bottom
            bounds may be adjusted to ensure the density in the y
            direction is the same as the density in the x direction.
            In such a case, the top and bottom bounds are adjusted
            so that the center y point remains the same, and each
            bound is as close as possible to its specified value. The
            actual value of this Parameter is not adjusted, but the
            true bounds may be found from the 'bounds' attribute
            of this object.
            """)

    nominal_density = param.Number(default=10,
                                   constant=True,
                                   doc="""
            User-specified number of processing units per 1.0 distance
            horizontally or vertically in Sheet coordinates. The actual
            number may be different because of discretization; the matrix
            needs to tile the plane exactly, and for that to work the
            density might need to be adjusted.  For instance, an area of 3x2
            cannot have a density of 2 in each direction. The true density
            may be obtained from either the xdensity or ydensity attribute
            (since these are identical for a Sheet).
            """)

    plastic = param.Boolean(True,
                            doc="""
            Setting this to False tells the Sheet not to change its
            permanent state (e.g. any connection weights) based on
            incoming events.
            """)

    precedence = param.Number(default=0.1,
                              softbounds=(0.0, 1.0),
                              doc="""
            Allows a sorting order for Sheets, e.g. in the GUI.""")

    row_precedence = param.Number(default=0.5,
                                  softbounds=(0.0, 1.0),
                                  doc="""
            Allows grouping of Sheets before sorting precedence is
            applied, e.g. for two-dimensional plots in the GUI.""")

    layout_location = param.NumericTuple(default=(-1, -1),
                                         precedence=-1,
                                         doc="""
            Location for this Sheet in an arbitrary pixel-based space
            in which Sheets can be laid out for visualization.""")

    output_fns = param.HookList(
        default=[],
        class_=TransferFn,
        doc=
        "Output function(s) to apply (if apply_output_fns is true) to this Sheet's activity."
    )

    apply_output_fns = param.Boolean(
        default=True,
        doc="Whether to apply the output_fn after computing an Activity matrix."
    )

    properties = param.Dict(default={},
                            doc="""
       A dictionary of property values associated with the Sheet
       object.  For instance, the dictionary:

       {'polarity':'ON', 'eye':'Left'}

       could be used to indicate a left, LGN Sheet with ON-surround
       receptive fields.""")

    def _get_density(self):
        return self.xdensity

    density = property(_get_density,
                       doc="""The sheet's true density (i.e. the
        xdensity, which is equal to the ydensity for a Sheet.)""")

    def __init__(self, **params):
        """
        Initialize this object as an EventProcessor, then also as
        a SheetCoordinateSystem with equal xdensity and ydensity.

        views is a Layout, which stores associated measurements,
        i.e. representations of the sheet for use by analysis or plotting
        code.
        """
        EventProcessor.__init__(self, **params)

        # Initialize this object as a SheetCoordinateSystem, with
        # the same density along y as along x.
        SheetCoordinateSystem.__init__(self, self.nominal_bounds,
                                       self.nominal_density)

        n_units = round((self.lbrt[2] - self.lbrt[0]) * self.xdensity, 0)
        if n_units < 1:            raise ValueError(
                "Sheet bounds and density must be specified such that the "+ \
 "sheet has at least one unit in each direction; " \
 +self.name+ " does not.")

        # setup the activity matrix
        self.activity = zeros(self.shape, activity_type)

        # For non-plastic inputs
        self.__saved_activity = []
        self._plasticity_setting_stack = []

        self.views = Layout()
        self.views.Maps = Layout()
        self.views.Curves = Layout()

    ### JABALERT: This should be deleted now that sheet_views is public
    ### JC: shouldn't we keep that, or at least write a function in
    ### utils that deletes a value in a dictinnary without returning an
    ### error if the key is not in the dict?  I leave for the moment,
    ### and have to ask Jim to advise.
    def release_sheet_view(self, view_name):
        """
        Delete the dictionary entry with key entry 'view_name' to save
        memory.
        """
        if view_name in self.views.Maps:
            self.views.Maps[view_name] = None

    # CB: what to call this? sheetcoords()? sheetcoords_of_grid()? idxsheetcoords()?
    def sheetcoords_of_idx_grid(self):
        """
        Return an array of x-coordinates and an array of y-coordinates
        corresponding to the activity matrix of the sheet.
        """
        nrows, ncols = self.activity.shape

        C, R = meshgrid(arange(ncols), arange(nrows))

        X, Y = self.matrixidx2sheet(R, C)
        return X, Y

    # CB: check whether we need this function any more.
    def row_col_sheetcoords(self):
        """
        Return an array of Y-coordinates corresponding to the rows of
        the activity matrix of the sheet, and an array of
        X-coordinates corresponding to the columns.
        """
        # The row and column centers are returned in matrix (not
        # sheet) order (hence the reversals below).
        nrows, ncols = self.activity.shape
        return self.matrixidx2sheet(arange(nrows - 1, -1, -1),
                                    arange(ncols))[::-1]

    # CBALERT: to be removed once other code uses
    # row_col_sheetcoords() or sheetcoords_of_idx_grid().
    def sheet_rows(self):
        return self.row_col_sheetcoords()[0]

    def sheet_cols(self):
        return self.row_col_sheetcoords()[1]

    # CEBALERT: haven't really thought about what to put in this. The
    # way it is now, subclasses could make a super.activate() call to
    # avoid repeating some stuff.
    def activate(self):
        """
        Collect activity from each projection, combine it to calculate
        the activity for this sheet, and send the result out.

        Subclasses will need to override this method to whatever it
        means to calculate activity in that subclass.
        """
        if self.apply_output_fns:
            for of in self.output_fns:
                of(self.activity)

        self.send_output(src_port='Activity', data=self.activity)

    def state_push(self):
        """
        Save the current state of this sheet to an internal stack.

        This method is used by operations that need to test the
        response of the sheet without permanently altering its state,
        e.g. for measuring maps or probing the current behavior
        non-invasively.  By default, only the activity pattern of this
        sheet is saved, but subclasses should add saving for any
        additional state that they maintain, or strange bugs are
        likely to occur.  The state can be restored using state_pop().

        Note that Sheets that do learning need not save the
        values of all connection weights, if any, because
        plasticity can be turned off explicitly.  Thus this method
        is intended only for shorter-term state.
        """
        self.__saved_activity.append(array(self.activity))
        EventProcessor.state_push(self)
        for of in self.output_fns:
            if hasattr(of, 'state_push'):
                of.state_push()

    def state_pop(self):
        """
        Pop the most recently saved state off the stack.

        See state_push() for more details.
        """
        self.activity = self.__saved_activity.pop()
        EventProcessor.state_pop(self)
        for of in self.output_fns:
            if hasattr(of, 'state_pop'):
                of.state_pop()

    def activity_len(self):
        """Return the number of items that have been saved by state_push()."""
        return len(self.__saved_activity)

    def override_plasticity_state(self, new_plasticity_state):
        """
        Temporarily override plasticity of medium and long term internal state.

        This function should be implemented by all subclasses so that
        it preserves the ability of the Sheet to compute activity,
        i.e. to operate over a short time scale, while preventing any
        lasting changes to the state (if new_plasticity_state=False).

        Any operation that does not have any lasting state, such as
        those affecting only the current activity level, should not
        be affected by this call.

        By default, simply saves a copy of the plastic flag to an
        internal stack (so that it can be restored by
        restore_plasticity_state()), and then sets plastic to
        new_plasticity_state.
        """
        self._plasticity_setting_stack.append(self.plastic)
        self.plastic = new_plasticity_state

    def restore_plasticity_state(self):
        """
        Restores plasticity of medium and long term internal state after
        a override_plasticity_state call.

        This function should be implemented by all subclasses to
        remove the effect of the most recent override_plasticity_state call,
        i.e. to restore plasticity of any type that was overridden.
        """
        self.plastic = self._plasticity_setting_stack.pop()

    def n_bytes(self):
        """
        Return a lower bound for the memory taken by this sheet, in bytes.

        Typically, this number will include the activity array and any
        similar arrays, plus any other significant data owned (in some
        sense) by this Sheet.  It will not usually include memory
        taken by the Python dictionary or various "housekeeping"
        attributes, which usually contribute only a small amount to
        the memory requirements.

        Subclasses should reimplement this method if they store a
        significant amount of data other than in the activity array.
        """
        return self.activity.nbytes

    def __getitem__(self, coords):
        metadata = AttrDict(precedence=self.precedence,
                            row_precedence=self.row_precedence,
                            timestamp=self.simulation.time())

        image = Image(self.activity.copy(),
                      self.bounds,
                      label=self.name,
                      group='Activity')[coords]
        image.metadata = metadata
        return image
Example #17
0
                                                      ydensity=y)()
            if BlackBackground:
                assert T[idx_proto][idx_shift].max(
                ) <= 1.0 and T[idx_proto][idx_shift].min() >= 0
                T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift]
            idx_shift += 1
        idx_proto += 1

    return T


if __name__ == '__main__':
    # image size
    x = 24
    y = 24
    Bound = BoundingBox(radius=20.4)
    BlackBackground = True  # convert image to black background
    phase_shift = False  # generate different phases

    ############ waves
    SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=24)
    SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=24)
    T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=24)
    HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=24)
    RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=24)

    # ############## save images to .mat file
    if phase_shift:
        if BlackBackground:
            sio.savemat('SG_shift_b.mat', {'imgs': SG})
            sio.savemat('HG_shift_b.mat', {'imgs': HG})
Example #18
0
                T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift]
            idx_shift += 1
        idx_proto += 1

    return T



if __name__ == '__main__':

    BlackBackground = True  # convert image to black background
    phase_shift = False  # generate different phases
    f = 4

    # for training, to generate images used for slant and tilt
    Bound = BoundingBox(radius=2.08)   # r = 2.08 for slant and tilt cropping #r=1.1 for all 159 set
    for scale in [1/1.2, 1, 1.2]:
        x = 192*scale
        y = 192*scale
        # ########### only the spirals for training
        SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f)
        save_name = 'SpG_b_scale{0:.2f}.mat'.format(scale)
        sio.savemat(save_name, {'imgs': SpG})



    # # for 159 complete set
    # x = 192
    # y = 192
    # Bound = BoundingBox(radius=1.1)   # r = 2.08 for slant and tilt cropping #r=1.1 for all 159 set
 def test_bounds_equal_lbrt(self):
     self.assertEqual(BoundingBox(points=((-1, -1), (3, 4.5))),
                      BoundingBox(points=((-1, -1), (3, 4.5))))
        if BlackBackground:
            assert Ba[idx].max() <= 1.0 and Ba[idx].min >= 0
            Ba[idx] = 1 - Ba[idx]
        idx += 1

    return Ba


if __name__ == '__main__':
    # image size
    # x = 256
    # y = 256
    # Bound = BoundingBox(radius=1.16)
    x = 256
    y = 256
    Bound = BoundingBox(radius=0.58 * 2)
    BlackBackground = True  # convert image to black background
    jetter = False  # add perturbations

    # ############# waves
    SG = SineG(x, y, BlackBackground, jetter, Bound)
    HG = HyperG(x, y, BlackBackground, jetter, Bound)
    SpG = SpiralG(x, y, BlackBackground, jetter, Bound)
    RG = RadialG(x, y, BlackBackground, jetter, Bound)
    T = Targets(x, y, BlackBackground, jetter, Bound)

    # ############## save images to .mat file
    if jetter:
        if BlackBackground:
            sio.savemat('SG_pert_b.mat', {'imgs': SG})
            sio.savemat('HG_pert_b.mat', {'imgs': HG})
                                                      ydensity=y)()
            if BlackBackground:
                assert T[idx_proto][idx_shift].max(
                ) <= 1.0 and T[idx_proto][idx_shift].min() >= 0
                T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift]
            idx_shift += 1
        idx_proto += 1

    return T


if __name__ == '__main__':
    # image size
    x = 192
    y = 192
    Bound = BoundingBox(radius=1.05)
    BlackBackground = True  # convert image to black background
    phase_shift = False  # generate different phases
    f = 4

    ############ waves
    SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=f)
    HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=f)
    RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=f)

    Bound = BoundingBox(radius=1.5)
    SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f)

    ############## save images to .mat file
    if phase_shift:
Example #22
0
    def setUp(self):
        ### Simple case: we only pass a dictionary to Plot()
        ### that does not belong to a Sheet:
        views = {}

        time = 0
        metadata = AttrDict(timestamp=time)

        ### SheetView1:
        ### Find a way to assign randomly the matrix.
        self.matrix1 = np.zeros((10,10),dtype=np.float) + np.random.random((10,10))
        self.bounds1 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5)))
        sv = Matrix(self.matrix1, self.bounds1)
        sv.metadata=metadata
        self.sheet_view1 = NdMapping((None, sv))
        self.sheet_view1.metadata = AttrDict(src_name='TestInputParam',
                                            precedence=0.1, row_precedence=0.1,
                                            cyclic_range=None, timestamp=time)
        self.key1 = 'SV1'
        views[self.key1] = self.sheet_view1

        ### SheetView2:
        ### Find a way to assign randomly the matrix.
        self.matrix2 = np.zeros((10,10),dtype=np.float) + 0.3
        self.bounds2 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5)))
        sv = Matrix(self.matrix2, self.bounds2)
        sv.metadata=metadata
        self.sheet_view2 = NdMapping((None, sv))
        self.sheet_view2.metadata = AttrDict(src_name='TestInputParam',
                                             precedence=0.2, row_precedence=0.2,
                                             cyclic_range=None, timestamp=time)
        self.key2 = 'SV2'
        views[self.key2] = self.sheet_view2

        ### SheetView3:
        ### Find a way to assign randomly the matrix.
        self.matrix3 = np.zeros((10,10),dtype=np.float) + np.random.random((10,10))
        self.bounds3 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5)))
        sv = Matrix(self.matrix3, self.bounds3)
        sv.metadata=metadata
        self.sheet_view3 = NdMapping((None, sv))
        self.sheet_view3.metadata = AttrDict(src_name='TestInputParam',
                                             precedence=0.3, row_precedence=0.3,
                                             cyclic_range=None, timestamp=time)
        self.key3 = 'SV3'
        views[self.key3] = self.sheet_view3

        ### SheetView4: for testing clipping + different bounding box
        ### Find a way to assign randomly the matrix.
        self.matrix4 = np.zeros((10,10),dtype=np.float) + 1.6
        self.bounds4 = BoundingBox(points=((-0.7,-0.7),(0.7,0.7)))
        sv = Matrix(self.matrix4, self.bounds4)
        sv.metadata=metadata
        self.sheet_view4 = NdMapping((None, sv))
        self.sheet_view4.metadata = AttrDict(src_name='TestInputParam',
                                             precedence=0.4, row_precedence=0.4,
                                             cyclic_range=None, timestamp=time)
        self.key4 = 'SV4'
        views[self.key4] = self.sheet_view4

        self.view_dict = {'Strength': views, 'Hue': views, 'Confidence': views}

        ### JCALERT! for the moment we can only pass a triple when creating plot
        ### adding more sheetView to test when plot will be fixed for accepting
        ### as much as you want.

        # plot0: empty plot + no sheetviewdict passed: error or empty plot?
        ### JCALERT! It has to be fixed what to do in this case in plot..
        ### disabled test for the moment.
        #self.plot0 = Plot((None,None,None),None,name='plot0')
        ### CATCH EXCEPTION

        plot_channels1 = {'Strength':None,'Hue':None,'Confidence':None}
        # plot1: empty plot
        self.plot1 = make_template_plot(plot_channels1,self.view_dict,density=10.0,name='plot1')

        plot_channels2 = {'Strength':self.key1,'Hue':None,'Confidence':None}
        # plot2: sheetView 1, no normalize, no clipping
        self.plot2 = make_template_plot(plot_channels2,self.view_dict,density=10.0,name='plot2')

        plot_channels3 = {'Strength':self.key1,'Hue':self.key2,'Confidence':None}
        # plot3: sheetView 1+2, no normalize, no clipping
        self.plot3 = make_template_plot(plot_channels3,self.view_dict,density=10.0,name='plot3')

        plot_channels4 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3}
        # plot4: sheetView 1+2+3, no normalize , no clipping
        self.plot4 = make_template_plot(plot_channels4,self.view_dict,density=10.0,name='plot4')

        plot_channels5 = {'Strength':self.key1,'Hue':None,'Confidence':self.key3}
        # plot5: sheetView 1+3, no normalize, no clipping
        self.plot5 = make_template_plot(plot_channels5,self.view_dict,density=10.0,name='plot5')

        plot_channels6 = {'Strength':None,'Hue':self.key2,'Confidence':self.key3}
        # plot6: sheetView 2+3, no normalize , no clipping
        self.plot6 = make_template_plot(plot_channels6,self.view_dict,density=10.0,name='plot6')

        plot_channels7 = {'Strength':self.key4,'Hue':self.key2,'Confidence':self.key3}
        # plot7: sheetView 1+2+3, no normalize , clipping
        self.plot7 = make_template_plot(plot_channels7,self.view_dict,density=10.0,name='plot7')

        plot_channels8 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3}
        # plot8: sheetView 1+2+3, normalize , no clipping
        self.plot8 = make_template_plot(plot_channels8,self.view_dict,density=10.0,normalize=True,name='plot8')

        ### JCALERT! FOR THE MOMENT I TAKE THE DEFAULT FOR NORMALIZE.
        ### WE WILL SEE IF IT REMAINS IN PLOT FIRST.

        ### also makes a sheet to test realease_sheetviews

        self.sheet = Sheet()
        self.sheet.views.Maps[self.key1]=self.sheet_view1
        self.sheet.views.Maps[self.key2]=self.sheet_view2
        self.sheet.views.Maps[self.key3]=self.sheet_view3
        self.sheet.views.Maps[self.key4]=self.sheet_view4

        plot_channels9 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3}
        self.plot9 = make_template_plot(plot_channels9,self.sheet.views.Maps,density=10.0,name='plot9')