psp.models#

Models used by the tutorials, recipes, tests and benchmarks.

  • psp.models.prospect: prospect theory on four bets of Kahneman and Tversky (1979).

  • psp.models.alcove: ALCOVE (Kruschke, 1992) on the six category structures of Shepard, Hovland and Jenkins (1961), batched over parameter sets.

  • psp.models.oscar: OSCAR on the inverse base-rate effect data (dome2025ibre), one trial order per participant.

  • psp.models.voronoi: a cheap toy model whose regions are Voronoi cells.

They show how to write a batched model and discretize; you do not need them to partition a model of your own.

Prospect theory#

Prospect theory on four bets of Kahneman and Tversky (1979), the model of the tutorial.

Each option is a prospect: an amount x won with probability p. Its value is w(p) * v(x) with v(x) = x ** alpha and the probability weighting function of Tversky and Kahneman (1992), w(p) = p**g / (p**g + (1 - p)**g) ** (1 / g). The model returns, for each problem, the value of the riskier option minus the value of the safer one, and the ordinal pattern is the sign of each difference on the diagonal of a 4 x 4 matrix.

psp.models.prospect.PROBLEMS = (Problem(problem=3, risky_amount=4000, risky_chance=0.8, safe_amount=3000, safe_chance=1.0, chose_risky=20, people=95), Problem(problem=4, risky_amount=4000, risky_chance=0.2, safe_amount=3000, safe_chance=0.25, chose_risky=65, people=95), Problem(problem=7, risky_amount=6000, risky_chance=0.45, safe_amount=3000, safe_chance=0.9, chose_risky=14, people=66), Problem(problem=8, risky_amount=6000, risky_chance=0.001, safe_amount=3000, safe_chance=0.002, chose_risky=73, people=66))#

Problems 3, 4, 7 and 8 of Kahneman and Tversky (1979).

class psp.models.prospect.Problem(problem, risky_amount, risky_chance, safe_amount, safe_chance, chose_risky, people)[source]#

One choice between a riskier and a safer prospect, with what people chose.

psp.models.prospect.weight(p, gamma)[source]#

The decision weight of probability p with weighting parameter gamma.

psp.models.prospect.prospect_value(amount, chance, alpha, gamma)[source]#

Subjective value of winning amount with probability chance.

psp.models.prospect.model(par)[source]#

Value of the riskier minus the safer option in each problem, shape (n, 4).

par holds alpha and gamma in its two columns.

psp.models.prospect.discretize(delta)[source]#

The sign of each difference on the diagonal of a 4 x 4 matrix, shape (n, 4, 4).

psp.models.prospect.describe(pattern)[source]#

Name a pattern by the problems in which the model takes the riskier option.

psp.models.prospect.human_pattern()[source]#

What most people chose, as an ordinal pattern.

ALCOVE#

ALCOVE (Kruschke, 1992) on the six category structures of Shepard, Hovland and Jenkins (1961).

This is a batched port of slpALCOVE() and nosof94train() from the R package catlearn (Wills et al., 2025), wrapped for psp.PSP() as in the ALCOVE recipe of the R package psp. Many parameter sets are run through the same training sequences at once, which is what makes a long PSP run affordable on a GPU.

The training orders are the ones catlearn generates for its seeds, shipped with the package, so that results can be compared with the R analysis trial for trial.

psp.models.alcove.ALCOVE_PARAMETERS_FULL = AlcoveParameters(name=('c', 'phi', 'lw', 'la'), lower=(0.01, 0.01, 0.001, 0.001), upper=(20.0, 6.0, 1.0, 1.0))#

The full ranges of the learning rates, 0 to 1, with the same specificity and consistency ranges.

psp.models.alcove.ALCOVE_COLUMNS = ('ctrl', 'cond', 'blk', 'stim', 'x1', 'x2', 'x3', 't1', 't2', 'm1', 'm2', 'm3')#

Columns of a training matrix, as catlearn’s nosof94train() produces them.

