Пример #1
0
class Cog(object):
    """ 
    The basic units of which gearboxes are composed

    Cogs are named for their similarity to clockwork cogwheels.
    They are simple and do the same task over and over, but by
    virtue of how they are connected to their fellows, they 
    collectively bring about interesting behavior.  
    In a conflicting metaphor, the inputs to a cog
    are similar to electrical cables: they carry activity 
    signals that vary over time.

    Each cog contains two important parts, a daisychain and a ziptie.
    The daisychain is an object that builds cables into short sequences,
    and the ziptie is an object that takes the resulting chains
    and performs clustering on them, grouping them into bundles.
    During upward processing, cable activities are used to train
    the daisychain and ziptie, making new bundles, maturing existing 
    bundles, and calculating the activity in bundle. 
    During downward processing, 
    the daisychain and ziptie use the bundle activity goals from 
    the gearbox above to create goals for the cables. 
    """
    def __init__(self, max_cables, max_bundles, max_chains_per_bundle=None,
                 name='anonymous', level=0):
        """ 
        Initialize the cogs with a pre-determined maximum size 
        """
        self.name = name
        self.max_cables = max_cables
        self.max_bundles = max_bundles
        if max_chains_per_bundle is None:
            max_chains_per_bundle = int(max_cables ** 2 / max_bundles)
        self.daisychain = DaisyChain(max_cables, name=name)        
        if max_bundles > 0:
            self.ziptie = ZipTie(max_cables **2, max_bundles, 
                                 max_cables_per_bundle=max_chains_per_bundle, 
                                 name=name)

    def step_up(self, cable_activities, enough_cables):
        """ 
        Cable_activities percolate upward through daisychain and ziptie 
        """
        # TODO: fix this so that cogs can gracefully handle more cables 
        # or else never be assigned them in the first place. 
        # Enable them to grow dynamically, rather than preallocated,
        # if that can be shown to improve performance.
        if cable_activities.size > self.max_cables:
            cable_activities = cable_activities[:self.max_cables, :]
            print ''.join(['-----  Number of max cables exceeded in', 
                            self.name, '  -----'])
        chain_activities = self.daisychain.step_up(cable_activities)
        # Wait to start training the cog's bundles until the cog's
        # input cables are adequately populated. This is the job
        # of the gearbox's ziptie.
        if enough_cables is True:
            bundle_activities = self.ziptie.step_up(chain_activities)
        else:
            bundle_activities = np.zeros((0,1))
        # TODO: Check whether this is necessary
        bundle_activities = tools.pad(bundle_activities, (self.max_bundles, 0))
        return bundle_activities

    def step_down(self, bundle_goals):
        """ 
        Bundle_goals percolate downward 
        """
        chain_goals = self.ziptie.step_down(bundle_goals) 
        cable_goals = self.daisychain.step_down(chain_goals)     
        return cable_goals

    def get_index_projection(self, bundle_index):
        """ 
        Project a bundle down through the ziptie and daisychain 
        """
        chain_projection = self.ziptie.get_index_projection(bundle_index)
        cable_projection = self.daisychain.get_index_projection(
                chain_projection)
        return cable_projection
         
    def fraction_filled(self):
        """ 
        How full is the set of cables for this cog? 
        """
        return float(self.daisychain.num_cables) / float(self.max_cables)

    def num_bundles(self):
        """ 
        How many bundles have been created in this cog? 
        """
        return self.ziptie.num_bundles
            
    def visualize(self):
        """ 
        Show the internal state of the daisychain and ziptie 
        """
        self.daisychain.visualize()
        if self.max_bundles > 0:
            self.ziptie.visualize()
