Пример #1
0
class PatternCombine(TransferFn):
    """
    Combine the supplied pattern with one generated using a
    PatternGenerator.

    Useful for operations like adding noise or masking out lesioned
    items or around the edges of non-rectangular shapes.
    """

    generator = param.ClassSelector(PatternGenerator,
        default=Constant(), doc="""
        Pattern to combine with the supplied matrix.""")

    operator = param.Parameter(numpy.multiply,precedence=0.98,doc="""
        Binary Numeric function used to combine the two patterns.

        Any binary Numeric array "ufunc" returning the same type of
        array as the operands and supporting the reduce operator is
        allowed here.  See topo.pattern.Composite.operator for more
        details.
        """)

    def __call__(self,x):
        ###JABHACKALERT: Need to set it up to be independent of
        #density; right now only things like random numbers work
        #reasonably
        rows,cols = x.shape
        bb = BoundingBox(points=((0,0), (rows,cols)))
        generated_pattern = self.generator(bounds=bb,xdensity=1,ydensity=1).transpose()
        new_pattern = self.operator(x, generated_pattern)
        x *= 0.0
        x += new_pattern
Пример #2
0
    def push_input_generator(self):
        """Push the current input_generator onto a stack for future retrieval."""
        self.input_generator_stack.append(self.input_generator)

        # CEBALERT: would be better to reorganize code so that
        # push_input_generator must be supplied with a new generator.
        # CEBALERT: presumably we can remove this import.
        from topo.base.patterngenerator import Constant
        self.set_input_generator(Constant())
Пример #3
0
    def test_constant(self):
        """
        Constant overrides PatternGenerator's usual matrix creation.
        """
        pattern_bounds = BoundingBox(points=((0.3, 0.2), (0.5, 0.5)))

        pattern_target = array([[1, 1], [1, 1], [1, 1]])

        c = Constant(bounds=pattern_bounds, xdensity=10.0, ydensity=10)
        assert_array_equal(c(), pattern_target)
Пример #4
0
class GeneratorSheet(Sheet):
    """
    Sheet for generating a series of 2D patterns.

    Typically generates the patterns by choosing parameters from a
    random distribution, but can use any mechanism.
    """

    src_ports = ['Activity']

    period = param.Number(
        default=1,
        bounds=(0, None),
        inclusive_bounds=(False, True),
        constant=True,
        doc="Delay (in Simulation time) between generating new input patterns."
    )

    phase = param.Number(default=0.05,
                         doc="""
        Delay after the start of the Simulation (at time zero) before
        generating an input pattern.  For a clocked, feedforward simulation,
        one would typically want to use a small nonzero phase and use delays less
        than the user-visible step size (typically 1.0), so that inputs are
        generated and processed before this step is complete.
        """)

    input_generator = param.ClassSelector(
        PatternGenerator,
        default=Constant(),
        doc=
        """Specifies a particular PatternGenerator type to use when creating patterns."""
    )

    def __init__(self, **params):
        super(GeneratorSheet, self).__init__(**params)
        self.input_generator_stack = []
        self.set_input_generator(self.input_generator)

    def set_input_generator(self, new_ig, push_existing=False):
        """
        Set the input_generator, overwriting the existing one by default.

        If push_existing is false, the existing input_generator is
        discarded permanently.  Otherwise, the existing one is put
        onto a stack, and can later be restored by calling
        pop_input_generator.
        """

        if push_existing:
            self.push_input_generator()

        # CEBALERT: replaces any bounds specified for the
        # PatternGenerator with this sheet's own bounds. When
        # PatternGenerators can draw patterns into supplied
        # boundingboxes, should remove this.
        new_ig.set_matrix_dimensions(self.bounds, self.xdensity, self.ydensity)
        self.input_generator = new_ig

    def push_input_generator(self):
        """Push the current input_generator onto a stack for future retrieval."""
        self.input_generator_stack.append(self.input_generator)

        # CEBALERT: would be better to reorganize code so that
        # push_input_generator must be supplied with a new generator.
        # CEBALERT: presumably we can remove this import.
        from topo.base.patterngenerator import Constant
        self.set_input_generator(Constant())

    def pop_input_generator(self):
        """
        Discard the current input_generator, and retrieve the previous one from the stack.

        Warns if no input_generator is available on the stack.
        """
        if len(self.input_generator_stack) >= 1:
            self.set_input_generator(self.input_generator_stack.pop())
        else:
            self.warning('There is no previous input generator to restore.')

    def generate(self):
        """
        Generate the output and send it out the Activity port.
        """
        self.verbose("Generating a new pattern")

        try:
            ac = self.input_generator()
        except StopIteration:
            # Note that a generator may raise an exception StopIteration if it runs out of patterns.
            # Example is if the patterns are files that are loaded sequentially and are not re-used (e.g. the constructors
            # are  discarded to save memory).
            self.warning(
                'Pattern generator {0} returned None. Unable to generate Activity pattern.'
                .format(self.input_generator.name))
        else:
            self.activity[:] = ac

            if self.apply_output_fns:
                for of in self.output_fns:
                    of(self.activity)
            self.send_output(src_port='Activity', data=self.activity)

    def start(self):
        assert self.simulation

        if self.period > 0:
            # if it has a positive period, then schedule a repeating event to trigger it
            e = FunctionEvent(0, self.generate)
            now = self.simulation.time()
            self.simulation.enqueue_event(
                PeriodicEventSequence(
                    now + self.simulation.convert_to_time_type(self.phase),
                    self.simulation.convert_to_time_type(self.period), [e]))

    def input_event(self, conn, data):
        raise NotImplementedError
