Skip to contents

This vignette shows how to define observed responses with first_of(), all_of(), none_of(), and inhibit(). Use these helpers when a response is not a direct readout from a single accumulator.

## 
## Attaching package: 'AccumulatR'
## The following object is masked from 'package:stats':
## 
##     simulate

What a response rule does

An outcome rule states when an observed response should count as having happened. Common cases include:

  • one of several routes being able to generate it
  • several processes all being complete
  • the absence of some competing event
  • a stop-like process that can cancel an otherwise available response

The logical helpers encode those cases directly in the model definition.

The four main helpers

The main helpers are:

  • first_of(x, y) finishes when the first of x and y finishes
  • all_of(x, y) finishes when both x and y have finished
  • none_of(x) requires x not to have finished before its enclosing rule
  • inhibit(x, y) finishes with x unless y finishes strictly earlier

first_of(): either route can generate the response

Use first_of() when one of several routes can generate the same response.

model_first <- race_spec() |>
  add_accumulator("word_route", "lognormal") |>
  add_accumulator("picture_route", "lognormal") |>
  add_outcome("target_detected", first_of("word_route", "picture_route")) |>
  finalize_model()

names(model_first$prep$outcomes)
## [1] "target_detected"

all_of(): several things must all be true

Use all_of() when a response depends on several processes all being complete.

model_all <- race_spec() |>
  add_accumulator("encoding", "lognormal") |>
  add_accumulator("verification", "lognormal") |>
  add_outcome("confirmed_response", all_of("encoding", "verification")) |>
  finalize_model()

names(model_all$prep$outcomes)
## [1] "confirmed_response"

none_of(): the response requires the competing event to be absent

Use none_of() inside all_of() to require that another event has not occurred before the conjunction completes.

model_none <- race_spec() |>
  add_accumulator("go", "lognormal") |>
  add_accumulator("stop", "lognormal") |>
  add_outcome("respond", all_of("go", none_of("stop"))) |>
  finalize_model()

names(model_none$prep$outcomes)
## [1] "respond"

The response occurs when go finishes, provided stop has not finished earlier.

inhibit(): the response is driven by one process and blocked by another

Use inhibit() when one process would generate the response and another can block it.

model_inhibit <- race_spec() |>
  add_accumulator("go", "lognormal") |>
  add_accumulator("stop", "lognormal") |>
  add_outcome("respond", inhibit("go", "stop")) |>
  finalize_model()

names(model_inhibit$prep$outcomes)
## [1] "respond"

Here stop cancels the response only if it finishes before go.

none_of() versus inhibit()

These two rules look similar:

rule_none <- all_of("go", none_of("stop"))
rule_inhibit <- inhibit("go", "stop")

c(absence_rule = rule_none$kind, inhibit_rule = rule_inhibit$kind)
## absence_rule inhibit_rule 
##        "and"      "guard"

For these two distinct accumulators, they give the same response rule: go completes before stop. The absence condition is evaluated when the enclosing conjunction completes, not over the entire trial.

Nesting matters. all_of("a", "b", none_of("stop")) checks absence when both a and b have completed. In all_of(inhibit("a", "stop"), "b"), inhibition is decided when a completes; a later stop does not undo that event.

none_of() needs an event at which to evaluate absence. Use it inside all_of() with an event that generates a response; a bare none_of() cannot be an outcome or a standalone branch of first_of().

A combined example

The helpers can be combined when a response depends on several kinds of logic at once. For example, suppose a response requires:

  • an encoding stage to finish
  • either a left route or a right route to generate the choice
  • no stop event before those requirements have completed
model_combo <- race_spec() |>
  add_accumulator("encoding", "lognormal") |>
  add_accumulator("left_route", "lognormal") |>
  add_accumulator("right_route", "lognormal") |>
  add_accumulator("stop", "lognormal") |>
  add_outcome(
    "choice",
    all_of(
      "encoding",
      first_of("left_route", "right_route"),
      none_of("stop")
    )
  ) |>
  finalize_model()

names(model_combo$prep$outcomes)
## [1] "choice"