Пример #2
0
class Block(object):
    """
    The building block of which the agent is composed

    Blocks are arranged hierarchically within the agent. 
    The agent begins with only one block, and creates additional
    blocks in a tower arrangement as lower ones mature. 
    
    The block's input channels (cables) are organized 
    into clusters (bundles)
    whose activities are passed up to the next block in the hierarchy.  
    Each block performs the same two functions, 
    1) a step_up 
    where cable activities are converted to bundle activities and
    passed up the tower and 
    2) a step_down where bundle activity goals are passed back down
    and converted into cable activity goals. 
    Internally, a block contains a number of cogs that work in parallel
    to convert cable activities into bundle activities and back again.
    """
    def __init__(self, min_cables, name='anonymous', level=0):
        """ Initialize the level, defining the dimensions of its cogs """
        self.max_cables = int(2 ** np.ceil(np.log2(min_cables)))
        self.max_cables_per_cog = 8
        self.max_bundles_per_cog = 4
        self.max_cogs = self.max_cables / self.max_bundles_per_cog
        self.max_bundles = self.max_cogs * self.max_bundles_per_cog
        self.name = name
        self.level = level
        ziptie_name = ''.join(('ziptie_', self.name))
        self.ziptie = ZipTie(self.max_cables, self.max_cogs, 
                             max_cables_per_bundle=self.max_cables_per_cog,
                             mean_exponent=-2, name=ziptie_name)
        self.cogs = []
        # TODO: only create cogs as needed
        for cog_index in range(self.max_cogs):
            self.cogs.append(Cog(self.max_cables_per_cog, 
                                 self.max_bundles_per_cog,
                                 max_chains_per_bundle=self.max_cables_per_cog,
                                 name='cog'+str(cog_index), 
                                 level=self.level))
        self.cable_activities = np.zeros((self.max_cables, 1))
        self.hub_cable_goals = np.zeros((self.max_cables, 1))
        self.fill_fraction_threshold = .7
        self.ACTIVITY_DECAY_RATE = 1.# real, 0 < x < 1
        # Constants for adaptively rescaling the cable activities
        self.max_vals = np.zeros((self.max_cables, 1)) 
        self.min_vals = np.zeros((self.max_cables, 1))
        self.RANGE_DECAY_RATE = 10 ** -5
        
    def step_up(self, new_cable_activities):
        """ Find bundle_activities that result from new_cable_activities """
        # Condition the cable activities to fall between 0 and 1
        if new_cable_activities.size < self.max_cables:
            new_cable_activities = tools.pad(new_cable_activities, 
                                             (self.max_cables, 1))
        self.min_vals = np.minimum(new_cable_activities, self.min_vals)
        self.max_vals = np.maximum(new_cable_activities, self.max_vals)
        spread = self.max_vals - self.min_vals
        new_cable_activities = ((new_cable_activities - self.min_vals) / 
                   (self.max_vals - self.min_vals + tools.EPSILON))
        self.min_vals += spread * self.RANGE_DECAY_RATE
        self.max_vals -= spread * self.RANGE_DECAY_RATE
        # Update cable_activities, incorporating sensing dynamics
        self.cable_activities = tools.bounded_sum([
                new_cable_activities, 
                self.cable_activities * (1. - self.ACTIVITY_DECAY_RATE)])

        # Update the map from self.cable_activities to cogs
        self.ziptie.step_up(self.cable_activities)
        # Process the upward pass of each of the cogs in the block
        self.bundle_activities = np.zeros((0, 1))
        for cog_index in range(len(self.cogs)):
            # Pick out the cog's cable_activities, process them, 
            # and assign the results to block's bundle_activities
            cog_cable_activities = self.cable_activities[
                    self.ziptie.get_index_projection(
                    cog_index).ravel().astype(bool)]
            # Cogs are only allowed to start forming bundles once 
            # the number of cables exceeds the fill_fraction_threshold
            enough_cables = (self.ziptie.cable_fraction_in_bundle(cog_index)
                             > self.fill_fraction_threshold)
            cog_bundle_activities = self.cogs[cog_index].step_up(
                    cog_cable_activities, enough_cables)
            self.bundle_activities = np.concatenate((self.bundle_activities, 
                                                     cog_bundle_activities))
        # Goal fulfillment and decay
        self.hub_cable_goals -= self.cable_activities
        self.hub_cable_goals *= self.ACTIVITY_DECAY_RATE
        self.hub_cable_goals = np.maximum(self.hub_cable_goals, 0.)
        return self.bundle_activities

    def step_down(self, bundle_goals):
        """ Find cable_activity_goals, given a set of bundle_goals """
        bundle_goals = tools.pad(bundle_goals, (self.max_bundles, 1))
        cable_goals = np.zeros((self.max_cables, 1))
        self.surprise = np.zeros((self.max_cables, 1))
        # Process the downward pass of each of the cogs in the level
        cog_index = 0
        for cog in self.cogs:
            # Gather the goal inputs for each cog
            cog_bundle_goals = bundle_goals[
                    cog_index * self.max_bundles_per_cog:
                    cog_index + 1 * self.max_bundles_per_cog,:]
            # Update the downward outputs for the level 
            cable_goals_by_cog = cog.step_down(cog_bundle_goals)
            cog_cable_indices = self.ziptie.get_index_projection(
                    cog_index).ravel().astype(bool)
            cable_goals[cog_cable_indices] = np.maximum(
                    cable_goals_by_cog, cable_goals[cog_cable_indices]) 
            #self.reaction[cog_cable_indices] = np.maximum(
            #        tools.pad(cog.reaction, (cog_cable_indices[0].size, 0)),
            #        self.reaction[cog_cable_indices]) 
            self.surprise[cog_cable_indices] = np.maximum(
                    cog.surprise, self.surprise[cog_cable_indices]) 
            cog_index += 1
        #self.hub_cable_goals = tools.bounded_sum([self.hub_cable_goals, 
        #                                          cable_goals])
        return self.hub_cable_goals 

    def get_index_projection(self, bundle_index):
        """ Represent one of the bundles in terms of its cables """
        # Find which cog it belongs to and which output it corresponds to
        cog_index = int(bundle_index / self.max_bundles_per_cog)
        cog_bundle_index = bundle_index - cog_index * self.max_bundles_per_cog
        # Find the projection to the cog's own cables
        cog_cable_indices = self.ziptie.get_index_projection(
                cog_index).ravel().astype(bool)
        num_cables_in_cog = np.sum(cog_cable_indices)
        cog_projection = self.cogs[cog_index].get_index_projection(
                cog_bundle_index)
        # Then re-sort them to the block's cables
        projection = np.zeros((self.max_cables, 2))
        projection[cog_cable_indices,:] = cog_projection[:num_cables_in_cog,:]
        return projection

    def bundles_created(self):
        total = 0.
        for cog in self.cogs:
            # Check whether all cogs have created all their bundles
                total += cog.num_bundles()
        if np.random.random_sample() < 0.01:
            print total, 'bundles in', self.name, ', max of', self.max_bundles
        return total

    def visualize(self):
        """ Show what's going on inside the level """
        self.ziptie.visualize()
        #for cog in self.cogs:
        #    cog.visualize()
        return
