Beispiel #1
0
    def create(self, otherchunk, actrvariables=None):
        """
        Create (aka set) a chunk for manual control. The chunk is returned (and could be used by device or external environment).
        """
        if actrvariables == None:
            actrvariables = {}
        try:
            mod_attr_val = {
                x[0]: utilities.check_bound_vars(actrvariables, x[1])
                for x in otherchunk.removeunused()
            }  #creates dict of attr-val pairs according to otherchunk
        except ACTRError as arg:
            raise ACTRError(
                "Setting the chunk '%s' in the manual buffer is impossible; %s"
                % (otherchunk, arg))

        new_chunk = chunks.Chunk(self._MANUAL,
                                 **mod_attr_val)  #creates new chunk

        if new_chunk.cmd.values not in utilities.CMDMANUAL:
            raise ACTRError(
                "Motor module received an invalid command: '%s'. The valid commands are: '%s'"
                % (new_chunk.cmd.values, utilities.CMDMANUAL))

        if new_chunk.cmd.values == utilities.CMDPRESSKEY:
            pressed_key = new_chunk.key.values.upper(
            )  #change key into upper case
            mod_attr_val["key"] = pressed_key
            new_chunk = chunks.Chunk(self._MANUAL,
                                     **mod_attr_val)  #creates new chunk
        if pressed_key not in self.LEFT_HAND and new_chunk.key.values not in self.RIGHT_HAND:
            raise ACTRError("Motor module received an invalid key: %s" %
                            pressed_key)

        return new_chunk
Beispiel #2
0
def chunktype(cls_name, field_names, defaults=None):
    """
    Creates type chunk. Works like namedtuple.

    For example:
    >>> chunktype('chunktype_example0', 'value')

    :param field_names: an iterable or a string of slot names separated by spaces
    :param defaults: default values for the slots, given as an iterable, counting from the last element
    """
    if cls_name in utilities.SPECIALCHUNKTYPES and field_names != utilities.SPECIALCHUNKTYPES[cls_name]:
        raise ACTRError("You cannot redefine slots of the chunk type '%s'; you can only use the slots '%s'" % (cls_name, utilities.SPECIALCHUNKTYPES[cls_name]))

    try:
        field_names = field_names.replace(',', ' ').split()
    except AttributeError:  # no .replace or .split
        pass  # assume it's already a sequence of identifiers
    field_names = tuple(sorted(name + "_" for name in field_names))
    for each in field_names:
        if each == "ISA" or each == "isa":
            raise ACTRError("You cannot use the slot 'isa' in your chunk. That slot is used to define chunktypes.")
    try:
        Chunk._chunktypes.update({cls_name:collections.namedtuple(cls_name, field_names, defaults=defaults)}) #chunktypes are not returned; they are stored as Chunk class attribute
    except TypeError:
        Chunk._chunktypes.update({cls_name:collections.namedtuple(cls_name, field_names)}) #chunktypes are not returned; they are stored as Chunk class attribute
Beispiel #3
0
def chunktype(cls_name, field_names, verbose=False):
    """
    Creates type chunk. Works like namedtuple.

    For example:
    >>> chunktype('chunktype_example0', 'value')
    """
    if cls_name in utilities.SPECIALCHUNKTYPES and field_names != utilities.SPECIALCHUNKTYPES[
            cls_name]:
        raise ACTRError(
            "You cannot redefine slots of the chunk type '%s'; you can only use the slots '%s'"
            % (cls_name, utilities.SPECIALCHUNKTYPES[cls_name]))

    try:
        field_names = field_names.replace(',', ' ').split()
    except AttributeError:  # no .replace or .split
        pass  # assume it's already a sequence of identifiers
    field_names = tuple(sorted(name + "_" for name in field_names))
    for each in field_names:
        if each == "ISA" or each == "isa":
            raise ACTRError(
                "You cannot use the slot 'isa' in your chunk. That slot is used to define chunktypes."
            )

    Chunk._chunktypes.update({
        cls_name:
        collections.namedtuple(cls_name, field_names, verbose=verbose)
    })  #chunktypes are not returned; they are stored as Chunk class attribute
Beispiel #4
0
 def default_harvest(self, value):
     try:
         self.dm = value
     except ValueError:
         raise ACTRError(
             'The default harvest set in the goal buffer is not a possible declarative memory'
         )
