Example #1
0
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
Example #3
0
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
Example #4
0
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'])
Example #5
0
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
Example #6
0
    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