def add(m, num1, num2): # formulate the task at hand as a 'goal' m.goal = Chunk(name='goal', slots={ 'isa': 'add-goal', 'sum': num1, 'counter': 'zero' }) while not m.goal.slots['counter'] == num2: # formulate a request for the next number after the current sum sum_request = Chunk(name='request', slots={ 'isa': 'count-fact', 'num1': m.goal.slots['sum'] }) # add the time it takes to create the request m.time += 0.05 # retrieve the chunk from declarative memory sum_chunk, sum_latency = m.retrieve(sum_request) m.add_encounter(sum_chunk) # add the time it takes to retrieve the chunk m.time += sum_latency # formulate a request for the next number after the current counter cnt_request = Chunk(name='request', slots={ 'isa': 'count-fact', 'num1': m.goal.slots['counter'] }) # add the time it takes to create the request m.time += 0.05 # retrieve the chunk from declarative memory cnt_chunk, cnt_latency = m.retrieve(cnt_request) m.add_encounter(cnt_chunk) # add the time it takes to retrieve the chunk m.time += cnt_latency # add the time it takes to say a number m.time += 0.3 # print the number that was just said and the time elapsed print(m.time) print(m.goal.slots['sum']) # update the sum so we know where we are m.goal.slots['sum'] = sum_chunk.slots['num2'] # update the counter so we know when to stop m.goal.slots['counter'] = cnt_chunk.slots['num2'] print(m.time) print(m.goal.slots['sum'])
def do_trial(subj: Model, distribution) -> float: # Participants click the mouse after a time of their choosing to start # Time of their choosing is interpreted here as a uniform time in 0.5-3s subj.time += sum(rng.uniform(0.500, 3.000, size=1)) # click # x ms delay (sampled from distribution), then the yellow dot was flashed sample_interval = distribution.rvs(1) / 1000 subj.time += sample_interval # flash # Take the same model as in the previous homeworks as a baseline # Convert time to pulses and remember how many it took counted_pulses = time_to_pulses(sample_interval) subj.add_encounter(Chunk( name=f'pf_{counted_pulses}', slots={'isa': 'pulse-fact', 'pulses': counted_pulses} )) # Flash is shown for 18.5ms subj.time += 0.0185 # end flash # Retrieve a blended trace request = Chunk( name='pulse-request', slots={'isa': 'pulse-fact'} ) estimated_pulses, _ = subj.retrieve_blended_trace(request, 'pulses') # Convert pulses back to time response_interval = pulses_to_time(estimated_pulses) # Subjects were required to wait at least 250ms before reproducing. # 'at least' is interpreted here as a uniform distribution from 250-350ms # TODO: i guess it would actually be more skewed towards 250ms subj.time += sum(rng.uniform(0.250, 0.350, size=1)) # end wait # Interval is estimated and reproduced by holding the mouse click subj.time += response_interval # release mouse click # Feedback is represented after a uniformly sampled delay (450-850ms) subj.time += sum(rng.uniform(0.450, 0.850, size=1)) # end delay # Feedback is presented for 62ms error = get_error(sample_interval, response_interval) subj.time += 0.062 # end feedback # Fixation cross disappears after 500-750ms, followed by a blank screen for # another 500-750ms and then the trial restarts. interpreted as uniform. subj.time += sum(rng.uniform(0.500, 0.750, size=2)) return sample_interval, response_interval, error
def do_trial(subj: Model, sample_interval: float) -> float: """This function takes a subject and an interval time, and goes through the process of an experiment trial. Args: subj (Model): The subject which will do the trial. sample_interval (float): The interval time defining the trial. Returns: float: The (re)production time. """ # "Trials began with the presentation of a central fixation point for 1s," subj.time += 1 # "followed by the presentation of a warning stimulus ..." # "After a variable delay ranging from 0.25-0.85s drawn randomly from a # truncated exponential distribution, ..." subj.time += truncexpon(0.6, 0.25).rvs(1, random_state=rng)[0] # "two 100ms flashes separated by the sample interval were presented." subj.time += 0.1 # READY subj.time += sample_interval # convert time to pulses and remember how many it took pulses = time_to_pulses(sample_interval) subj.add_encounter( Chunk(name=f'pf_{pulses}', slots={ 'isa': 'pulse-fact', 'pulses': pulses })) # "Production times, t_p, were measured from the center of the flash, (that # is, 50ms after its onset) to when the key was pressed" subj.time += 0.05 # SET # retrieve the most activated memory request = Chunk(name='pulse-request', slots={'isa': 'pulse-fact'}) chunk, latency = subj.retrieve(request) subj.add_encounter(chunk) subj.time += latency # convert pulse to time, then add and return the production time production_time = pulses_to_time(chunk.slots['pulses']) subj.time += production_time # GO return production_time
def count_from(m, start, end): # formulate the task at hand as a 'goal' m.goal = Chunk(name='goal', slots={ 'isa': 'count-goal', 'start': start, 'end': end, 'current': start }) while not m.goal.slots['current'] == m.goal.slots['end']: # formulate a request for the next number after 'current' request = Chunk(name='request', slots={ 'isa': 'count-fact', 'num1': m.goal.slots['current'] }) # add the time it takes to create the request m.time += 0.05 # retrieve the chunk from declarative memory chunk, latency = m.retrieve(request) m.add_encounter(chunk) # add the time it takes to retrieve the chunk m.time += latency # add the time it takes to say a number m.time += 0.3 # print the number that was just said and the time elapsed print(m.time) print(m.goal.slots['current']) # update current so we can look for the next number m.goal.slots['current'] = chunk.slots['num2'] print(m.time) print(m.goal.slots['current'])
def init_model(): # create a model m = Model() # instantiate the declarative knowledge of how to count to 6 for num1, num2 in zip(numbers, numbers[1:]): fact = Chunk(name=f'cf_{num1}-{num2}', slots={ 'isa': 'count-fact', 'num1': num1, 'num2': num2 }) m.add_encounter(fact) return m
def add_encounter(self, chunk): """ Add an encounter of a specified chunk at the current time. If the chunk does not exist yet, create it first. """ update_fan = False # If a chunk by this name does not yet exist, add it to DM if chunk.name not in [chunk.name for chunk in self.dm]: self.dm.append(chunk) update_fan = True # If a chunk by this name does exist, ensure that it has the same slots and slot values chunk_idx = [i for i, j in enumerate(self.dm) if j.name == chunk.name][0] if self.dm[chunk_idx].slots != chunk.slots: raise ValueError( "Trying to add an encounter to a chunk with the same name (%s) but different slots and/or slot values" % chunk.name) # Add an encounter at the current time self.dm[chunk_idx].add_encounter(self.time) slot_vals = chunk.slots.values() # Add slot values as singleton chunks for v in slot_vals: if type(v) == str and v not in [ ch.name for ch in self.dm ]: # NT: we want some contraints on the adding of chunks s = Chunk(name=v, slots={}) self.add_encounter(s) # Increment the fan of all chunks that this chunk references in its slots if update_fan: refs = [ i for i, ref in enumerate(self.dm) if ref.name in slot_vals ] for ref in refs: self.dm[ref].fan += 1