psp.models.alcove.ALCOVE_STIMULI = tensor([[0., 0., 0., 0., 1., 1., 1., 1.],         [0., 0., 1., 1., 0., 0., 1., 1.],         [0., 1., 0., 1., 0., 1., 0., 1.]], dtype=torch.float64)#

The eight stimuli as hidden nodes: three binary features each, one column per stimulus.

psp.models.alcove.TYPES = ('I', 'II', 'III', 'IV', 'V', 'VI')#

The six category structures, Types I to VI.

class psp.models.alcove.AlcoveParameters(name=('c', 'phi', 'lw', 'la'), lower=(0.01, 0.01, 0.001, 0.001), upper=(20.0, 6.0, 0.2, 0.2))[source]#

The four free parameters with the ranges of Pitt, Kim, Navarro and Myung (2006).

The lower bounds are kept above 0 because ALCOVE rejects a learning rate of 0.

psp.models.alcove.alcove(params, training, *, h, alpha, w, colskip, r=1.0, q=1.0, dec='ER', humble=True, attcon=False, absval=-1.0)[source]#

Run ALCOVE for a batch of parameter sets over a batch of training sequences.

A port of catlearn’s slpALCOVE(). Every parameter set runs through every sequence, all in parallel, and the state is carried from trial to trial within a sequence.

Parameters:
params

c, phi, lw and la, each a tensor of shape (batch,).

training

Shape (sequences, trials, columns), see sequences(). Column 0 holds the control code (0 normal, 1 reset the network, 2 freeze learning); the inputs, teaching signals and missing-dimension flags follow colskip columns, as in catlearn.

h

Hidden node positions, shape (inputs, hidden).

alpha

Initial attention weights, shape (inputs,).

w

Initial association weights, shape (outputs, hidden).

colskip

Number of columns before the inputs, counting the control column.

r, q

Distance metric (1 city-block, 2 Euclidean) and similarity gradient (1 exponential, 2 Gaussian).

dec

"ER" for the exponential ratio rule, "BN" for the background noise rule.

humble

Use a humble teacher (Kruschke, 1992, Eq. 4b).

attcon

Constrain the attention weights to sum to 1.

absval

Teaching value for an absent category.

Returns:
torch.Tensor

Response probabilities, shape (batch, sequences, trials, outputs).

Notes

The exponential ratio rule is computed as a numerically stable softmax. Where catlearn’s exp(phi * o) / sum(exp(phi * o)) overflows (the association weights diverge when the specificity is tiny and the association learning rate large, so every exemplar responds alike and the updates overshoot), catlearn returns NaN and this function returns the limiting probabilities. Everywhere else the two agree to machine precision.

psp.models.alcove.alcove_curves(unit, training, *, chunk=256, parameters=AlcoveParameters(name=('c', 'phi', 'lw', 'la'), lower=(0.01, 0.01, 0.001, 0.001), upper=(20.0, 6.0, 0.2, 0.2)))[source]#

Error rate of each type in each block for parameter sets on the unit hypercube.

This is the model of the ALCOVE recipe. unit has shape (n, 4) and is mapped onto ALCOVE’s ranges, parameters, with to_alcove(). training is a matrix from alcove_training(). The result has shape (n, 96): the 16 blocks of Type I, then of Type II, and so on, each averaged over the simulated learners.

chunk bounds how many parameter sets run at once, to limit memory.

psp.models.alcove.alcove_training(learners=5, seed=7624)[source]#

One training sequence per type and simulated learner, in catlearn’s trial order.

The orders catlearn’s nosof94train() generates with R’s random number generator are shipped for seed 7624 with 5 and 20 learners, and for seeds 11, 22, 33 and 44 with 5 learners (the settings of the ALCOVE recipe). Other settings fall back to nosof94train() and NumPy’s generator.

Returns:
torch.Tensor

Shape (6 * learners * 16 * 8 * 2, 12), float64: types I to VI in turn, each with learners sequences of 16 blocks.

psp.models.alcove.nosof94()[source]#

Nosofsky et al.’s (1994) replication: columns type (1-6), block (1-16), error.

psp.models.alcove.nosof94train(cond=1, blocks=16, absval=-1, subjs=1, seed=7624, blkstyle='accurate')[source]#