Пример #3
0
Файл: cog.py Проект: 00mjk/becca
class Cog(object):
    """ 
    The basic units of which gearboxes are composed

    Cogs are named for their similarity to clockwork cogwheels.
    They are simple and do the same task over and over, but by
    virtue of how they are connected to their fellows, they 
    collectively bring about interesting behavior.  
    In a conflicting mmetaphor, the inputs to a cog
    are similar to electrical cables: they carry activity 
    signals that vary over time.

    Each cog contains two important parts, a daisychain and a ziptie.
    The daisychain is an object that builds cables into short sequences,
    and the ziptie is an object that takes the resulting chains
    and performs clustering on them, grouping them into bundles.
    During upward processing, cable activities are used to train
    the daisychain and ziptie, making new bundles, maturing existing 
    bundles, and calculating the activity in bundle. 
    During downward processing, 
    the daisychain and ziptie use the bundle activity goals from 
    the next level higher to create goals for the cables. 
    """
    def __init__(self,
                 max_cables,
                 max_bundles,
                 max_chains_per_bundle=None,
                 name='anonymous',
                 level=0):
        """ Initialize the cogs with a pre-determined maximum size """
        self.name = name
        self.max_cables = max_cables
        self.max_bundles = max_bundles
        if max_chains_per_bundle is None:
            max_chains_per_bundle = int(max_cables**2 / max_bundles)
        self.daisychain = DaisyChain(max_cables, name=name)
        if max_bundles > 0:
            self.ziptie = ZipTie(max_cables**2,
                                 max_bundles,
                                 max_cables_per_bundle=max_chains_per_bundle,
                                 name=name)

    def step_up(self, cable_activities, enough_cables):
        """ Cable_activities percolate upward through daisychain and ziptie """
        # TODO: fix this so that cogs can gracefully handle more cables
        # or else never be assigned them in the first place
        if cable_activities.size > self.max_cables:
            cable_activities = cable_activities[:self.max_cables, :]
            print '-----  Number of max cables exceeded in', self.name, \
                    '  -----'
        chain_activities = self.daisychain.step_up(cable_activities)
        self.surprise = self.daisychain.get_surprise()
        if enough_cables is True:
            bundle_activities = self.ziptie.step_up(chain_activities)
        else:
            bundle_activities = np.zeros((0, 1))
        bundle_activities = tools.pad(bundle_activities, (self.max_bundles, 0))
        return bundle_activities

    def step_down(self, bundle_goals):
        """ Bundle_goals percolate downward """
        chain_goals = self.ziptie.step_down(bundle_goals)
        cable_goals = self.daisychain.step_down(chain_goals)
        return cable_goals

    def get_index_projection(self, bundle_index):
        """ Project a bundle down through the ziptie and daisychain """
        chain_projection = self.ziptie.get_index_projection(bundle_index)
        cable_projection = self.daisychain.get_index_projection(
            chain_projection)
        return cable_projection

    def fraction_filled(self):
        """ How full is the set of cables for this cog? """
        return float(self.daisychain.num_cables) / float(self.max_cables)

    def num_bundles(self):
        """ How many bundles have been created in this cog? """
        return self.ziptie.num_bundles

    def visualize(self):
        """ Show the internal state of the daisychain and ziptie """
        #self.daisychain.visualize()
        if self.max_bundles > 0:
            self.ziptie.visualize()
