Computer crashes mid-experiment due to memory overflow - coding problem?

Hi PsychoPy-Community!

I have an experiment that I am trying to run in our labs. The experiment has a very high number of trials, as two routines (stimulus presentation and response, Feedback) are repeated over and over again.

After the experiment crashed with the first participants shortly before the end of the experiment (no error message, computer shuts down completely), I noticed the following:

While in other of my PsychoPy experiments the working memory increases by a maximum of 0.02 MB per trial, the working memory in this experiment increases by 4-6 MB.

However, the experiment does not consist of much code and all I use in the code are lists. Does anyone have experience with lists that are updated from trial to trial? I have rebuilt the experiment from scratch several times and am now at the point of saying that the problem can only be the updating lists from trial to trial (which nevertheless should not take up so much working memory capacity…?).

In each trial, I present a stimulus, the participants presses a key corresponding to the stimulus, and I give feedback for that response.
This is the code I am using:

###Stims
stimList=["A","B","C","1","2","3"]
shuffle(stimList)  

###Targets
if trialsTr.thisN < 2:
    Sn = stimList.pop(0)
    while Sn in prevList:
        shuffle(stimList)
        Sn = stimList[0]
    Snot = stimList.pop(1)
    if Sn == "A":
        Snot = "1"
    if Sn == "1":
        Snot = "A" 
    if Sn == "2":
        Snot = "B"
    if Sn == "B":
        Snot = "2"
    if Sn == "3":
        Snot = "C"
    if Sn == "C":
        Snot = "3"
    prevList.append(Sn)
    prevList.append(Snot)

if trialsTr.thisN == 2:
    prevList.pop(1)
    Sn = stimList.pop(0)
    while Sn in prevList:
        shuffle(stimList)
        Sn = stimList[0]
    Snot = stimList.pop(1)
    if Sn == "A":
        Snot ="1"
    if Sn == "1":
        Snot = "A" 
    if Sn == "2":
        Snot = "B"
    if Sn == "B":
        Snot = "2"
    if Sn == "3":
        Snot = "C"
    if Sn == "C":
        Snot = "3"
    prevList.append(Sn)
    prevList.append(Snot)
    
if trialsTr.thisN > 2:
    print(prevList)
    prevList.pop(0)
    prevList.pop(1)
    print(prevList)
    Sn = stimList.pop(0)
    while Sn in prevList:
        shuffle(stimList)
        Sn = stimList[0]
    Snot = stimList.pop(1)
    if Sn == "A":
        Snot ="1"
    if Sn == "1":
        Snot ="A" 
    if Sn == "2":
        Snot ="B"
    if Sn == "B":
        Snot ="2"
    if Sn == "3":
        Snot ="C"
    if Sn == "C":
        Snot ="3"
    prevList.append(Sn)
    prevList.append(Snot)    
    print(prevList)

If anyone has had similar experiences or knows what the problem could be - thank you in advance!

What version of PsychoPy are you using? Are you using Builder? Please could you post the exact error message?

I am using the latest PsychoPy Version (v2023.2.3.) and the Builder to build the experiment. Since the computer crashes completely, there is no error message at all…

Hello