Beispiel #5
0
    def update(self, RHSdictionary, time):
        """
        Update buffers (RHS of production rules).
        """
        temp_actrvariables = dict(self.__actrvariables)
        ordering_dict = {"!": 0, "?": 0, "=": 1, "@": 2, "*": 3, "+": 4, "~": 5}
        try:
            dictionary = collections.OrderedDict.fromkeys(sorted(RHSdictionary, key=lambda x:ordering_dict[x[0]]))
        except KeyError:
            raise ACTRError("The RHS rule '%s' is invalid; every condition in RHS rules must start with one of these signs: %s" % (self.used_rulename, list(self._RHSCONVENTIONS.keys())))
        dictionary.update(RHSdictionary)
        for key in dictionary:
            submodule_name = key[1:] #this is the name of updated submodule
            code = key[0] #this is what the key should do
            
            try:
                temp_actrvariables.pop("=" + submodule_name) #pop used submodule (needed for strict harvesting)
            except KeyError:
                pass
            updated = self.buffers[submodule_name]
            production = getattr(self, self._RHSCONVENTIONS[code])(submodule_name, updated, dictionary[key], self.__actrvariables, time)

            updated.state = updated._BUSY

            if production.__name__ in self._INTERRUPTIBLE:
                self.procs.append((submodule_name, production)) 
            else:
                yield from production #this either moves production on to modify, retrieve etc. (see RHSCONVENTIONS for the list), or it appends that process to the processes that have to be done as an extra process by model, i.e., not directly by productions (distinction made as in ACT-R)

        #this last part is strict harvesting
        if self.model_parameters["strict_harvesting"]:
            for key in temp_actrvariables:
                submodule_name = key[1:]
                if submodule_name in self.buffers:
                    self.procs.append((submodule_name, self.clear(submodule_name, self.buffers[submodule_name], None, self.__actrvariables, time)))