Пример #4
0
class Block(object):
    """
    The building block of which the agent is composed

    Blocks are arranged hierarchically within the agent. 
    The agent begins with only one block, and creates additional
    blocks in a tower arrangement as lower ones mature. 
    
    The block's input channels (cables) are organized 
    into clusters (bundles)
    whose activities are passed up to the next block in the hierarchy.  
    Each block performs the same two functions, 
    1) a step_up 
    where cable activities are converted to bundle activities and
    passed up the tower and 
    2) a step_down where bundle activity goals are passed back down
    and converted into cable activity goals. 
    Internally, a block contains a number of cogs that work in parallel
    to convert cable activities into bundle activities and back again.
    """
    def __init__(self, min_cables, name='anonymous', level=0):
        """ Initialize the level, defining the dimensions of its cogs """
        self.max_cables = int(2**np.ceil(np.log2(min_cables)))
        self.max_cables_per_cog = 8
        self.max_bundles_per_cog = 4
        self.max_cogs = self.max_cables / self.max_bundles_per_cog
        self.max_bundles = self.max_cogs * self.max_bundles_per_cog
        self.name = name
        self.level = level
        ziptie_name = ''.join(('ziptie_', self.name))
        self.ziptie = ZipTie(self.max_cables,
                             self.max_cogs,
                             max_cables_per_bundle=self.max_cables_per_cog,
                             mean_exponent=-2,
                             name=ziptie_name)
        self.cogs = []
        # TODO: only create cogs as needed
        for cog_index in range(self.max_cogs):
            self.cogs.append(
                Cog(self.max_cables_per_cog,
                    self.max_bundles_per_cog,
                    max_chains_per_bundle=self.max_cables_per_cog,
                    name='cog' + str(cog_index),
                    level=self.level))
        self.cable_activities = np.zeros((self.max_cables, 1))
        self.hub_cable_goals = np.zeros((self.max_cables, 1))
        self.fill_fraction_threshold = .7
        self.ACTIVITY_DECAY_RATE = 1.  # real, 0 < x < 1
        # Constants for adaptively rescaling the cable activities
        self.max_vals = np.zeros((self.max_cables, 1))
        self.min_vals = np.zeros((self.max_cables, 1))
        self.RANGE_DECAY_RATE = 10**-5

    def step_up(self, new_cable_activities):
        """ Find bundle_activities that result from new_cable_activities """
        # Condition the cable activities to fall between 0 and 1
        if new_cable_activities.size < self.max_cables:
            new_cable_activities = tools.pad(new_cable_activities,
                                             (self.max_cables, 1))
        self.min_vals = np.minimum(new_cable_activities, self.min_vals)
        self.max_vals = np.maximum(new_cable_activities, self.max_vals)
        spread = self.max_vals - self.min_vals
        new_cable_activities = (
            (new_cable_activities - self.min_vals) /
            (self.max_vals - self.min_vals + tools.EPSILON))
        self.min_vals += spread * self.RANGE_DECAY_RATE
        self.max_vals -= spread * self.RANGE_DECAY_RATE
        # Update cable_activities, incorporating sensing dynamics
        self.cable_activities = tools.bounded_sum([
            new_cable_activities,
            self.cable_activities * (1. - self.ACTIVITY_DECAY_RATE)
        ])

        # Update the map from self.cable_activities to cogs
        self.ziptie.step_up(self.cable_activities)
        # Process the upward pass of each of the cogs in the block
        self.bundle_activities = np.zeros((0, 1))
        for cog_index in range(len(self.cogs)):
            # Pick out the cog's cable_activities, process them,
            # and assign the results to block's bundle_activities
            cog_cable_activities = self.cable_activities[
                self.ziptie.get_index_projection(cog_index).ravel().astype(
                    bool)]
            # Cogs are only allowed to start forming bundles once
            # the number of cables exceeds the fill_fraction_threshold
            enough_cables = (self.ziptie.cable_fraction_in_bundle(cog_index) >
                             self.fill_fraction_threshold)
            cog_bundle_activities = self.cogs[cog_index].step_up(
                cog_cable_activities, enough_cables)
            self.bundle_activities = np.concatenate(
                (self.bundle_activities, cog_bundle_activities))
        # Goal fulfillment and decay
        self.hub_cable_goals -= self.cable_activities
        self.hub_cable_goals *= self.ACTIVITY_DECAY_RATE
        self.hub_cable_goals = np.maximum(self.hub_cable_goals, 0.)
        return self.bundle_activities

    def step_down(self, bundle_goals):
        """ Find cable_activity_goals, given a set of bundle_goals """
        bundle_goals = tools.pad(bundle_goals, (self.max_bundles, 1))
        cable_goals = np.zeros((self.max_cables, 1))
        self.surprise = np.zeros((self.max_cables, 1))
        # Process the downward pass of each of the cogs in the level
        cog_index = 0
        for cog in self.cogs:
            # Gather the goal inputs for each cog
            cog_bundle_goals = bundle_goals[
                cog_index * self.max_bundles_per_cog:cog_index +
                1 * self.max_bundles_per_cog, :]
            # Update the downward outputs for the level
            cable_goals_by_cog = cog.step_down(cog_bundle_goals)
            cog_cable_indices = self.ziptie.get_index_projection(
                cog_index).ravel().astype(bool)
            cable_goals[cog_cable_indices] = np.maximum(
                cable_goals_by_cog, cable_goals[cog_cable_indices])
            #self.reaction[cog_cable_indices] = np.maximum(
            #        tools.pad(cog.reaction, (cog_cable_indices[0].size, 0)),
            #        self.reaction[cog_cable_indices])
            self.surprise[cog_cable_indices] = np.maximum(
                cog.surprise, self.surprise[cog_cable_indices])
            cog_index += 1
        #self.hub_cable_goals = tools.bounded_sum([self.hub_cable_goals,
        #                                          cable_goals])
        return self.hub_cable_goals

    def get_index_projection(self, bundle_index):
        """ Represent one of the bundles in terms of its cables """
        # Find which cog it belongs to and which output it corresponds to
        cog_index = int(bundle_index / self.max_bundles_per_cog)
        cog_bundle_index = bundle_index - cog_index * self.max_bundles_per_cog
        # Find the projection to the cog's own cables
        cog_cable_indices = self.ziptie.get_index_projection(
            cog_index).ravel().astype(bool)
        num_cables_in_cog = np.sum(cog_cable_indices)
        cog_projection = self.cogs[cog_index].get_index_projection(
            cog_bundle_index)
        # Then re-sort them to the block's cables
        projection = np.zeros((self.max_cables, 2))
        projection[
            cog_cable_indices, :] = cog_projection[:num_cables_in_cog, :]
        return projection

    def bundles_created(self):
        total = 0.
        for cog in self.cogs:
            # Check whether all cogs have created all their bundles
            total += cog.num_bundles()
        if np.random.random_sample() < 0.01:
            print total, 'bundles in', self.name, ', max of', self.max_bundles
        return total

    def visualize(self):
        """ Show what's going on inside the level """
        self.ziptie.visualize()
        #for cog in self.cogs:
        #    cog.visualize()
        return