do you mind surrounding your code with triple ` such that it is properly formatted.

Best wishes Jens

Edited :wink:

Hello,

you wrote that you are using the builder to program the experiment. Where does this code appear? When do you update stimList? You keep on deleting elements from stimList. Why do you set

Snot = stimList.pop(1)

when you set it to a different value in the following if-constructions? Where do you set prevList for the first two trials?

Best wishes Jens

Hi Jens,

after thinking about the code again, this line is actually superfluous.

Snot = stimList.pop(1)

Thanks for pointing out! However, after excluding the lines in the code, the problem still exists (working memory now increases by as much as 10 mb per trial).

I am using the code in “Begin Routine” in a Routine within my trials-Loop.
Like that, stimLIst is defined at the beginning of each trial, from which a stim is drawn during the course of the code.

The prevList is empty before the first trial, this code appears in “Begin Experiment”:

prevList=[] 

Like that prevList is then filled by the first two trials (but nothing is removed), for the following trials prevList is filled and stims are removed in parallel (but prevlist is never larger than 5 elements).

Thanks in advance!
Maria

Hello Maria

do you mind showing us your code in the relevant tabs in addition to describing it? I suspect the memory problem is due to your while-loop but I might not see the whole picture.

What do you want to achieve with the while-loop? Currently you are checking whether Sn is in prevList. If this is the case, you shuffle stimList, assign Sn a new value from stimList and delete the value from stimList. As a matter of fact you probably do not need to reshuffle stimList in your while-loop. You shuffled if jsut before the while-loop. Just pick Sn from stimList until it is not longer in prevList.

How likely is it that Sn is in prevList? If it is very likely you might come up with another way to assign Sn.

BTW, you might want to simplify your if-construction

if Sn == "A":
    Snot ="1"
elif Sn == "1":
    Snot ="A" 
elif Sn == "2":
    Snot ="B"
elif Sn == "B":
    Snot ="2"
elif Sn == "3":
    Snot ="C"
elif Sn == "C":
    Snot ="3"

In your program each if-construction will be checked. Here only one if-elfi constuction will be checked. This will not solve your problem.

Best wishes Jens

Hi Jens,

thank you very much, I just simplified the if-constructions as you suggestet! And I also deleted the reshuffle in the while-loop.

And exactly, the while loop should check if Sn is in prevList and if so, it chooses a new value from stimList. The prevList is updatet every trial and always contains the values that are not allowed to be presented as Sn in the current trial.

It is in fact likely that Sn is in prevList, as prevList contains at least 3 elements (out of the six elements in stimList).

This is the structure of my Loop:

Loop

The Routine ProcTr consist of a code component with the following code:

**Begin Experiment**
import random
# set variables
condition = 0
counter = 0

# set List
prevList=[]

#Feedback
messageCorrTr = "richtig"
messageFalseTrc = "Falsch!"
messageFalseTro = "Schneller reagieren!"

messageCorrExp = ""
messageFalseExpc = ""
messageFalseExpo = "Schneller reagieren!"

**Begin Routine**
counter = counter + 1 
condition = 'training'

#Stims
stimList=["A","B","C","1","2","3"]
shuffle(stimList)  

# trials 0 and 1
if trialsTr.thisN < 2:
    Sn = stimList.pop(0)
    while Sn in prevList:
        Sn = stimList[0]
    if Sn == "A":
        Snot = "1"
    elif Sn == "1":
        Snot = "A" 
    elif Sn == "2":
        Snot = "B"
    elif Sn == "B":
        Snot = "2"
    elif Sn == "3":
        Snot = "C"
    elif Sn == "C":
        Snot = "3"
    prevList.append(Sn)
    prevList.append(Snot)
    
#trial 2 
if trialsTr.thisN == 2:
    prevList.pop(1)
    Sn = stimList.pop(0)
    while Sn in prevList:
        Sn = stimList[0]
    if Sn == "A":
        Snot ="1"
    elif Sn == "1":
        Snot = "A" 
    elif Sn == "2":
        Snot = "B"
    elif Sn == "B":
        Snot = "2"
    elif Sn == "3":
        Snot = "C"
    elif Sn == "C":
        Snot = "3"
    prevList.append(Sn)
    prevList.append(Snot)
    
if trialsTr.thisN > 2:
    prevList.pop(0)
    prevList.pop(1)
    Sn = stimList.pop(0)
    while Sn in prevList:
        Sn = stimList[0]
    if Sn == "A":
        Snot ="1"
    elif Sn == "1":
        Snot ="A" 
    elif Sn == "2":
        Snot ="B"
    elif Sn == "B":
        Snot ="2"
    elif Sn == "3":
        Snot ="C"
    elif Sn == "C":
        Snot ="3"
    prevList.append(Sn)
    prevList.append(Snot)    


### define correct answers

if Sn == "A":
    CorrAnsn = "j"
elif Sn == "1":
    CorrAnsn = "j"
elif Sn == "B":
    CorrAnsn = "k"
elif Sn == "2":
    CorrAnsn = "k"
elif Sn == "C":
    CorrAnsn = "l"
elif Sn == "3":
    CorrAnsn = "l"

The Routine N consists of a text component where I set $Sn as text, and a response keyboard component (resp_n).

The Routine FeedbackTr consists of a code component and a text component (where I set $msgFdb as text), the code is the following:

**Begin Routine**
### Feedback
##Training
# ommission error
if not resp_n.keys:
   msgFdb = messageFalseTro
   msgFdbColor = "red"
   Accuracy = 0
   errtype = 2

# correct
elif resp_n.corr:
    msgFdb = messageCorrTr
    msgFdbColor = "green"
    Accuracy = 1
    errtype = 0

# commission error
else:
    msgFdb = messageFalseTrc
    msgFdbColor = "red"
    Accuracy = 0
    errtype = 1    

**End Routine** 
#AddData
thisExp.addData('condition',condition)
thisExp.addData('Sn', Sn) 
thisExp.addData('resp_n', resp_n)
thisExp.addData('Accuracy',Accuracy)
thisExp.addData('errtype', errtype)

Please let me know if there are any improvements I should make to the way my code is presented in the post to enhance clarity, as I am still relatively new to the Psychopy community! :slight_smile:

Best regards
Maria

Hello Maria

Ok, I do not think that I have understood what you are trying to do. It is not easy to understand from the code what is supposed to happen in an experiment, at least not for me.

Do you need the

while Sn in prevList:
   Sn = stimList[0]

for the first two trials? You set prevList = [] in Begin Experiment, so it is empty for the first trial, isn’t it? And given that you delete one element from stimList so it can’t be repeated in a later trial? You see I am lost.

Also, you store Sn and Snot in prevList but you delete one (trial 3) or two elements (from trial 4 on) from prevList

So, what to do intend to achieve? You have a list of stimuli [“A”,“B”,“C”,“1”,“2”,“3”] that you want to present trial by trial. Your participant reacts and you provide feedback. Why do need to compare the chose stimulus with stimuli presented before?

Best wishes Jens

Hi Jens,

it is indeed a somewhat complex experiment within the framework of research on action control, and I can imagine that it may be difficult to understand the logic in the code and therefore assist me with my problem. So I really do appreciate your attempt to understand my experiment and help me with the problem! I would be happy to explain the code in more detail. I hope that it might help:

In each trial, the participant responds to a presented letter or number and receives feedback. However, these stimuli cannot follow each other in an arbitrary order; there are specific rules for the sequence of letters/numbers. I always divide the sequential sequence of stimuli into sets of three (mentally, not in the code): in these sets of three, the same stimulus (number or letter) should never occur twice; it is only allowed to repeat from the 4th trial onwards. Therefore, I add Sn from trial 0 to the prevList and only remove it for trial 4. Additionally, two stimuli are mapped to one response key (j for “A” and “1”, k for “B” and “2”, l for “C” and “3”). In two consecutive trials, the same response should never be given; hence, if “A” is presented as Sn in trial 0, the stimulus “1” is also added as Snot to the prevList for trial 1 and is only removed again in trial 3 (where “1” can reappear again). I continuously apply these rules throughout the entire sequence of stimuli.

To implement these two rules in the sequence of stimuli, I need the prevList. From trial to trial, “forbidden” stimuli are repeatedly added to the prevList (based on the just-presented stimulus), and previous stimuli are removed from the prevList (those that are allowed to be presented again in the following trials).

Maybe I have to think about an other way to implement the rules without using a while loop and updating lists from trial to trial.

Kind regards!
Maria

Hello Maria,

You want a pseudo-random sequence of your stimuli and responses. Instead of randomising your stimuli and checking in a while-loop whether the selected stimulus meets your requirements, I would take a different approach. Randomise your stimuli, pick the first one, and then build a sequence that meets your requirements. So imagine your first stimulus is ‘A’, then for the second stimulus randomly pick ‘B’ or ‘C’, the next stimulus will be ‘C’ or ‘B’ depending on the randomly chosen stimulus in trial 2.

Note that the last stimulus is always determined and is therefore predictable!

It is usually better to create the desired sequence than to “hope” that randomisation will produce the desired sequence.

Bets wishes Jens

1 Like