Randomised training blocks for one category structure, like catlearn’s nosof94train().

Each block presents the eight stimuli twice. In block 1 (or in every block with blkstyle="eights") each half of the block is shuffled separately; later blocks shuffle all sixteen trials together. Each simulated subject starts with a reset trial (ctrl = 1).

The shuffling uses NumPy’s generator, so the orders differ from R’s for the same seed. For the orders catlearn produces, use alcove_training().

Returns:
numpy.ndarray

Shape (subjs * blocks * 16, 12) with the columns of ALCOVE_COLUMNS.

psp.models.alcove.human_curves()[source]#

The human error rates in the order alcove_curves() uses, shape (96,).

psp.models.alcove.sequences(training)[source]#

Split a training matrix into equal-length sequences at every reset trial.

Returns a tensor of shape (sequences, trials, columns).

psp.models.alcove.to_alcove(unit, parameters=AlcoveParameters(name=('c', 'phi', 'lw', 'la'), lower=(0.01, 0.01, 0.001, 0.001), upper=(20.0, 6.0, 0.2, 0.2)))[source]#

Stretch points of the unit hypercube onto ALCOVE’s parameter ranges.

unit has shape (n, 4); the result maps c, phi, lw and la to tensors of shape (n,). parameters gives the ranges: those of Pitt et al. by default, or ALCOVE_PARAMETERS_FULL.

psp.models.alcove.weak_order(curves, gap=0.025)[source]#

The weak order of the six types by mean error, as a 6 x 6 comparison matrix.

This is the discretize of the ALCOVE recipe. The six mean errors are sorted and a new group starts wherever the gap to the next type exceeds gap. The entry (i, j) is 1 when type i is harder than type j, -1 when easier and 0 when they are tied. curves may be (96,), (n, 96) or (n, 6) (mean errors); the result has shape (n, 6, 6), or (6, 6) for a vector.

psp.models.alcove.describe_order(pattern)[source]#

Write a weak order the usual way, easiest first: "I < II < (III, IV, V) < VI".

psp.models.alcove.type_ranks(errors, gap=0.025)[source]#

Average rank of each type in its weak order, 1 for the easiest, ties sharing ranks.

errors holds the six mean errors, shape (6,) or (n, 6).

OSCAR#

OSCAR (Dome & Wills, 2026) on the inverse base-rate effect data (dome2025ibre) from Dome & Wills (2025), batched over sets and participants.

OSCAR is the model of the inverse base-rate effect of Dome and Wills (2026). This module is a port of its C++ implementation (architecture.cpp and model-row-by-row.cpp) and of the participant-level PSP routine around it (convert.R, imac.R, psp.R):

  • oscar() runs the network for a batch of parameter sets, each row on one of a batch of trial sequences, and returns the response probabilities;

  • dome2025ibre() loads the dataset (354 participants) and training_batch() builds the padded trial matrices of ConvertToStateList() for any set of participants;

  • evaluate() is the model of the PSP routine (P(rare) at test for A, B, BC and C behind a 0.5 anchor) and discretize() its discretize (clobe’s imac() with the ±0.125 thresholds).

Every function takes whole batches: no loop runs over parameter sets or participants, only over trials and over the ten recurrent attention-shift iterations of a learning trial.

Dome, L., & Wills, A. J. (2025). g-Distance: On the comparison of model and human heterogeneity. Psychological Review, 132(3), 632–655. https://doi.org/10.1037/rev0000550

Dome, L., & Wills, A. J. (2026). Errorless Irrationality: A unified computational account of the inverse base-rate effect across predictive, observational, and unsupervised procedures (arXiv:2608.06149). arXiv. https://doi.org/10.48550/arXiv.2608.06149

psp.models.oscar.OSCAR_PARAMETERS = ('P', 'alpha', 'mu', 'rho', 'beta')#

The five free parameters, in the order PSP() passes them.

psp.models.oscar.OSCAR_BOUNDS = ((1.0, 0.001, 0.001, 0.001, 0.001), (5.0, 1.0, 1.0, 5.0, 5.0))#

Their bounds in the PSP routine (run.r): lower, upper.

