Markov Chain Monte Carlo with People (MCMCP)#
Markov Chain Monte Carlo with People (MCMCP) is an adaptive procedure related to Gibbs Sampling with People (GSP). Like GSP, it is intended to map participants’ associations of a stimulus space. In each trial, the participant is presented with a pair of stimuli: a ‘current state’ and a ‘proposal state’. They are asked to decide which stimulus best matches a given criterion. The chosen stimulus is then accepted as the next state, and a new proposal is generated from that state by making a small random jump in the stimulus space.
Source: demos/mcmcp
# pylint: disable=unused-import,abstract-method,unused-argument
import random
import psynet.experiment
from psynet.consent import MainConsent
from psynet.modular_page import Prompt, PushButtonControl
from psynet.page import InfoPage, ModularPage, SuccessfulEndPage
from psynet.timeline import Timeline
from psynet.trial.mcmcp import MCMCPNode, MCMCPTrial, MCMCPTrialMaker
from psynet.utils import get_logger
logger = get_logger()
from .test_imports import CustomCls # noqa -- this is to test custom class import
MAX_AGE = 100
OCCUPATIONS = ["doctor", "babysitter", "teacher"]
SAMPLE_RANGE = 5
class CustomTrial(MCMCPTrial):
time_estimate = 5
def show_trial(self, experiment, participant):
occupation = self.context["occupation"]
age_1 = self.first_stimulus["age"]
age_2 = self.second_stimulus["age"]
prompt = (
f"Person A is {age_1} years old. "
f"Person B is {age_2} years old. "
f"Which one is the {occupation}?"
)
return ModularPage(
"mcmcp_trial",
Prompt(prompt),
control=PushButtonControl(
["0", "1"], labels=["Person A", "Person B"], arrange_vertically=False
),
time_estimate=self.time_estimate,
)
class CustomNode(MCMCPNode):
def create_initial_seed(self, experiment, participant):
return {"age": random.randint(0, MAX_AGE)}
def get_proposal(self, state, experiment, participant):
age = state["age"] + random.randint(-SAMPLE_RANGE, SAMPLE_RANGE)
age = age % (MAX_AGE + 1)
return {"age": age}
def start_nodes(participant):
return [
CustomNode(
context={
"occupation": occupation,
},
)
for occupation in OCCUPATIONS
]
class Exp(psynet.experiment.Experiment):
label = "MCMCP demo experiment"
timeline = Timeline(
MainConsent(),
MCMCPTrialMaker(
id_="mcmcp_demo",
start_nodes=start_nodes,
trial_class=CustomTrial,
node_class=CustomNode,
chain_type="within", # can be "within" or "across"
expected_trials_per_participant=9,
max_trials_per_participant=9,
chains_per_participant=3, # set to None if chain_type="across"
chains_per_experiment=None, # set to None if chain_type="within"
max_nodes_per_chain=3,
trials_per_node=1,
balance_across_chains=True,
check_performance_at_end=False,
check_performance_every_trial=False,
fail_trials_on_participant_performance_check=True,
recruit_mode="n_participants",
target_n_participants=1,
),
InfoPage("You finished the experiment!", time_estimate=0),
SuccessfulEndPage(),
)
def __init__(self, session=None):
super().__init__(session)
self.initial_recruitment_size = 1