Beispiel #6
0
    def shift(self, otherchunk, harvest=None, actrvariables=None):
        """
        Return a chunk, time needed to attend and shift eye focus to the chunk, and the landing site of eye mvt.
        """
        if actrvariables == None:
            actrvariables = {}
        try:
            mod_attr_val = {x[0]: utilities.check_bound_vars(actrvariables, x[1]) for x in otherchunk.removeunused()} #creates dict of attr-val pairs according to otherchunk
        except ACTRError as arg:
            raise ACTRError("The chunk '%s' is not defined correctly; %s" % (otherchunk, arg))

        vis_delay = None

        for each in self.environment.stimulus:
            try:
                if self.environment.stimulus[each]['position'] == (float(mod_attr_val['screen_pos'].screen_x), float(mod_attr_val['screen_pos'].screen_y)):
                    mod_attr_val['value'] = self.environment.stimulus[each]['text']
                    vis_delay = self.environment.stimulus[each].get('vis_delay')
            except (AttributeError, KeyError):
                raise ACTRError("The chunk in the visual buffer is not defined correctly. It is not possible to move attention.")

        new_chunk = chunks.Chunk(self._VISUAL, **mod_attr_val) #creates new chunk

        if new_chunk.cmd not in utilities.CMDVISUAL:
            raise ACTRError("Visual module received an invalid command: '%s'. The valid commands are: '%s'" % (new_chunk.cmd, utilities.CMDVISUAL))

        if new_chunk.cmd == utilities.CMDMOVEATTENTION and self.model_parameters['emma']:
            angle_distance = utilities.calculate_visual_angle(self.current_focus, [float(new_chunk.screen_pos.screen_x), float(new_chunk.screen_pos.screen_y)], self.environment.size, self.environment.simulated_screen_size, self.environment.viewing_distance)
            encoding_time = utilities.calculate_delay_visual_attention(angle_distance=angle_distance, K=self.model_parameters["eye_mvt_scaling_parameter"], k=self.model_parameters['eye_mvt_angle_parameter'], emma_noise=self.model_parameters['emma_noise'], vis_delay=vis_delay)
            preparation_time = utilities.calculate_preparation_time(emma_noise=self.model_parameters['emma_noise'])
            execution_time = utilities.calculate_execution_time(angle_distance, emma_noise=self.model_parameters['emma_noise'])
            landing_site = utilities.calculate_landing_site([float(new_chunk.screen_pos.screen_x), float(new_chunk.screen_pos.screen_y)], angle_distance, emma_landing_site_noise=self.model_parameters['emma_landing_site_noise'])
        elif new_chunk.cmd == utilities.CMDMOVEATTENTION and not self.model_parameters['emma']:
            encoding_time = 0.085
            preparation_time = 0
            execution_time = 0.085
            landing_site = (float(new_chunk.screen_pos.screen_x), float(new_chunk.screen_pos.screen_y))
        else:
            raise ACTRError("Visual module received an invalid command: '%s'. The only valid command currently is: %s" % (new_chunk.cmd, utilities.CMDMOVEATTENTION))
        return new_chunk, (encoding_time, preparation_time, execution_time), landing_site
    def shift(self, otherchunk, harvest=None, actrvariables=None, model_parameters=None):
        """
        Return a chunk, time needed to attend and shift eye focus to the chunk, and the landing site of eye mvt.
        """
        if model_parameters == None:
            model_parameters = {}
        model_parameters = model_parameters.copy()
        model_parameters.update(self.model_parameters)

        if actrvariables == None:
            actrvariables = {}
        try:
            mod_attr_val = {x[0]: utilities.check_bound_vars(actrvariables, x[1]) for x in otherchunk.removeunused()}
        except ACTRError as arg:
            raise ACTRError("Shifting towards the chunk '%s' is impossible; %s" % (otherchunk, arg))

        vis_delay = None

        for each in self.environment.stimulus:
            try:
                if self.environment.stimulus[each]['position'] == (float(mod_attr_val['screen_pos'].values.screen_x.values), float(mod_attr_val['screen_pos'].values.screen_y.values)):
                    mod_attr_val['value'] = self.environment.stimulus[each]['text']
                    vis_delay = self.environment.stimulus[each].get('vis_delay')
            except (AttributeError, KeyError):
                raise ACTRError("The chunk in the visual buffer is not defined correctly. It is not possible to move attention.")

        new_chunk = chunks.Chunk(self._VISUAL, **mod_attr_val) #creates new chunk

        if model_parameters['emma']:
            angle_distance = utilities.calculate_visual_angle(self.environment.current_focus, [float(new_chunk.screen_pos.values.screen_x.values), float(new_chunk.screen_pos.values.screen_y.values)], self.environment.size, self.environment.simulated_screen_size, self.environment.viewing_distance)
            encoding_time = utilities.calculate_delay_visual_attention(angle_distance=angle_distance, K=model_parameters["eye_mvt_scaling_parameter"], k=model_parameters['eye_mvt_angle_parameter'], emma_noise=model_parameters['emma_noise'], vis_delay=vis_delay)
            preparation_time = utilities.calculate_preparation_time(emma_noise=model_parameters['emma_noise'], emma_preparation_time=model_parameters['emma_preparation_time'])
            execution_time = utilities.calculate_execution_time(angle_distance, emma_noise=model_parameters['emma_noise'])
            landing_site = utilities.calculate_landing_site([float(new_chunk.screen_pos.values.screen_x.values), float(new_chunk.screen_pos.values.screen_y.values)], angle_distance, emma_landing_site_noise=model_parameters['emma_landing_site_noise'])
        elif not model_parameters['emma']:
            encoding_time = 0.085
            preparation_time = 0
            execution_time = 0.085
            landing_site = (float(new_chunk.screen_pos.values.screen_x.values), float(new_chunk.screen_pos.values.screen_y.values))
        return new_chunk, (encoding_time, preparation_time, execution_time), landing_site