Пример #5
0
class TestPattern(SheetPanel):

    sheet_type = GeneratorSheet

    dock = param.Boolean(False)

    edit_sheet = param.ObjectSelector(doc="""
        Sheet for which to edit pattern properties.""")

    plastic = param.Boolean(default=False,
                            doc="""
        Whether to enable plasticity during presentation.""")

    duration = param.Number(default=1.0,
                            softbounds=(0.0, 10.0),
                            doc="""
        How long to run the simulation for each presentation.""")

    Present = tk.Button(doc="""Present this pattern to the simulation.""")

    pattern_generator = param.ClassSelector(default=Constant(),
                                            class_=PatternGenerator,
                                            doc="""
        Type of pattern to present. Each type has various parameters that can be changed."""
                                            )

    def __init__(self, master, plotgroup=None, **params):
        plotgroup = plotgroup or TestPatternPlotGroup()

        super(TestPattern, self).__init__(master, plotgroup, **params)

        self.auto_refresh = True

        self.plotcommand_frame.pack_forget()
        for name in ['pre_plot_hooks', 'plot_hooks', 'Fwd', 'Back']:
            self.hide_param(name)

        edit_sheet_param = self.get_parameter_object('edit_sheet')
        edit_sheet_param.objects = self.plotgroup.sheets()

        self.pg_control_pane = Frame(self)  #,bd=1,relief="sunken")
        self.pg_control_pane.pack(side="top", expand='yes', fill='x')

        self.params_frame = tk.ParametersFrame(
            self.pg_control_pane,
            parameterized_object=self.pattern_generator,
            on_modify=self.conditional_refresh,
            msg_handler=master.status)

        self.params_frame.hide_param('Close')
        self.params_frame.hide_param('Refresh')

        # CEB: 'new_default=True' is temporary so that the current
        # behavior is the same as before; shoudl make None the
        # default and mean 'apply to all sheets'.
        self.pack_param('edit_sheet',
                        parent=self.pg_control_pane,
                        on_modify=self.switch_sheet,
                        widget_options={
                            'new_default': True,
                            'sort_fn_args': {
                                'cmp':
                                lambda x, y: cmp(-x.precedence, -y.precedence)
                            }
                        })
        self.pack_param('pattern_generator',
                        parent=self.pg_control_pane,
                        on_modify=self.change_pattern_generator,
                        side="top")

        present_frame = Frame(self)
        present_frame.pack(side='bottom')

        self.pack_param('plastic', side='bottom', parent=present_frame)
        self.params_frame.pack(side='bottom', expand='yes', fill='x')
        self.pack_param('duration', parent=present_frame, side='left')
        self.pack_param('Present',
                        parent=present_frame,
                        on_set=self.present_pattern,
                        side="right")

    def setup_plotgroup(self):
        super(TestPattern, self).setup_plotgroup()

        # CB: could copy the sheets instead (deleting connections etc)
        self.plotgroup._sheets = [
            GeneratorSheet(name=gs.name,
                           nominal_bounds=gs.nominal_bounds,
                           nominal_density=gs.nominal_density)
            for gs in topo.sim.objects(GeneratorSheet).values()
        ]
        self.plotgroup._set_name("Test Pattern")

    def switch_sheet(self):
        if self.edit_sheet is not None:
            self.pattern_generator = self.edit_sheet.input_generator
        self.change_pattern_generator()

    def change_pattern_generator(self):
        """
        Set the current PatternGenerator to the one selected and get the
        ParametersFrameWithApply to draw the relevant widgets
        """
        # CEBALERT: if pattern generator is set to None, there will be
        # an error. Need to handle None in the appropriate place
        # (presumably tk.py).
        self.params_frame.set_PO(self.pattern_generator)

        for sheet in self.plotgroup.sheets():
            if sheet == self.edit_sheet:
                sheet.set_input_generator(self.pattern_generator)

        self.conditional_refresh()

    def refresh(self, update=True):
        """
        Simply update the plots: skip all handling of history.
        """
        self.refresh_plots(update)

    def present_pattern(self):
        """
        Move the user created patterns into the GeneratorSheets, run for
        the specified length of time, then restore the original
        patterns.
        """
        input_dict = dict([(sheet.name,sheet.input_generator) \
                           for sheet in self.plotgroup.sheets()])
        pattern_present(inputs=input_dict,
                        durations=[self.duration],
                        plastic=self.plastic,
                        overwrite_previous=False,
                        install_sheetview=True,
                        restore_state=True)
        topo.guimain.auto_refresh(update=False)