Пример #5
0
class Gearbox(object):
    """
    The building block of which the drivetrain is composed

    Gearboxes are arranged hierarchically within the agent's drivetrain. 
    The agent begins with only one gearbox, and creates subsequent
    gearboxes as previous ones mature. 
    
    The gearbox's inputs (cables) are organized into clusters (bundles)
    whose activities are passed up to the next gearbox in the hierarchy.  
    """
    def __init__(self, min_cables, name='anonymous', level=0):
        """ 
        Initialize the level, defining the dimensions of its cogs 
        """
        self.max_cables = int(2 ** np.ceil(np.log2(min_cables)))
        #self.max_cables_per_cog = 16
        #self.max_bundles_per_cog = 8
        #self.max_cogs = self.max_cables / self.max_bundles_per_cog
        #self.max_bundles = self.max_cogs * self.max_bundles_per_cog
        self.max_bundles = self.max_cables
        self.name = name
        self.level = level
        ziptie_name = ''.join([self.name, '_ziptie'])
        self.ziptie = ZipTie(self.max_cables, self.max_bundles, 
                             name=ziptie_name, in_gearbox=True)
        '''
        self.ziptie = ZipTie(self.max_cables, self.max_cogs, 
                             max_cables_per_bundle=self.max_cables_per_cog,
                             name=ziptie_name, in_gearbox=True)
        self.cogs = []
        # TODO: only create cogs as needed
        for cog_index in range(self.max_cogs):
            self.cogs.append(Cog(self.max_cables_per_cog, 
                                 self.max_bundles_per_cog,
                                 max_chains_per_bundle=self.max_cables_per_cog,
                                 name='_'.join(['cog', str(cog_index),
                                                self.name]), 
                                 level=self.level))
        '''
        self.cable_activities = np.zeros((self.max_cables, 1))
        self.bundle_activities = np.zeros((self.max_bundles, 1))
        #self.raw_cable_activities = np.zeros((self.max_cables, 1))
        #self.previous_cable_activities = np.zeros((self.max_cables, 1))
        #self.cable_goals = np.zeros((self.max_cables, 1))
        #self.fill_fraction_threshold = 0.
        #self.step_multiplier = int(2 ** self.level)
        #self.step_counter = 1000000
        # The rate at which cable activities decay (float, 0 < x < 1)
        self.ACTIVITY_DECAY_RATE = 2 ** (-self.level)
        # Constants for adaptively rescaling the cable activities
        #self.max_vals = np.zeros((self.max_cables, 1)) 
        #self.min_vals = np.zeros((self.max_cables, 1))
        #self.RANGE_DECAY_RATE = 1e-10
        
    def step_up(self, new_cable_activities):
        """ 
        Find bundle_activities that result from new_cable_activities 
        """
        if new_cable_activities.size < self.max_cables:
            new_cable_activities = tools.pad(new_cable_activities, 
                                             (self.max_cables, 1))
        # Update cable_activities
        #self.raw_cable_activities *= 1. - (self.ACTIVITY_DECAY_RATE /
        #                                   float(self.step_multiplier))
        #self.raw_cable_activities += new_cable_activities
        #self.step_counter += 1
        #if self.step_counter < self.step_multiplier:
        #    return self.bundle_activities
        # Condition the cable activities to fall between 0 and 1
        #self.min_vals = np.minimum(self.raw_cable_activities, self.min_vals)
        #self.max_vals = np.maximum(self.raw_cable_activities, self.max_vals)
        #spread = self.max_vals - self.min_vals
        #self.cable_activities = ((self.raw_cable_activities - self.min_vals) / 
        #           (self.max_vals - self.min_vals + tools.EPSILON))
        #self.min_vals += spread * self.RANGE_DECAY_RATE
        #self.max_vals -= spread * self.RANGE_DECAY_RATE
        
        # debug: don't adapt cable activities 
        self.cable_activities = new_cable_activities
        self.cable_activities = tools.bounded_sum2(self.cable_activities,
                                                  new_cable_activities * 
                                                  self.ACTIVITY_DECAY_RATE)

        '''
        cluster_training_activities = np.maximum(
                self.previous_cable_activities, self.cable_activities)
        self.previous_cable_activities = self.cable_activities.copy() 
        # Update the map from self.cable_activities to cogs
        self.ziptie.step_up(cluster_training_activities)
        '''
        self.bundle_activities = self.ziptie.step_up(self.cable_activities)
        # Process the upward pass of each of the cogs in the gearbox
        #self.bundle_activities = np.zeros((0, 1))
        '''
        for cog_index in range(len(self.cogs)):
            # Pick out the cog's cable_activities, process them, 
            # and assign the results to gearbox's bundle_activities
            cog_cable_activities = self.cable_activities[
                    self.ziptie.get_index_projection(
                    cog_index).astype(bool)]
            # Cogs are only allowed to start forming bundles once 
            # the number of cables exceeds the fill_fraction_threshold
            enough_cables = (self.ziptie.cable_fraction_in_bundle(cog_index)
                             > self.fill_fraction_threshold)
            cog_bundle_activities = self.cogs[cog_index].step_up(
                    cog_cable_activities, enough_cables)
            self.bundle_activities = np.concatenate((self.bundle_activities, 
                                                     cog_bundle_activities))
        # Goal fulfillment and decay
        self.cable_goals -= self.cable_activities
        self.cable_goals *= self.ACTIVITY_DECAY_RATE
        self.cable_goals = np.maximum(self.cable_goals, 0.)
        '''

        # debug: no bundle activities
        #self.bundle_activities = np.zeros(self.bundle_activities.shape)
        
        return self.bundle_activities
        '''
    def step_down(self, bundle_goals):
        """ 
        Find cable_activity_goals, given a set of bundle_goals 
        """
        # debug
        #if self.step_counter < self.step_multiplier:
        #    if 'self.hub_bundle_goals' not in locals():
        #        self.hub_bundle_goals = np.zeros((self.max_cables, 1))
        #    return self.hub_bundle_goals
        #else:
        #    self.step_counter = 0
        if 'self.hub_bundle_goals' not in locals():
            self.hub_bundle_goals = np.zeros((self.max_cables, 1))

        bundle_goals = tools.pad(bundle_goals, (self.max_bundles, 1))
        # debug: don't propogate any goals downward
        #bundle_goals = np.zeros(bundle_goals.shape)

        new_cable_goals = np.zeros((self.max_cables, 1))
        # Process the downward pass of each of the cogs in the level
        cog_index = 0
        for cog in self.cogs:
            # Gather the goal inputs for each cog
            cog_bundle_goals = bundle_goals[
                    cog_index * self.max_bundles_per_cog:
                    cog_index + 1 * self.max_bundles_per_cog,:]
            # Update the downward outputs for the level 
            cable_goals_by_cog = cog.step_down(cog_bundle_goals)
            cog_cable_indices = self.ziptie.get_index_projection(
                    cog_index).astype(bool)
            new_cable_goals[cog_cable_indices] = np.maximum(
                    cable_goals_by_cog, new_cable_goals[cog_cable_indices]) 
            cog_index += 1
        self.cable_goals = tools.bounded_sum([self.cable_goals, 
                                              new_cable_goals])
        return self.cable_goals 
        '''

    def get_index_projection(self, bundle_index):
        """ 
        Represent one of the bundles in terms of its cables 
        """
        '''
        # Find which cog it belongs to and which output it corresponds to
        cog_index = int(bundle_index / self.max_bundles_per_cog)
        cog_bundle_index = bundle_index - cog_index * self.max_bundles_per_cog
        # Find the projection to the cog's own cables
        cog_cable_indices = self.ziptie.get_index_projection(
                cog_index).astype(bool)
        num_cables_in_cog = np.sum(cog_cable_indices)
        cog_projection = self.cogs[cog_index].get_index_projection(
                cog_bundle_index)
        # Then re-sort them to the gearbox's cables
        projection = np.zeros((self.max_cables, 2))
        projection[cog_cable_indices,:] = cog_projection[:num_cables_in_cog,:]
        '''
        projection = self.ziptie.get_index_projection(bundle_index)
        return projection

    def bundles_created(self):
        """
        How many bundles have been created in the gearbox in total?
        """
        #total = 0.
        #for cog in self.cogs:
        #        total += cog.num_bundles()
        return self.ziptie.num_bundles

    def visualize(self):
        print self.name
        self.ziptie.visualize()