psp.models.oscar.STIMULI = ('A', 'B', 'C', 'AB', 'ABX', 'AC', 'ACY', 'BC')#

Stimulus names, in the order their integer codes take in a trial matrix.

psp.models.oscar.NODES = ('A', 'B', 'C', 'common', 'rare')#

The five nodes of the network: three cues and the two outcomes.

psp.models.oscar.TRIAL_COLUMNS = ('ctrl', 'ppt', 'trials', 'stim', 'x1', 'x2', 'x3', 'x4', 'x5', 'y1', 'y2', 'y3', 'y4', 'y5', 'f1', 'f2', 'f3', 'f4', 'f5')#

Columns of a trial matrix, as ConvertToStateList() lays them out (colskip = 4).

class psp.models.oscar.IbreData(ppt, abstim, trial, phase, abresp)[source]#

The trials of the dataset, one entry per row: participant, stimulus, trial, phase, response.

Arrays of equal length.

property participants#

Participant ids in order of first appearance.

psp.models.oscar.dome2025ibre()[source]#

The inverse base-rate effect data (ply207): 354 participants, training then 72 test trials.

abresp is common, rare or none; phase is training or test.

References:

Dome, L., & Wills, A. J. (2025). g-Distance: On the Comparison of Model and Human Heterogeneity. Psychological Review, 132(3), 632–655. https://doi.org/10.1037/rev0000550

psp.models.oscar.convert_to_state_list(schedule, block, trials, ppt=0, design='supervised')[source]#

One participant’s trial matrix, as ConvertToStateList() in convert.R builds it.

Parameters:
schedule

Stimulus of each trial, names from STIMULI.

block

Phase code of each trial: 0 or 4 for training (4 is what psp.R uses for a supervised design), 2 for test.

trials

Trial numbers, kept as a column.

ppt

Participant code, kept as a column (an integer here; R keeps the string).

design

"supervised": outcomes are eligible outputs in both phases and training trials carry feedback; the first trial resets the network with code 3. "unsupervised": no feedback and no eligible outputs in training; code 1.

Returns:
numpy.ndarray

Shape (trials, 19) with TRIAL_COLUMNS; stim holds the index of the stimulus in STIMULI.

psp.models.oscar.training_batch(data, participants=None, *, dtype=torch.float64)[source]#

Trial matrices of several participants, padded to the longest with control code PAD.

Returns the tensor of shape (participants, trials, 19) and the participant ids in row order.

psp.models.oscar.oscar(params, training, *, eta0, weights0, sequence=None, zero_first_column=True, return_trials=False)[source]#

Run OSCAR for a batch of parameter sets, each on one trial sequence.

Parameters:
params

P, alpha, mu, rho and beta, each of shape (B,).

training

Trial matrices, shape (S, T, 19) with TRIAL_COLUMNS, or (T, 19) for a single sequence shared by the batch. Control codes: 1 and 3 reset the network before the trial; 2 responds without learning; 0, 4 and 5 learn (3 and 4 with feedback as part of the teacher); PAD rows are skipped.

eta0, weights0

Initial saliences and connection weights, shape (B, 5, 5); their diagonals are zeroed as in the C++.

sequence

For each row of the batch, the index of its sequence in training, shape (B,). Defaults to sequence 0 for every row.

zero_first_column

Reproduce the C++ AttentionShift, whose .diag().zeros() on a one-row matrix zeroes the attended activation of node A (column 0) for every row, instead of each row’s own node. False zeroes each row’s own node.

return_trials

Also return the trial-by-trial probabilities, activations and errors.

Returns:
dict

rare_sum (B, 8) and rare_count (B, 8): the sum and count of P(rare) over the test trials (code 2) of each stimulus of STIMULI, weights and eta (B, 5, 5) after the last trial, and with return_trials also prob, activations and error of shape (B, T, 5).

psp.models.oscar.random_initial_state(batch, *, scale=0.001, generator=None, device='cpu', dtype=torch.float64)[source]#

Initialize non-zero saliences and weights for a batch of parameter sets. Returns eta0 with a zero diagonal and weights0, both of shape (batch, 5, 5).

