Function index (Python)
choices
choice_file_combined
Aggregate trial-level comparison judgments into a consolidated choice file.
This script is the downstream aggregation step following
rs_detailed_choice.py, which produces trial-level triadic (or tetradic)
distance comparisons from ranking experiment click-order data. Unlike the
preceding utilities, which emit one row per comparison per trial, this module
collapses across trials to produce a summary of unique comparisons.
The script does the following:
- Takes as input a detailed choices file in which the same comparison (defined by two pairs of stimulus IDs) may appear multiple times.
- Groups comparisons that are identical under canonicalization (standardized stimulus ordering).
- Tallies how many times each unique comparison appears, stored in a new
column
N(comparisons). - Sums judgments across occurrences of each comparison, yielding the total number of times the first stimulus pair was judged more dissimilar than the second.
- Drops all trial-level information; the
trialfield is not retained.
Notes: The resulting file is intended for downstream modeling and inference methods that operate on aggregated choice counts rather than individual trials, such as distance-based embedding and psychophysical scaling approaches (e.g., Waraich and Victor, 2022; 2024).
This assumes comparisons have already been standardized and, if
applicable, stimulus labels replaced with numeric IDs.
build_combine_choice_mat(input_mat_path, output_dir, exp_name, subject)
Combine repeated triadic or tetradic comparison judgments.
This function inspects the response column names in the input .mat file to
determine whether the file contains triadic comparisons (ref, s1, s2) or
tetradic comparisons (s1, s2, s3, s4). It then dispatches to the
appropriate aggregation function to combine repeated judgments and save the
resulting .mat file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_mat_path
|
str
|
Path to the input |
required |
output_dir
|
str
|
Directory where the combined |
required |
exp_name
|
str
|
Experiment name used to build the output filename. |
required |
subject
|
str
|
Subject identifier used to build the output filename. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
None |
Calls the appropriate aggregation function and writes the combined
|
See Also
build_combine_choice_mat_triadic_format: Aggregates triadic comparison responses. build_combined_mat_tetradic_format: Aggregates tetradic comparison responses.
Source code in src/rs_py/choices/choice_file_combined.py
build_combine_choice_mat_triadic_format(input_mat_path, output_dir, exp_name, subject)
Combine judgments across repeated triadic or tetradic comparisons.
This function loads a .mat file containing trial-level comparison judgments, aggregates repeated comparisons by summing the judgment counts, and records how many times each unique comparison was repeated. The result is saved as a new combined .mat file in the specified output directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_mat_path
|
str
|
Path to the input .mat file containing the fields responses, responses_colnames, and metadata. |
required |
output_dir
|
str
|
Directory where the combined .mat file will be saved. |
required |
exp_name
|
str
|
Experiment name used to build the output filename. |
required |
subject
|
str
|
Subject identifier used to build the output filename. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
None |
Saves a .mat file named {exp_name}combined_choices.mat in output_dir. Prints the full output path after saving. |
Source code in src/rs_py/choices/choice_file_combined.py
build_combined_mat_tetradic_format(input_mat_path, output_dir, exp_name, subject)
Combine judgments across repeated tetradic comparisons.
This function loads a .mat file containing trial-level comparison judgments,
aggregates repeated comparisons by summing the judgment counts, and records how
many times each unique comparison was repeated. The result is saved as a new
combined .mat file in the specified output directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_mat_path
|
str
|
Path to the input |
required |
output_dir
|
str
|
Directory where the combined |
required |
exp_name
|
str
|
Experiment name used to build the output filename. |
required |
subject
|
str
|
Subject identifier used to build the output filename. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
None |
Saves a |
Source code in src/rs_py/choices/choice_file_combined.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |
choice_file_detailed
Utilities for converting ranking experiment click-order data into triadic or tetradic distance comparisons.
This module reads response CSV files from ranking experiments, parses per-trial click orderings relative to a reference stimulus, and generates all corresponding pairwise distance comparisons. It provides functionality to represent pairwise comparisons in a standardized way, replace stimulus labels with numeric IDs, and prepare data for downstream analysis (e.g., MATLAB .mat files), following the framework of Waraich and Victor (2022).
Each row in the output (.mat) file contains information about a judgment between two pairs of stimuli, and a trial number. It contains a matlab struct, with one field for the trial-by-trial judgments, and one field for metadata. The metadata in turn contains information regarding the stimuli, paradigm, number of trials, or any optional information a user may find useful to add. In our case, (Waraich and Victor, 2024), metadata contains a list of stimuli, number of sessions, the subject identifier, and the task.
generate_comparisons(reference, clicks, trial_num)
Generate all pairwise triadic distance comparisons for a single trial.
Given a reference stimulus and an ordered list of non-reference stimuli, generate all pairwise triadic comparisons implied by the click order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference
|
str
|
Label of the reference stimulus. |
required |
clicks
|
list[str]
|
Ordered list of non-reference stimuli in the order they were clicked. |
required |
trial_num
|
int
|
Trial index assigned to all generated comparisons. |
required |
Returns:
| Type | Description |
|---|---|
|
|
|
Each dictionary contains: - trial - s1 - s2 - s3 - s4 - operator - judgment |
Notes
The number of generated comparisons is $n# choose 2, where \(n\) is the number of comparison stimuli. Each unordered stimulus pair appears exactly once per trial. Canonicalization of comparison keys and stimulus-ID remapping are performed by downstream processing steps.
See also: standardize_comparison_keys
Source code in src/rs_py/choices/choice_file_detailed.py
parse_click_sequence(row)
Parse the click order for a trial into a sequence of stimulus labels.
Given a trial row, read the stored click-order indices from row['clicks']
and return the corresponding stimuli in the order they were clicked.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
row
|
dict
|
A single trial row containing a |
required |
Returns:
| Type | Description |
|---|---|
|
Notes
- Assumes data are being read in from csv files created by Waraich and Victor (2022) paradigm.
Source code in src/rs_py/choices/choice_file_detailed.py
process_subject_data(input_directory)
Read response CSV files for a single subject and convert each trial’s click order into all implied pairwise triadic distance comparisons relative to the reference stimulus.
For every row in every matching response CSV file, the function parses the observed click order, generates all (n choose 2) comparisons among the comparison stimuli, and assigns trial numbers sequentially across all files and rows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_directory
|
str
|
Path to a directory containing one or more response CSV files for a
single subject. Subdirectories are searched recursively for files
matching the response-file pattern defined by |
required |
Returns:
| Type | Description |
|---|---|
|
|
|
Notes
- Trial numbering starts at 1 and increases sequentially across all files and rows; no session boundaries are inferred.
- To ensure compatibility with experiments that utilize multiple exemplars per stimulus, stimuli are generated from the stimulus names in the CSV files after ignoring the text after an underscore. If a stimulus name contains no underscore, then this is not a problem. This affects experiments where an experimenter uses multiple images/ exemplars per stimulus which are coded as 'stim23_002', 'stim23_003' etc. In this case both instances will be tied to one stimulus called 'stim23'.
- CSV files are read using UTF-8 with BOM (
utf-8-sig) encoding to match experimental data exports. - This function does not canonicalize comparison keys, remap stimulus IDs, or aggregate across trials; those steps are handled downstream.
- The interpretation of click order and judgment semantics is handled by
generate_comparisons.
See also: generate_comparisons
Source code in src/rs_py/choices/choice_file_detailed.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | |
replace_stimuli_with_ids(comparisons, stimuli_set)
Replace stimulus labels in comparison dictionaries with integer stimulus IDs.
Constructs a deterministic mapping from stimulus labels to integer IDs
based on the sorted order of stimuli_set, then replaces the values of the
stimulus fields (s1, s2, s3, s4) in each comparison dictionary with
their corresponding integer IDs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comparisons
|
list[dict]
|
List of comparison dictionaries. Each dictionary must contain the
keys |
required |
stimuli_set
|
set
|
Set of all stimulus labels to be mapped to integer IDs. IDs are assigned starting from 1, in alphabetical order of the labels. |
required |
Returns:
| Type | Description |
|---|---|
|
Notes
- The function mutates the input
comparisonslist in place. - Judgment values and non-stimulus fields are not modified.
- If a comparison contains a stimulus label not present in
stimuli_set, aKeyErrorwill be raised. - The function does not perform canonicalization, reordering of stimulus keys, or judgment flipping.
See also: standardize_comparison_keys
Source code in src/rs_py/choices/choice_file_detailed.py
standardize_comparison_keys(comparisons, comparison_type='triadic')
Standardize comparison field order and canonicalize comparison keys.
Takes in a list of comparisons, edits their fields (s1, s2, s3, s4,
judgment), and returns the same list with comparison keys ordered
consistently. Equivalent comparisons are therefore represented identically,
which supports downstream tallying and aggregation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comparisons
|
list[dict]
|
A list of comparisons and judgments with the keys |
required |
comparison_type
|
str
|
Comparison type to standardize. |
'triadic'
|
Returns:
| Type | Description |
|---|---|
|
Notes
- If
(s2, s4)appears in reverse order, the elements are swapped and the judgment is flipped. - For triadic comparisons, the reference appears in both pairs of stimuli
and is always assigned as
s1 = s3 = ref. - The ordering of the two stimulus pairs is determined by alphabetical order of the non-reference elements.
- Example: for pairs
(k, l)and(c, k), the standardized form iss1 = k, s2 = c, s3 = k, s4 = l. - Tetradic comparisons are not yet implemented.
- Within each pair, stimulus order is also determined alphabetically.
- Example: for pairs
(k, l)and(h, w), the standardized form iss1 = h, s2 = w, s3 = k, s4 = l.
See also: generate_comparisons
Source code in src/rs_py/choices/choice_file_detailed.py
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | |
choice_likelihoods
Utilities for computing log-likelihoods for geometry-based comparison data.
This file provides methods for evaluating the log-likelihood of aggregated comparison counts under a distance-geometry response model. The observed data are of the form \(N((i, j) > (k, l))\), meaning the number of times one pair of stimuli was judged more different than another pair.
The model computes choice probabilities from interstimulus distances using an error-function approximation, then evaluates the corresponding log-likelihood. It also includes reference calculations for random-choice and empirical best-case benchmarks.
Note:
The likelihood calculations use log2, so the returned values are in bits.
When sigma_point = 0, the Gaussian-noise assumption matches the erf-based
probability exactly. When sigma_point > 0, the erf probability is only an
approximation because the full noise model is not strictly Gaussian.
(By sigma_point, we mean the standard deviation of additive noise on stimulus
coordinates before distances are computed.)
best_model_ll(judgments, judgment_repeats)
Compute the log-likelihood under an empirical best-case benchmark.
This benchmark assigns each comparison the probability estimated from its observed frequency in the data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
judgments
|
dict
|
Mapping from comparison keys to observed judgment counts. |
required |
judgment_repeats
|
dict
|
Mapping from comparison keys to total repeats. |
required |
Returns:
| Type | Description |
|---|---|
|
tuple[float, bool]: The log-likelihood and infeasibility flag returned by |
Source code in src/rs_py/choices/choice_likelihoods.py
calculate_ll(counts, probs, num_repeats)
Calculate the log-likelihood of observed counts given model probabilities.
This function augments each comparison with its reverse outcome, checks whether the model assigns zero probability to any observed event, and returns the log-likelihood using a base-2 logarithm.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counts
|
ndarray
|
Observed counts for each comparison direction. |
required |
probs
|
ndarray
|
Model probabilities for the corresponding comparisons. |
required |
num_repeats
|
ndarray
|
Total number of repeats for each comparison. |
required |
Returns:
| Type | Description |
|---|---|
|
tuple[float, bool]: The log-likelihood and a boolean flag indicating whether the model is infeasible. |
|
|
The flag is |
Note
The function uses a variable called EPSILON set to 1e-30. This very small positive constant is added only when a model assigns
zero probability to an observed comparison. It prevents log2(0) from causing an error
during likelihood computation, while keeping the adjustment negligible.
Source code in src/rs_py/choices/choice_likelihoods.py
dist_model_ll_vectorized(pair_a, pair_b, judgment_counts, judgment_repeats, params, stimuli)
Compute the log-likelihood under a specific perceptual space model with given distances between points.
This function converts stimulus coordinates into a full pairwise distance
matrix, computes comparison probabilities with find_probabilities, and then
evaluates the log-likelihood against the observed judgment counts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pair_a
|
ndarray
|
Array of index pairs defining the first distance in each comparison. |
required |
pair_b
|
ndarray
|
Array of index pairs defining the second distance in each comparison. |
required |
judgment_counts
|
ndarray
|
Observed counts for the first pair being judged more dissimilar than the second. |
required |
judgment_repeats
|
ndarray
|
Total number of repeats for each comparison. |
required |
params
|
dict
|
Model parameters. Must contain |
required |
stimuli
|
ndarray
|
Stimulus coordinates used to compute pairwise distances. |
required |
Returns:
| Type | Description |
|---|---|
|
tuple[float, bool]: The log-likelihood and the infeasibility flag returned by |
See Also
find_probabilities: Convert distance differences into choice probabilities.
Source code in src/rs_py/choices/choice_likelihoods.py
find_probabilities(distances, pair_a, pair_b, noise_st_dev)
Compute choice probabilities from pairwise distance differences.
For each comparison, this function subtracts the second pair distance from the first pair distance and converts that difference into a probability that the first pair is judged more different.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
distances
|
ndarray
|
Square matrix of pairwise stimulus distances. |
required |
pair_a
|
ndarray
|
Array of index pairs defining the first distance in each comparison. |
required |
pair_b
|
ndarray
|
Array of index pairs defining the second distance in each comparison. |
required |
noise_st_dev
|
float
|
Standard deviation of the combined Gaussian noise term. |
required |
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Probability that the first pair is judged more different than the second. |
Note
When noise_st_dev = 0, the output is deterministic, with probabilities 0, 0.5, or 1
depending on the sign of the distance difference. When noise_st_dev > 0, the probability
is computed using an approximation based on the erf function.
Source code in src/rs_py/choices/choice_likelihoods.py
random_choice_ll(judgments, judgment_repeats)
Compute the log-likelihood under a random-choice benchmark.
This benchmark assumes every comparison direction is equally likely, so each observed judgment has probability 0.5.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
judgments
|
dict
|
Mapping from comparison keys to observed judgment counts. |
required |
judgment_repeats
|
dict
|
Mapping from comparison keys to total repeats. |
required |
Returns:
| Type | Description |
|---|---|
|
tuple[float, bool]: The log-likelihood and infeasibility flag returned by |
Source code in src/rs_py/choices/choice_likelihoods.py
demos
demo_combined_choices
To demo the script that aggregates detailed trial-level choice judgments into a combined (unique-comparison) choice file.
This demos
combine_choice_mat(input_mat_path, output_dir, exp_name, subject)
Enter 0 to use default values.
demo_detailed_choices
Demo: create a detailed choices .mat file from raw ranking judgments.
This script
- Parses raw subject CSV files from a ranking experiment.
- Generates triadic or tetradic comparisons.
- Replaces stimulus labels with numeric IDs.
- Canonicalizes comparison keys.
- Saves a detailed trial-level .mat file.
Enter 0 to use default values.
demo_fit_euclidean
Demo to fit models of Euclidean spaces of different dimensions, from tallied similarity judgments. Enter '0' to use default values.
demo_inputs()
Populate demo defaults. Adjust the default filepath/outdir to wherever your sample materials live.
Source code in src/rs_py/demos/demo_fit_euclidean.py
geometry
euclidean
Sample points from Euclidean spaces of configurable dimension.
This module provides utilities for drawing stimulus locations in an n-dimensional Euclidean space. Points can be sampled from the surface of a sphere, from a Gaussian distribution, or uniformly from inside a sphere.
EuclideanSpace
Represent an n-dimensional Euclidean space for sampling points.
Source code in src/rs_py/geometry/euclidean.py
__init__(num_dim)
Set the dimensionality of the space. Args: num_dim (int): Number of dimensions in the Euclidean space.
Source code in src/rs_py/geometry/euclidean.py
get_samples(num_stimuli, magnitude=1, method='spherical_shell')
Sample multiple points from the space.
Args:
num_stimuli (int): Number of points to sample.
magnitude (float): Target magnitude or scale of each sample.
method (str): Sampling method. Options are spherical_shell, gaussian, and uniform.
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Array of sampled points, one per stimulus. |
Source code in src/rs_py/geometry/euclidean.py
sample_space(magnitude, method='spherical_shell')
Sample one point from the space.
Args:
magnitude (float): Target magnitude or scale of the sample.
method (str): Sampling method. Options are spherical_shell, gaussian, and uniform.
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray or float: A sampled point. For |
Source code in src/rs_py/geometry/euclidean.py
hyperbolic
Add curvature to a Euclidean fit and test whether the fit improves.
This module takes a Euclidean embedding that already explains psychophysical judgments, maps the points onto the top sheet of a two-sheet hyperboloid using Loid geometry, and then computes pairwise hyperbolic distances. The resulting distances can be used to evaluate whether adding negative curvature improves log-likelihood relative to the Euclidean model.
The mapping is controlled by a curvature parameter, which determines how close the projected points lie to the hyperboloid center. When the curvature parameter approaches 0, the geometry approaches Euclidean space, so improved fit at positive curvature provides evidence for curvature in the space, after accounting for the extra parameter.
hyperbolic_distances(X, curvature)
Compute pairwise hyperbolic distances between points on the hyperboloid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Array of shape (d + 1, n) containing points already projected onto the hyperboloid. |
required |
curvature
|
float
|
Positive curvature parameter used to scale the resulting distances. |
required |
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Pairwise hyperbolic distance matrix for the points in X. |
Notes
Distances are computed as \(arccosh(-[X, X])\).
Source code in src/rs_py/geometry/hyperbolic.py
loid_map(X, degree_curvature)
Map Euclidean points onto the top sheet of a two-sheet hyperboloid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Array of shape (d, n), with n points in d Euclidean dimensions. |
required |
degree_curvature
|
float
|
Curvature parameter controlling how strongly the points are projected toward hyperbolic geometry. |
required |
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Array of shape (d + 1, n) containing the projected points on the hyperboloid. |
Source code in src/rs_py/geometry/hyperbolic.py
spherical
Sample points on a sphere and compute pairwise spherical distances.
This module provides helpers for mapping Euclidean points onto a spherical surface and measuring pairwise spherical distances. It includes legacy (deprecated) versions of the mapping and distance functions, plus the current implementations used in the codebase.
sphere_map(X, radius)
Map Euclidean points to the surface of a sphere.
This function rescales the input by the sphere radius and applies the current spherical mapping used for visualization and analysis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Array of shape (d, n), with n points in d Euclidean dimensions. |
required |
radius
|
float
|
Radius of the sphere. |
required |
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Array of shape (d + 1, n) containing points projected onto the sphere. |
Notes
mu (curvature) is 1/ radius.
Source code in src/rs_py/geometry/spherical.py
spherical_distances(X, radius)
Compute pairwise spherical distances between points on the sphere.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Array of shape (d, n) containing points already projected onto the sphere. |
required |
radius
|
float
|
Radius of the sphere. |
required |
Returns:
| Type | Description |
|---|---|
|
numpy.ndarray: Pairwise spherical distance matrix. |
Notes
Assumes the points passed in are not off the surface - already projected! Distance is \(arccos(-[X, X])\) for all points X
Source code in src/rs_py/geometry/spherical.py
model
compare_curved_space_models
Here, given a data set, generate surrogate datasets that are drawn from the original choice probablities. Then, for each surrogate dataset, essentially calculate LLs for a range of curvatures and (chosen/ adjusted) sigma values.
This should yield a scatterplot of model LLs by scripts values. We start by doing so for the 2D case and we can progress to higher dimensions as needed.
## DEPRECATED - DO NOT USE
The inputs are - a range of scripts values - dimensions for which to apply the analysis. Minimum dimension is 2. - path to json files for individual datasets. - optionally, can and probably should pass in a legend for when multiple curves are drawn - number of iterations (surrogates) - max number of iterations to run the model_fitting pipeline with.
fit_geometric_models
hyperbolic_points_of_best_fit(judgments, number_repeats, args, start_points=None)
Fit hyperbolic coordinates to the observed judgments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
judgments
|
dict
|
Pairwise comparison judgments. |
required |
number_repeats
|
dict
|
Number of repeats for each comparison key in |
required |
args
|
dict
|
Model settings. Must include:
- |
required |
start_points
|
array - like
|
Initial coordinates for optimization. If not provided, MDS-derived starting points are used. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(coordinates, solution_ll) - coordinates: fitted hyperbolic coordinates - solution_ll: negative log-likelihood of the fitted solution |
Source code in src/rs_py/model/fit_geometric_models.py
points_of_best_fit(judgments, number_repeats, args, start_points=None)
Fit Euclidean coordinates to the observed judgments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
judgments
|
dict
|
Pairwise comparison judgments |
required |
number_repeats
|
dict
|
Number of repeats for each comparison key in |
required |
args
|
dict
|
Model settings. Must include:
- |
required |
start_points
|
array - like
|
Initial coordinates for optimization. If not provided, MDS-derived starting points are used. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(coordinates, solution_ll) - coordinates: fitted Euclidean coordinates - solution_ll: negative log-likelihood of the fitted solution |
Source code in src/rs_py/model/fit_geometric_models.py
spherical_points_of_best_fit(judgments, number_repeats, args, start_points=None)
Fit spherical coordinates to the observed judgments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
judgments
|
dict
|
Pairwise comparison judgments |
required |
number_repeats
|
dict
|
Number of repeats for each comparison key in |
required |
args
|
dict
|
Model settings. Must include at least:
- |
required |
start_points
|
array - like
|
Initial coordinates for optimization. If not provided, MDS-derived starting points are used. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(coordinates, solution_ll) - coordinates: fitted spherical coordinates - solution_ll: negative log-likelihood of the fitted solution |
Source code in src/rs_py/model/fit_geometric_models.py
scripts
model_fitting
Script wrapper for the geometric model fit demo.
build_model_fit_args(user_params)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_params
|
dict
|
Partial parameter dictionary supplied by the caller. Any keys present here override the defaults in CONFIG["inputs"][]. If provided, this may include required keys such as "filepath" and "output_dir", along with optional settings like "sigma" or "model_dimensions". |
required |
Returns: args (dict): A complete parameter dictionary for the model-fit runner. This is built from CONFIG["inputs"][] plus any overrides from user_params.
Notes
The returned dict is intended to be passed directly to the run function. Required keys must still be present after merging.
Source code in src/rs_py/scripts/model_fitting.py
fit(params)
Fit Euclidean geometric models to aggregated choice data and save model outputs.
This function loads a combined choice file, optionally subsamples a fixed
number of unique triadic judgments, fits Euclidean models across one or more
requested dimensions, compares them against best-choice and random-choice
baselines, and saves both a CSV summary and a .mat file of fitted
coordinates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
params
|
dict
|
Dictionary of run parameters. Common keys include: Required:
filepath (str):
Path to the combined choices Recommended / commonly used:
exp_name (str):
Experiment name used in output filenames.
subject (str):
Subject ID used in output filenames.
model_dimensions (list[int]):
Dimensions to fit, for example |
required |
Returns:
| Name | Type | Description |
|---|---|---|
None |
Writes output files to |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the input file does not exist. |
ValueError
|
If no triadic judgments are found after loading or filtering. |
Notes
- The input file is expected to be a combined choice file produced by the earlier aggregation step.
sigmais a required noise scale and controls the uncertainty in distance comparisons.model_dimensionsshould be chosen with the number of stimuli and the intended model complexity in mind.- The function saves fitted coordinates for each dimension, along with a CSV comparing model log-likelihoods.
Source code in src/rs_py/scripts/model_fitting.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | |
write_choice_file
Script wrapper for the combined-choice demo.
write_choice_file_detailed
To demo the script choice_file_detailed.py
run(user_params)
Run the detailed choice-file builder on a set of user parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_params
|
dict
|
Dictionary of parameters used to build the detailed choice file. Required keys: - input_path: Path to the input directory containing raw data. - output_dir: Path to the directory where outputs should be saved. Optional key: - metadata: Dictionary with optional fields such as: - exp_name: Experiment name. - subject: Subject identifier. - stim_list: List of stimuli. - num_sessions: Number of sessions. - num_trials: Number of trials. - total_judgments: Total number of judgments. - judgment_type: Type of judgment task, default is "triadic". |
required |
Returns:
| Type | Description |
|---|---|
|
None |
Raises: - ValueError: If a required parameter is missing or empty. - TypeError: If metadata is provided but is not a dictionary. - FileNotFoundError: If input_path does not exist.
Source code in src/rs_py/scripts/write_choice_file_detailed.py
utils
anchor_coordinates
Use the Gram Schmidt procedure to reorient a set of points such that one point is at the origin, another point lies on one axis (x1, 0, ..., 0) and the next point lies on a plane spanned by the two axes (x2, x3, 0, ..., 0), and so on. This constrains the minimization function that looks for the points of best fit, as rotations and translations are made redundant.
This can also take into effect the noise parameter as we do not constrain where on the first axis, the second point lies.
anchor_points(points)
points: 37 by d matrix Given a set of 37 points, find the rotation needed using Gram Schmidt and then transform the coordinates to the format needed - one point is zero and the rest are partly in a triangular form
Source code in src/rs_py/utils/anchor_coordinates.py
choose_basis_vectors(M)
Given a matrix of points M (m by n), where m is the number of dimensions and n is the number of points, choose m vectors that are linearly independent from each other.
The chosen submatrix is the first m columns of M (m by m). If it has full rank, it is returned unchanged.
If it is rank-deficient, a warning is issued and a multiple of the identity matrix is added to it: q2^hI, where q is the smallest nonzero absolute value in the submatrix and h is the smallest non-negative integer for which the result has full rank. If the submatrix is all zeros, the identity matrix is returned.
Source code in src/rs_py/utils/anchor_coordinates.py
gram_schmidt(B)
Take in an m by m matrix A and return a matrix with orthonormal vectors that span the same space as A In this case, we assume that the input matrix A is square and has linearly independent vectors.
Source code in src/rs_py/utils/anchor_coordinates.py
params_to_points(x0, num_stimuli, n_dim)
Takes a vector of parameters and separates it into points :param x0: all stimulus coordinates (that are nonzero) vectorized :param num_stimuli: (int) number of points :param n_dim: (int) dimensionality of space points come from :return: points is a 2D array containing point coordinates. size: num_stimuli x n_dim
Source code in src/rs_py/utils/anchor_coordinates.py
points_to_params(points)
points is a matrix with at least as many rows as columns. d is the number of columns n is the number of rows (points) This function takes a matrix of the form [[0, ..., 0], [x1, 0..., 0], [x2, x3, ..., 0], ... [xk, xk+1, ...xl, 0], [xl+1, ..., xl+d] ...] such that the first d points have 0, 1, 2, ..., d non zero params and the following rows all have nonzero params
Return the nonzero params in an array
Source code in src/rs_py/utils/anchor_coordinates.py
helpers
combine_model_npy_files_to_mat(directory, domain, subject, outdir='.', min_dim=1, max_dim=7)
Edited on Aug 3, 2023 Add LL and biases too @param directory: input dir - dir in which is a domain dir then a subject dir @param subject: @param outdir: @param min_dim: @param max_dim: @return:
Source code in src/rs_py/utils/helpers.py
create_coords_file(outdir, exp, subject, model_dimensions, points, lls, stim_labels, tolerance=0.5, samples=70)
Save fitted coordinates, likelihoods, and stimulus labels to a .mat file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
outdir
|
str
|
Directory where the |
required |
exp
|
str
|
Experiment name used in the output filename. |
required |
subject
|
str
|
Subject ID used in the output filename. |
required |
model_dimensions
|
list[int]
|
Model dimensions to include, such as |
required |
points
|
dict
|
Fitted coordinates for each dimension, keyed by dimension. |
required |
lls
|
dict
|
Log-likelihood values for each dimension, plus |
required |
stim_labels
|
list[str]
|
Stimulus labels in the order matching the fitted data. |
required |
tolerance
|
float
|
Tolerance used when estimating likelihood bias. Default is |
0.5
|
samples
|
int
|
Number of samples used when estimating likelihood bias. Default is |
70
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
Path to the saved |
Notes
The saved file includes:
- dim{d} for each fitted dimension
- rawLLs
- biasEstimate
- debiasedRelativeLL
- bestModelLL
- randModelLL
- stim_labels
Source code in src/rs_py/utils/helpers.py
write_choice_probs_to_mat(filepath, outdir, outfilename, include_names=False)
In output mat file, in responses matrix, ref, s1 and s2 go from 1-37 or 1-25 in JV's experiments. Because Matlab has 1-indexing this is better - allows indexing stim_list more natural. @param include_names: @param filepath: path to exp.json file with rank judgments @param outdir: directory to write mat file in @param outfilename: name of output file. May include subject and/ or condition and/ or num_sessions information @return:
Source code in src/rs_py/utils/helpers.py
mds_embedding
To improve ordinary Nelder-Mead minimization, I can initialize the minimization with coordinates returned by metric multidimensional scaling (MDS). This file is to test if this alternate seeding can help.
To get coordinates from MDS, I first need a distance matrix. The simulated judgments do not directly provide pairwise distances. Instead they provide data on comparisons of pairs of pairs of stimuli - all we know is if one distance is larger than another. We do not know the magnitude of any distance.
We can work around this by using a heuristic as follows. Let d(i, j) be (a + 1)/ (a + b + 2), where a is the number of times d(i, j) was judged to be LARGER than another distance d(m, n) a is counted by iterating over all comparisons of (i, j) with other pairs (m, n). b is the number of times d(i, j) was judged to be SMALLER than another distance d(m, n), summed over all pairs m, n
format_distances(distance_dict)
Take in dict of distances and convert to a symmetric matrix. Leave any unknown distance values 0 :param distance_dict: e.g. (0,1) -> 3 :return: distance matrix, e.g. D[0, 3] = D[3, 0] = 3
Source code in src/rs_py/utils/mds_embedding.py
get_coordinates(n_dim, judgments, repeats, epsilon=1e-09)
Given judgments and number of dimensions, return an estimate of point coordinates using MDS :param seed: for MDS (int) :param judgments (dict) :param repeats (int) :param n_dim (int) :param epsilon: error threshold which controls when MDS terminates
Source code in src/rs_py/utils/mds_embedding.py
heuristic_distances(judgments, repeats)
Returns a numeric value for each distance (i, j) in judgments: d = (a + 1)/ (a + b + 2) a is number of times a distance is greater than another :param repeats: number of times each pairwise comparison is repeated :param judgments: (dict) key: pairs of distances (i,j) (m,n), value: counts :return: dict of distances (pair (i, j) -> distance value)
Source code in src/rs_py/utils/mds_embedding.py
minimize
gradient_descent(costfunc, start, pair_a, pair_b, counts, repeats, params)
" Implements stochastic gradient descent. The code below is my first attempt and not an optimized program Based on a tutorial on realpython.com
Source code in src/rs_py/utils/minimize.py
util
Some utilities to help with processing psychophysical data files
judgments_to_arrays(judgments_dict, repeats)
Instead of having trials be a dictionary with keys made of tuples, convert judgment keys and values into numpy arrays for faster operations
Source code in src/rs_py/utils/util.py
ranking_to_pairwise_comparisons(distance_pairs, ranked_stimuli)
Convert ranking data to comparisons of pairs of pairs of stimuli
@param distance_pairs: :type distance_pairs: list :param ranked_stimuli: :type ranked_stimuli: list
Source code in src/rs_py/utils/util.py
read_combined_choices(filepath)
Read a combined choice .mat file and return aggregated pairwise judgments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
Path to the combined choice file. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
pairwise_responses, pairwise_num_repeats, metadata, stim_list
|