Selection from a group & randomization

Many experiments require selecting a particular stimulus from a group of stimuli and presenting it. Once a group is defined, tags that denote particular stimuli can be chosen in BITTSy, with or without replacement, either in the order in which they are listed in the group or with randomization. This is done with choose statements.

Choose statements can occur on their own, but they are often employed within loops, sections of steps that repeat until a specific condition is met. For example, a particular STEP could select and display an image from a group, and a loop could repeat that STEP until all of the images have been chosen and displayed. After covering the basics of choose statements and loops individually, more about how they work together can be seen in the "putting it all together" section.

Choose statements and dynamic tags

Remember dynamic tags? Unlike other tags, they are not defined at the start of a protocol. Rather, they get defined through choose statements, within the steps of your protocol, and refer to the result of that choose statement on its most recent execution.

LET <dynamic tag> = (<TAKE or FROM> <group tag> <RANDOM or FIRST>)

The syntax above shows how to create a dynamic tag. The name you give it within the LET statement is its new name: this will be what you use later to refer to whatever tag or stimulus was selected. The part in parentheses on the right side of the equals sign is the choose statement (we'll talk more about the syntax and options for choose statements later.)

The restrictions on valid dynamic tag names are the same as for other tags. Unlike static tags that directly denote files or groups, there is no restriction on defining the same dynamic tag name twice - indeed, this is extremely common, as you are often creating and overwriting dynamic tags via executing a choose statement within a loop. However, they must not have the same name as any static tag.

LET dalmatian = "C:\BITTSy_Stimuli\dalmatian.png"
LET deerhound = "C:\BITTSy_Stimuli\deerhound.png"
...
LET dogs = {dalmatian, deerhound, boxer, bulldog, beagle, whippet}

In the example above, we have a group dogs that contains several tags referencing image files. We want to pick a random one and display it. We don't know which tag out of the group dogs will be chosen on any given run of this particular STEP. Therefore, we can't refer to the result by directly using any of the tags referencing files (dalmatian, deerhound, boxer, etc.) Instead, we create a dynamic tag, to which we can assign whatever tag we randomly select.

STEP 1
LET dog = (TAKE dogs RANDOM)
IMAGE CENTER dog

You can think of dynamic tags like arrows. If the choose statement selects beagle from the group, dog points to beagle, and in the subsequent action statement to display the image, BITTSy follows the arrow back from dog to beagle to the actual file on your computer it will access and display.

Dynamic tags keep referring back to the same tag until a later choose statement changes their reference - that is, the arrow stays pointing in the same direction until another choose statement moves it. If beagle was selected above, you could refer to dog many steps later and it would still mean beagle, as long as there were no intervening choose statements that also assigned their result to dog. If there were more choose statements that assigned to the same dynamic tag, dog would always refer to the result of the most recently-executed choose statement.

Often, dynamic tags are used within a loop. Loops repeatedly execute a set of STEPs within a protocol. When a dynamic tag and choose statement are defined within a loop, the choose statement is executed each time the loop runs, and the assignment of the dynamic tag changes each time.

Once a dynamic tag is reassigned via another choose statement to mean a different static tag, there is no way to use it to reference what it used to mean. Therefore, any experiment that needs to call back up "stimulus that was chosen two trials ago," after having chosen more things, will need to assign results of choose statements to new dynamic tags so that the older results are not overwritten. This can require not using a loop structure, as a loop repeatedly executes a single section of protocol and cannot allow modifications to the included lines.

Fixed order and random order

Whenever you create a choose statement, you must specify whether to choose the items from the group in order (by always selecting the FIRST tag that is eligible for selection), or to select in a random order (using the flag RANDOM).

LET dog = (TAKE dogs FIRST)
LET dog = (TAKE dogs RANDOM)

More on these and how they work in different types of choose statements below!

Selection without replacement

LET <dynamic tag> = (TAKE <group tag> <FIRST or RANDOM)
LET dog = (TAKE dogs RANDOM)
IMAGE CENTER dog

TAKE clauses specify selection that is strictly without replacement. Whatever tag is chosen is no longer available to be chosen from that group in any subsequent choose statements, whether they occur in later steps or in the same step via a loop. (However, tags that are chosen still belong to the group for the purposes of tracking accumulated looking time or logging experiment data.)

Whether or not a particular tag is eligible for selection is tracked per group. If a particular static tag belongs to two groups, and is chosen via TAKE from one of those groups, it could still later be selected when using a choose statement that is set to pull from the second group. (The same applies to choosing with FROM statements in the next section!)

Choosing items with RANDOM, as in the example above, does just that - picks any random remaining tag in that group, with equal probability.

Choosing items in order, via FIRST, is really designed for choosing without replacement with TAKE. Doing this allows you to set up a particular, fixed order of tags while defining the group, and then present those tags in that order. For example, the items from this group...

LET dogs = {dalmatian, deerhound, boxer}
...
STEP 1
LET dog1 = (TAKE dogs FIRST)
IMAGE CENTER dog1
UNTIL TIME 2500

STEP 2
LET dog2 = (TAKE dogs FIRST)
IMAGE CENTER dog2
UNTIL TIME 2500

STEP 3
LET dog3 = (TAKE dogs FIRST)
IMAGE CENTER dog3
UNTIL TIME 2500

...would display dalmatian, then deerhound, then boxer - the order in which they appear in the definition of dogs. This set-up is completely deterministic, which means you could equivalently set up your protocol to directly reference the static tags:

STEP 1
IMAGE CENTER dalmatian
UNTIL TIME 2500

STEP 2
IMAGE CENTER deerhound
UNTIL TIME 2500

STEP 3
IMAGE CENTER boxer
UNTIL TIME 2500

However, when designing experiments that present files in a fixed order, there are often multiple fixed-orders to create and assign across study participants. Using choose statements with FIRST allows you to refer back to these tags generically within the steps of the protocol. Therefore, when you are creating multiple fixed-order protocols for one experiment, all you need to do is change one line: the group definition.

Loops make TAKE <group> FIRST an even more convenient option for fixed-order protocols than using static tags. For an example protocol that puts this all together, see here.

Selection with replacement

LET <dynamic tag> = (FROM <group tag> <FIRST or RANDOM>)
LET dog = (FROM dogs RANDOM)
IMAGE CENTER dog

Choosing from groups with FROM marks the resulting tag as having been chosen, but does not bar it from being selected again from that group later.

For example, selecting with FROM dogs RANDOM two times on the following group...

LET dogs = {dalmatian, deerhound}

...could result in:

dalmatian, deerhound dalmatian, dalmatian deerhound, dalmatian deerhound, deerhound

Selecting with FROM dogs FIRST, on the other hand, would always yield dalmatian.

Repeat clauses

There are additional clauses you can add to a FROM statement that place restrictions on the repeated selection of tags.

LET <dynamic tag> = (FROM <group tag> <RANDOM or FIRST> {repeat clause 1, repeat clause 2...})

These repeat clauses are:

with max <number> repeats
with max <number> repeats in succession
with max <number> repeats in <number> trials

A common mistake with all of these is confusing the number of repeats with the total number of presentations. If you don't want it to repeat at all, it has to be listed as zero repeats, not one repeat. One repeat means it could present the item twice: the initial time, plus one repetition of it.

max <number> repeats

This type of clause allows you to restrict how many times a particular item is selected from a group, overall.

LET sides = {LEFT, RIGHT}
...
LET side1 = (FROM sides RANDOM {with max 4 repeats})
IMAGE side1 dog

This means that each side, LEFT or RIGHT, can be chosen for stimulus presentation up to 5 times. Once one side has been picked 5 times, any remaining repetitions will be forced to pick the other side. There are valid sides remaining for exactly 10 selections; if this step is executed 11 times, BITTSy will crash on the last one because it won't be allowed to pick either one!

More generally - ensure that when you are placing selection criteria, they are appropriate for the number of times a step will execute in your protocol, and there will always be a valid selection that BITTSy can make.

Selecting {with max 0 repeats} in a FROM statement is completely equivalent to using a TAKE statement - it specifies to not allow repeats, which is what selecting without replacement is! TAKE is just shorter to write, and easier for someone reading your protocol to understand.

LET dog = (FROM dogs RANDOM {with max 0 repeats})
LET dog = (TAKE dogs RANDOM)

max <number> repeats in succession

This type of clause allows you to restrict how many times a single item can be chosen from a group in a row.

LET side1 = (FROM sides RANDOM {with max 2 repeats in succession})
IMAGE side1 dog

In the above example, each side can be chosen up to 3 times in a row. Whenever one is chosen 3 times in a row, the next selected side must be the other one.

Using {with 0 repeats in succession} specifies to never make the same selection twice in a row. For a group that contains just two items, like sides in our example, this forces selections to alternate.

LET side1 = (FROM sides RANDOM {with max 0 repeats in succession})

max <number> repeats in <number> trials

This type of clause can be used when you wish to restrict how many times an item can be repeated within a particular window of trials.

LET dogs = {dalmatian, deerhound, boxer, bulldog, beagle, whippet}
...
LET dog = (FROM dogs RANDOM {with max 1 repeats in 4 trials})

This means that in any set of four consecutive selections, each item can appear a maximum of two times. For example, this would be a valid possible selection order:

boxer, bulldog, bulldog, beagle, dalmatian, bulldog, deerhound

Because every set of four contains only up to two of the same item.

{boxer, bulldog, bulldog, beagle}, dalmatian, bulldog, deerhound boxer, {bulldog, bulldog, beagle, dalmatian}, bulldog, deerhound boxer, bulldog, {bulldog, beagle, dalmatian, bulldog}, deerhound boxer, bulldog, bulldog, {beagle, dalmatian, bulldog, deerhound}

This type of clause is good for when you want to restrict how frequent one thing can be within a certain time frame, beyond whether they are strictly all in a row (which is repeats in succession).

Here's another example.

LET dog = (FROM dogs RANDOM {with max 0 repeats in 6 trials})

This means that as each item is selected, it cannot be selected again in any of the next 5 selections that are made from that group. For example, if boxer is chosen first, it cannot appear again until trial 7 at the earliest; beagle, if chosen second, cannot appear again until trial 8, and so on.

On the surface, the above example might seem like a good way to create a block structure in BITTSy (displaying all of the stimuli from a set in a random order without repeats, then showing the set again in a different random order). However, you would typically want stimuli within a block to be randomized independently, and this selection criteria always works along a moving window, meaning that there is never a point where the current selection is independent of the previous ones. For example, if repeated executions of the above line made the following selections:

whippet, dalmatian, deerhound, beagle, boxer, bulldog, ______

Because the last selection is considering the five previous, and won't allow any repeats within that frame...

whippet, {dalmatian, deerhound, beagle, boxer, bulldog, ______}

...that selection must be whippet - it is the only item that wouldn't be a repetition within that set of most recent 6 picks - and next would have to be dalmatian, and then deerhound... Essentially, what you get is a random permutation of the six items when moving through the group for the first time, but thereafter it repeats that same ordering of the six tags.

How, then, do you make a block structure with BITTSy? See below!

Selection and groups of groups (and groups of groups of groups!)

Let's go back to the basic formulation of a choose statement.

LET <dynamic tag> = (<TAKE or FROM> <group tag> <RANDOM or FIRST>)

When a group tag is referenced, BITTSy doesn't care what type of tags it contains, as long as it's defined as a group and has at least one tag in it that is eligible for selection, according to your selection criteria. It simply picks one and makes the dynamic tag point at it. That group can contain tags that denote files, it can contain SIDES, or it can contain other groups. Going back to our example from the groups section:

LET dog = "C:\BITTSy-Stimuli\animals\dog.png"
LET cat = "C:\BITTSy-Stimuli\animals\cat.png"
LET snake = "C:\BITTSy-Stimuli\animals\snake.png"
LET turtle = "C:\BITTSy-Stimuli\animals\turtle.png"

LET mammals = {dog, cat}
LET reptiles = {snake, turtle}

LET animals = {mammals, reptiles}

Let's say we're writing a protocol in which we want to display one of these images. We start with animals, a group whose members are other groups. We need two choose statements before we can display an image tag - first to select either mammals or reptiles out of animals, and second to select a particular mammal or reptile from that resulting group (which we've called class).

LET class = (TAKE animals RANDOM)
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

Now let's say we want to make an experiment that displays these images in a block structure. One block of trials will be mammals, one will be reptiles. We'll randomly select which block comes first, and within each block, we'll randomly order the two animals that belong to that phylogenetic class. Below is an example of how this can be constructed.

STEP 1
LET class = (TAKE animals RANDOM)
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

STEP 2
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

STEP 3
LET class = (TAKE animals RANDOM)
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

STEP 4
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

Or equivalently, with loops:

STEP 1
LET class = (TAKE animals RANDOM)

STEP 2
LET animal = (TAKE class RANDOM)
IMAGE CENTER animal
UNTIL KEY C

STEP 3
LOOP STEP 2 UNTIL class EMPTY

STEP 4
LOOP STEP 1 UNTIL animals EMPTY

Defining animals as a group of groups allows you to set up choose statements that create this type of simple block structure, and gives the following possibilities.

1

2

3

4

5

6

7

8

Block 1: mammals

  • cat

  • dog

Block 1: mammals

  • dog

  • cat

Block 1: mammals

  • cat

  • dog

Block 1: mammals

  • dog

  • cat

Block 1: reptiles

  • snake

  • turtle

Block 1: reptiles

  • turtle

  • snake

Block 1: reptiles

  • snake

  • turtle

Block 1: reptiles

  • turtle

  • snake

Block 2: reptiles

  • snake

  • turtle

Block 2: reptiles

  • snake

  • turtle

Block 2: reptiles

  • turtle

  • snake

Block 2: reptiles

  • turtle

  • snake

Block 2: mammals

  • cat

  • dog

Block 2: mammals

  • cat

  • dog

Block 2: mammals

  • dog

  • cat

Block 2: mammals

  • dog

  • cat

Last updated