Пример #6
0
class OneToOneProjection(Projection):
    """
    A projection that has at most one input connection for each unit.

    This projection has exactly one weight for each destination unit.
    The input locations on the input sheet are determined by a
    coordinate mapper.  Inputs that map outside the bounds of the
    input sheet are treated as having zero weight.
    """
    coord_mapper = param.ClassSelector(CoordinateMapperFn,
        default=IdentityMF(),
        doc='Function to map a destination unit coordinate into the src sheet.')

    weights_generator = param.ClassSelector(PatternGenerator,
        default=Constant(),constant=True,
        doc="""Generate initial weight values for each unit of the destination sheet.""")

    learning_fn = param.ClassSelector(LearningFn,default=IdentityLF(),
        doc="""Learning function applied to weights.""")

    learning_rate = param.Number(default=0)

    
    def __init__(self,**kw):
        super(OneToOneProjection,self).__init__(**kw)

        self.input_buffer = None
        
        dx,dy = self.dest.bounds.centroid()

        # JPALERT: Not sure if this is the right way to generate weights.
        # For full specificity, each initial weight should be dependent on the
        # coordinates of both the src unit and the dest unit.
        self.weights = self.weights_generator(bounds=self.dest.bounds,
                                              xdensity=self.dest.xdensity,
                                              ydensity=self.dest.ydensity)


        # JPALERT: CoordMapperFns should really be made to take
        # matrices of x/y points and apply their mapping to all.  This
        # could give great speedups, esp for AffineTransform mappings,
        # which can be applied to many points with a single matrix
        # multiplication.
        srccoords = [self.coord_mapper(x,y) 
                     for y in reversed(self.dest.sheet_rows())
                     for x in self.dest.sheet_cols()]
        
        self.src_idxs = array([rowcol2idx(r,c,self.src.activity.shape)
                               for r,c in (self.src.sheet2matrixidx(u,v)
                                           for u,v in srccoords)])

        # dest_idxs contains the indices of the dest units whose weights project
        # in bounds on the src sheet.
        src_rows,src_cols = self.src.activity.shape
        def in_bounds(x,y):
            r,c = self.src.sheet2matrixidx(x,y)
            return (0 <= r < src_rows) and (0 <= c < src_cols)
        destmask = [in_bounds(x,y) for x,y in srccoords]

        # The [0] is required because numpy.nonzero returns the
        # nonzero indices wrapped in a one-tuple.
        self.dest_idxs = nonzero(destmask)[0]
        self.src_idxs = self.src_idxs.take(self.dest_idxs)
        assert len(self.dest_idxs) == len(self.src_idxs)

        self.activity = zeros(self.dest.shape,dtype=float)

    def activate(self,input):
        self.input_buffer = input
        result = self.weights.take(self.dest_idxs) * input.take(self.src_idxs) * self.strength
        self.activity.put(self.dest_idxs,result)
        for of in self.output_fns:
            of(self.activity)

    def learn(self):
        if self.input_buffer is not None:
            self.learning_fn(self.input_buffer,
                             self.dest.activity,
                             self.weights,
                             self.learning_rate)

    def n_conns(self):
        rows,cols=self.activity.shape
        return rows*cols
    
    def n_bytes(self):
        return super(OneToOneProjection,self).n_bytes() + \
               self.activity.nbytes