Beispiel #8
0
    def retrieveorset(self, name, updated, otherchunk, temp_actrvariables, time):
        """
        Find out whether a buffer should be set (for buffers that are not attached to any dm, i.e., Goal or Motor or Vision) or should trigger retrieval.
        """
        updated.state = updated._BUSY
        if isinstance(updated, goals.Goal):
            yield from self.clear(name, updated, otherchunk, temp_actrvariables, time, freeing=False)
            extra_time = utilities.calculate_setting_time(updated)
            time += extra_time
            yield Event(roundtime(time), name, self._UNKNOWN)
            if self.model_parameters['production_compilation']:
                RHSdict = otherchunk._asdict()
                RHSdict = {item[0]: item[1] for item in RHSdict.items()}
                self.current_slotvals[name] = RHSdict

            updated.create(otherchunk, list(self.dm.values())[0], temp_actrvariables)
            created_elem = list(updated)[0]
            updated.state = updated._FREE
            yield Event(roundtime(time), name, "CREATED A CHUNK: %s" % str(created_elem))
        elif isinstance(updated, vision.VisualLocation):
            extra_time = utilities.calculate_setting_time(updated)
            time += extra_time #0 ms to create chunk in location (pop-up effect)
            yield Event(roundtime(time), name, self._UNKNOWN)
            chunk, stim = updated.find(otherchunk, actrvariables=temp_actrvariables, extra_tests=self.extra_tests.get(name, {})) #extra_time currently ignored
            if chunk:
                yield from self.clear(name, updated, None, temp_actrvariables, time, freeing=False)
                updated.add(chunk, stim, time)
                updated.state = updated._FREE
            else:
                updated.state = updated._ERROR
            yield Event(roundtime(time), name, "ENCODED LOCATION:'%s'" % str(chunk))
        elif isinstance(updated, vision.Visual):
            mod_attr_val = {x[0]: utilities.check_bound_vars(temp_actrvariables, x[1]) for x in otherchunk.removeunused()}
            if (not mod_attr_val['cmd'].values) or mod_attr_val['cmd'].values not in utilities.CMDVISUAL:
                raise ACTRError("Visual module received no command or an invalid command: '%s'. The valid commands are: '%s'" % (mod_attr_val['cmd'].values, utilities.CMDVISUAL))
            if mod_attr_val['cmd'].values == utilities.CMDMOVEATTENTION:
                ret = yield from self.visualshift(name, updated, otherchunk, temp_actrvariables, time)
                return ret #visual action returns value, namely, its continuation method
            elif mod_attr_val['cmd'].values == utilities.CMDCLEAR:
                updated.stop_automatic_buffering()
                updated.state = updated._FREE
                yield Event(roundtime(time), name, "VISUAL STOPPED FROM AUTOMATIC BUFFERING AT ITS CURRENT FOCUS")
        elif isinstance(updated, motor.Motor):
            ret = yield from self.motorset(name, updated, otherchunk, temp_actrvariables, time)
            return ret #motor action returns value, namely, its continuation method
        else:
            yield from self.retrieve(name, updated, otherchunk, temp_actrvariables, time)
Beispiel #9
0
 def LHStest(self, dictionary, actrvariables, update=False):
     """
     Test rules in LHS of production rules. update specifies whether actrvariables should be updated (this does not happen when rules are tested, only when they are fired)
     """
     for key in dictionary:
         submodule_name = key[1:] #this is the module
         code = key[0] #this is what the module should do; standardly, query, i.e., ?, or test, =
         if code not in self._LHSCONVENTIONS:
             raise ACTRError("The LHS rule '%s' is invalid; every condition in LHS rules must start with one of these signs: %s" % (self.used_rulename, list(self._LHSCONVENTIONS.keys())))
         result = getattr(self, self._LHSCONVENTIONS[code])(submodule_name, self.buffers.get(submodule_name), dictionary[key], actrvariables)
         if not result[0]:
             return False
         else:
             actrvariables.update(result[1])
     if update:
         self.__actrvariables = actrvariables
     return True
Beispiel #10
0
 def clear(self, name, cleared, optional, temp_actrvariables, time, freeing=True):
     """
     Clear a buffer. The 'freeing' argument specifies whether the state should be considered FREE (if the rule is run alone) or not (if it is embedded in another rule).
     """
     cleared.state = cleared._BUSY
     try:
         cleared.clear(time) #clear the buffer; works for decl. mem. buffers (tied to a specific decl. mem)
     except AttributeError: #unless it fails because the cleared chunk cannot be added anywhere
         if len(self.dm) == 1:
             cleared.clear(time, list(self.dm.values())[0]) #if there is only one memory, add the chunk there
         elif optional:
             cleared.clear(time, self.dm[optional]) #if not, optional must specify memory where chunk should be added
         else:
             try:
                 cleared.clear(time, self.dm[name]) #if nothing else works, check whether buffer instance was bound to a decl. mem by user
             except KeyError:
                 raise ACTRError("It is not specified to what memory the buffer %s should be cleared" % name)
     yield Event(roundtime(time), name, "CLEARED")
     if freeing:
         cleared.state = cleared._FREE