Пример #6
0
class Cog(object):
    """ 
    The basic units of which blocks are composed

    Cogs are named for their similarity to clockwork cogwheels.
    They are simple and do the same task over and over, but by
    virtue of how they are connected to their fellows, they 
    collectively bring about interesting behavior.  

    Input channels are similar to cables in that they carry activity 
    signals that vary over time.
    Each cog contains two important parts, a daisychain and a ziptie.
    The daisychain is an object that builds cables into short sequences,
    and the ziptie is an object that takes the resulting chains
    and performs clustering on them, creating bundles.
    During upward processing, cable activities are used to train
    the daisychain and ziptie, making new bundles, maturing existing 
    bundles, and calculating the activity in bundle. 
    During downward processing, 
    the daisychain and ziptie use the bundle activity goals from 
    the next level higher to create goals for the cables. 
    """
    def __init__(self, max_cables, max_bundles, max_chains_per_bundle=None,
                 name='anonymous', level=0):
        """ Initialize the cogs with a pre-determined maximum size """
        self.name = name
        self.max_cables = max_cables
        self.max_bundles = max_bundles
        if max_chains_per_bundle is None:
            max_chains_per_bundle = int(max_cables ** 2 / max_bundles)
        self.daisychain = DaisyChain(max_cables, name=name)        
        if max_bundles > 0:
            self.ziptie = ZipTie(max_cables **2, max_bundles, 
                                 max_cables_per_bundle=max_chains_per_bundle, 
                                 name=name)

    def step_up(self, cable_activities, reward, enough_cables):
        # TODO: fix this so that cogs can gracefully handle more cables 
        # or else never be assigned them in the first place
        if cable_activities.size > self.max_cables:
            cable_activities = cable_activities[:self.max_cables, :]
            print '-----  Number of max cables exceeded in', self.name, \
                    '  -----'
        """ cable_activities percolate upward through daisychain and ziptie """
        chain_activities = self.daisychain.update(cable_activities, reward) 
        self.reaction= self.daisychain.get_cable_activity_reactions()
        self.surprise = self.daisychain.get_surprise()
        if enough_cables is True:
            bundle_activities = self.ziptie.update(chain_activities)
        else:
            bundle_activities = np.zeros((0,1))
        bundle_activities = tools.pad(bundle_activities, (self.max_bundles, 0))
        return bundle_activities

    def step_down(self, bundle_activity_goals):
        """ bundle_activity_goals percolate downward """
        chain_activity_goals = self.ziptie.get_cable_deliberation_vote(
                bundle_activity_goals) 
        instant_cable_activity_goals = self.daisychain.deliberate(
                chain_activity_goals)     
        self.cable_activity_goals =self.daisychain.get_cable_deliberation_vote()
        return instant_cable_activity_goals

    def get_projection(self, bundle_index):
        """ Project a bundle down through the ziptie and daisychain """
        chain_projection = self.ziptie.get_projection(bundle_index)
        cable_projection = self.daisychain.get_projection(chain_projection)
        return cable_projection
         
    def fraction_filled(self):
        """ How full is the set of cables for this cog? """
        return float(self.daisychain.num_cables) / float(self.max_cables)

    def num_bundles(self):
        """ How many bundles have been created in this cog? """
        return self.ziptie.num_bundles
            
    def visualize(self):
        """ Show the internal state of the daisychain and ziptie """
        self.daisychain.visualize()
        if self.max_bundles > 0:
            self.ziptie.visualize()
        return