psp.models.oscar.evaluate(par, training, *, sequence=None, generator=None, eta0=None, weights0=None, zero_first_column=True)[source]#

The model for the PSP routine:

  1. Evaluates OSCAR.

  2. Adds a 0.5 anchor.

  3. Computes P(rare) at test for A, B, BC and C.

par holds P, alpha, mu, rho and beta in its columns, shape (B, 5). The initial saliences and weights are drawn afresh for every row, as evaluate() in imac.R does, unless eta0 and weights0 are given.

Returns (B, 5).

psp.models.oscar.imac(probabilities, thresholds=(0.125, -0.125))[source]#

clobe’s inequality matrix constructor as the PSP routine used it: psp.clobe.imac() with inclusive=True.

For probabilities of shape (B, m) returns (B, m, m): above the diagonal, 1 where p_i - p_j >= thresholds[0], -1 where <= thresholds[1], 0 between; 2 on and below the diagonal. A NaN difference stays NaN.

psp.models.oscar.discretize(probabilities, thresholds=(0.125, -0.125))[source]#

The discretize of the PSP routine: imac(), every cell 99 for a row with any NaN.

psp.models.oscar.EVALUATED_STIMULI = ('A', 'B', 'BC', 'C')#

The stimuli whose P(rare) at test enter the ordinal pattern, after the 0.5 anchor.

Voronoi cells#

A cheap toy model whose ordinal regions are Voronoi cells of the unit hypercube.

The model returns the squared distance from the parameter set to each of regions random centres, and discretize returns the index of the nearest centre in a 2 x 2 matrix. It is the model of the package tests and benchmarks.

class psp.models.voronoi.VoronoiModel(centres)[source]#

A Voronoi model: centres of shape (regions, dimensions).

model(parameters)[source]#

Squared distance to every centre, shape (n, regions).

static discretize(distances)[source]#

Index of the nearest centre, as a 2 x 2 matrix per row.

psp.models.voronoi.voronoi_model(regions, dimensions, seed=7624)[source]#

A Voronoi model with regions centres drawn uniformly in the unit hypercube.

psp.models.voronoi.voronoi_control(regions, dimensions, iterations, population, radius=0.3, init=None)[source]#

The control settings used by the tests and benchmarks for a Voronoi model.

References#

Dome, L., & Wills, A. J. (2025). g-Distance: On the comparison of model and human heterogeneity. Psychological Review, 132(3), 632–655. https://doi.org/10.1037/rev0000550

Dome, L., & Wills, A. J. (2026). Errorless Irrationality: A unified computational account of the inverse base-rate effect across predictive, observational, and unsupervised procedures (arXiv:2608.06149). arXiv. https://doi.org/10.48550/arXiv.2608.06149

Kahneman, D., & Tversky, A. (1979). Prospect Theory: An Analysis of Decision under Risk. Econometrica, 47(2), 263–292. https://doi.org/10.2307/1914185

Kruschke, J. K. (1992). ALCOVE: An exemplar-based connectionist model of category learning. Psychological Review, 99(1), 22–44. https://doi.org/10.1037/0033-295X.99.1.22

Pitt, M. A., Kim, W., Navarro, D. J., & Myung, J. I. (2006). Global model analysis by parameter space partitioning. Psychological Review, 113(1), 57–83. https://doi.org/10.1037/0033-295X.113.1.57

Shepard, R. N., Hovland, C. I., & Jenkins, H. M. (1961). Learning and memorization of classifications. Psychological Monographs: General and Applied, 75(13), 1–42. https://doi.org/10.1037/h0093825

Tversky, A., & Kahneman, D. (1992). Advances in prospect theory: Cumulative representation of uncertainty. Journal of Risk and Uncertainty, 5(4), 297–323. https://doi.org/10.1007/BF00122574

Wills, A. J., Dome, L., Edmunds, C., Honke, G., Inkster, A., Schlegelmilch, R., & Spicer, S. (2025). catlearn: Formal Psychological Models of Categorization and Learning. R package version 1.1. https://CRAN.R-project.org/package=catlearn