├── LICENSE ├── README.md ├── experiments ├── frank2009.m ├── gerken2006_2010.m ├── gomez2002.m ├── kovacs2009.m ├── marcus2007.m └── saffran2007.m ├── helper ├── addNoiseToTraining.m ├── applyRuleToString.m ├── cacheCardinalities.m ├── cacheItems.m ├── cacheTest.m ├── chooseClass.m ├── cleanUpClasses.m ├── computeCRP.m ├── computeCleanTest.m ├── computeCorrectedPosteriorFromTrainingData.m ├── computeNoisyLikelihood.m ├── computeNoisyLikelihood2.m ├── computeNoisyPosterior.m ├── computeNoisyPosteriorGerken2010.m ├── computeNoisyPosteriorMultimodal.m ├── computeNoisyTest.m ├── computePosteriorFromTrainingData.m ├── computeTest.m ├── computeTestMultimodal.m ├── createHypothesisSpace.m ├── crp.m ├── displayOutputs.m ├── ent.m ├── findMLHypotheses.m ├── logsumexp.m ├── rotateticklabel.m ├── setupWorld.m ├── stderr.m ├── writeResults.m ├── writeResultsE1.m └── writeResultsNoisy.m ├── mats ├── endress2007.mat ├── frank2009.mat ├── gerken2006.mat ├── gerken2006_2010.mat ├── gerken2010.mat ├── gomez2002.mat ├── kovacs2009-sims.mat ├── kovacs2009.mat ├── marcus1999.mat ├── marcus2007.mat └── saffran2007.mat ├── model1.m ├── model2.m ├── model3.m └── modelE1.m /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, mcfrank 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rules 2 | ===== 3 | 4 | This repository contains the code for a model by Frank & Tenenbaum (2011), and corrections, elaborations, and extensions. It is a more dynamic version of the original zip file that was distributed with the paper. 5 | 6 | Correction 7 | ---------- 8 | 9 | Note that this code contains a correction to Equation 4, suggested by Florent Meyniel. The bottom term of this Equation should read \frac{(1-\alpha)}{|S|} instead of \frac{(1-\alpha)}{|S|-|r|}. 10 | 11 | When this correction is implemented, there are some small numerical differences in results, but as far as we know, no qualitative differences resulting in modification to any of our claims. 12 | 13 | Original readme is below: 14 | ===== 15 | Readme for code accompanying Frank & Tenenbaum, "Three ideal observer models for rule learning in simple languages." 16 | 17 | Paper linked here: http://langcog.stanford.edu/papers/FT-cognition2011.pdf 18 | 19 | This archive contains matlab code to reproduce the simulations reported in our paper. The main director contains three scripts. Each one can be modified directly by changing the parameters specified at the top of the script; comments in each one describe which options are possible. 20 | 21 | * SCRIPTS 22 | 23 | model1.m - single rule, no noise 24 | 25 | model2.m - single rule, memory noise 26 | 27 | model3.m - multiple rules, memory noise (note that this model uses a gibbs sampler for approximate inference and so runs considerably slower and provides approximate guesses about the posterior over rule clusters rather than giving an exact posterior as the other two do). 28 | 29 | * DIRECTORIES 30 | 31 | experiments - contains scripts for reproducing our simulations. 32 | 33 | helper - contains a variety of helper functions for the base models and the simulations. 34 | 35 | mats - contains cached hypothesis space .MAT files. the efficiency of our models relies on much of the computation being cached ahead of time and looked up during inference. 36 | 37 | All code was created using Matlab R2010a. Feel free to modify or distribute any of this code but please cite the corresponding paper. 38 | 39 | -------------------------------------------------------------------------------- /experiments/frank2009.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 2 | % frank, slemmer, marcus, & johnson (2009) simulations 3 | % 4 | % result was that multimodal rule learning succeeded with 5mos while 5 | % unimodal rule learning failed. 6 | 7 | clear all 8 | addpath('..') 9 | 10 | % parameters 11 | params.expt = 'frank2009'; 12 | langs = {'uni','multi'}; 13 | params.n_subs = 100; 14 | 15 | % initialization 16 | alphas = 0:.05:1; 17 | p_success = nan([length(alphas) 3 params.n_subs]); 18 | 19 | 20 | %% simulations 21 | 22 | for l = 1:length(langs) 23 | disp(['*** lang = ' langs{l} ' ***']) 24 | 25 | params.lang = langs{l}; 26 | name = ['../mats/' params.expt '.mat']; 27 | [hs train correct incorrect] = setupWorld(params); 28 | load(name); 29 | index_cache = cacheItems(train,correct,incorrect,hs); 30 | 31 | % square the hypothesis space if we're multimodal 32 | if strcmp(langs{l},'multi') 33 | hs.log_probs = hs.log_probs*2; 34 | hs.cardinalities = hs.cardinalities.^2; 35 | end 36 | 37 | % now iterate through the parameters 38 | for a = 1:length(alphas) 39 | params.alpha = alphas(a); 40 | 41 | tic 42 | for i = 1:params.n_subs 43 | 44 | ps = computeNoisyPosteriorMultimodal(hs,train,params,index_cache,langs{l}); 45 | resps = computeTestMultimodal(hs,ps,correct,incorrect,params,index_cache,langs{l}); 46 | 47 | resps = resps - logsumexp(resps'); 48 | p_success(a,l,i) = exp(resps(1)) / sum(exp(resps)); 49 | surprisal(a,l,i) = diff(-resps); 50 | end 51 | toc 52 | end 53 | end 54 | 55 | save frank2009.mat p_success surprisal 56 | 57 | %% plot 58 | load mats/frank2009.mat 59 | 60 | figure(1) 61 | clf 62 | hold on 63 | set(gca,'FontSize',12) 64 | mps = mean(surprisal,3); 65 | plot(alphas,mps(:,1),'k-') 66 | plot(alphas,mps(:,2),'k--') 67 | 68 | alphas = round(alphas*100)/100; 69 | axis([0 1 floor(min(min(mps))) ceil(max(max(mps)))]) 70 | xlabel('\alpha (noise parameter) value') 71 | ylabel('difference in surprisal (bits)') 72 | legend({'unimodal rule','multimodal rule'},'Location','NorthWest') -------------------------------------------------------------------------------- /experiments/gerken2006_2010.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 2 2 | % gerken (2006) and gerken (2010) simulations 3 | 4 | clear all 5 | addpath('../helper') 6 | 7 | % parameters 8 | expts = {'gerken2006','gerken2006','gerken2006','gerken2010','gerken2010'}; 9 | langs = {'AAB','AAx','AAx2','col+5','music+5'}; 10 | params.n_subs = 100; 11 | 12 | % initialization 13 | alphas = 0:.05:1; 14 | alpha_decrease = .3; % the amount you cut down alpha for the +5 15 | p_success = nan([length(alphas) 5 params.n_subs]); 16 | 17 | %% simulations 18 | 19 | for l = 1:length(langs) 20 | disp(['*** lang = ' langs{l} ' ***']) 21 | 22 | params.expt = expts{l}; 23 | params.lang = langs{l}; 24 | name = ['../mats/' params.expt '.mat']; 25 | [hs train correct incorrect] = setupWorld(params); 26 | load(name); 27 | index_cache = cacheItems(train,correct,incorrect,hs); 28 | 29 | for a = 1:length(alphas) 30 | params.alpha = alphas(a); 31 | 32 | tic 33 | for i = 1:params.n_subs 34 | if l > 3 35 | ps = computeNoisyPosteriorGerken2010(hs,train,params,index_cache,... 36 | alphas(a) - alpha_decrease); 37 | else 38 | ps = computeNoisyPosterior(hs,train,params,index_cache); 39 | end 40 | resps = computeTest(hs,ps,correct,incorrect,params,index_cache); 41 | surprisal(a,l,i) = diff(-( resps - logsumexp(resps'))); 42 | end 43 | toc 44 | end 45 | end 46 | 47 | save ../mats/gerken2006_2010.mat surprisal 48 | 49 | %% plot 50 | load ../mats/gerken2006_2010.mat 51 | aval = 17; % which value of alpha do we use? 52 | 53 | figure(1) 54 | clf 55 | set(gcf,'Position',[440 358 1000 350]) 56 | set(gcf,'Color','none') 57 | 58 | subplot(1,4,1:2) 59 | set(gca,'Color','none') 60 | hold on 61 | set(gca,'FontSize',12) 62 | mps = mean(surprisal,3); 63 | err = stderr(surprisal,3); 64 | r = 1:length(alphas)-1; 65 | plot(alphas(r),mps(r,1),'k-o') 66 | plot(alphas(r),mps(r,2),'k-s') 67 | plot(alphas(r),mps(r,3),'k-d') 68 | plot(alphas(r),mps(r,4),'k-^') 69 | plot(alphas(r),mps(r,5),'k-v') 70 | 71 | % fill the markers for the parameters we use 72 | plot(alphas(aval),mps(aval,1),'ok','MarkerFaceColor',[0 0 0]) 73 | plot(alphas(aval),mps(aval,2),'sk','MarkerFaceColor',[0 0 0]) 74 | plot(alphas(aval),mps(aval,3),'dk','MarkerFaceColor',[0 0 0]) 75 | plot(alphas(aval),mps(aval,4),'^k','MarkerFaceColor',[0 0 0]) 76 | plot(alphas(aval),mps(aval,5),'vk','MarkerFaceColor',[0 0 0]) 77 | 78 | 79 | alphas = round(alphas*100)/100; 80 | axis([0 1 floor(min(min(mps))) ceil(max(max(mps)))]) 81 | xlabel('\alpha (noise parameter) value') 82 | ylabel('difference in surprisal (bits)') 83 | title('Model 2: \alpha varied') 84 | set(gca,'YTick',0:5:15) 85 | set(gca,'XTick',0:.2:1) 86 | axis([0 1.2 0 15]) 87 | 88 | labels = {'AAB','AAx','AAx2','column+5','music+5'}; 89 | 90 | for i = 1:5 91 | text(1,mps(end-1,i),labels{i},'FontSize',12); 92 | end 93 | 94 | subplot(1,4,3) 95 | cla 96 | set(gca,'Color','none') 97 | set(gca,'FontSize',12) 98 | hold on 99 | bar(mps(aval,:),'FaceColor',[.5 .5 .5]) 100 | errorbar(1:5,mps(aval,:),err(aval,:),'k.','MarkerSize',.1); 101 | ylabel('difference in surprisal (bits)') 102 | set(gca,'XTick',1:5,'XTickLabel',{'AAB','AAx','AAx2','col+5','mus+5'}) 103 | th = rotateticklabel(gca); 104 | set(th,'FontSize',12) 105 | title(['Model 2: \alpha = ' num2str(alphas(aval)) ... 106 | ', \alpha_{+5} = ' num2str(alphas(aval)-alpha_decrease)]); 107 | set(gca,'Box','off') 108 | m = max(mps(aval,:)); 109 | axis([0 6 0 round(m*1.1)]) 110 | 111 | subplot(1,4,4) 112 | set(gca,'Color','none') 113 | set(gca,'FontSize',12) 114 | lt_diffs = [3.37 0.56 3.08 (10.7 - 8.5) (16.4 - 14.3)]; 115 | bar(lt_diffs,'FaceColor',[.5 .5 .5]); 116 | ylabel('difference in looking time (s)') 117 | set(gca,'XTick',1:5,'XTickLabel',{'AAB','AAx','AAx2','col+5','mus+5'}) 118 | th = rotateticklabel(gca); 119 | set(th,'FontSize',12) 120 | title('Experimental data') 121 | set(gca,'Box','off') 122 | axis([0 6 0 4]) 123 | -------------------------------------------------------------------------------- /experiments/gomez2002.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 3 2 | % simulations for gomez (2002), psych science 3 | % score alternative hypotheses 4 | 5 | % note the different alpha range and slightly greater number of sims 6 | % compared to the paper - this was done to follow up on some minor 7 | % numerical differences found between the figure and future simulations 8 | 9 | clear all 10 | 11 | params.expt = 'gomez2002'; 12 | params.lang = '2x'; 13 | params.alpha = 1; 14 | params.gamma = 1; % hyperparameter for the chinese restaurant process 15 | 16 | name = ['../mats/' params.expt '.mat']; 17 | [~, train correct incorrect] = setupWorld(params); 18 | load(name); 19 | 20 | % initialization 21 | conds = {'2x','6x','12x','24x'}; 22 | gammas = [1]; 23 | alphas = [.3:.025:.8]; % was [.1:.1:.9] 24 | num_subs = 200; % was 100 but the variance was pretty high 25 | 26 | %% simulations 27 | clear one_post two_post 28 | 29 | for cond = 1:length(conds) 30 | disp(conds{cond}); 31 | params.lang = conds{cond}; 32 | [~, original_train, ~, ~] = setupWorld(params); 33 | original_index_cache = cacheItems(original_train,correct,incorrect,hs); 34 | n = length(original_train); 35 | 36 | for a = 1:length(alphas) 37 | for g = 1:length(gammas) 38 | for i = 1:num_subs 39 | disp([num2str(a) '-' num2str(g) '-' num2str(i)]); 40 | params.alpha = alphas(a); 41 | params.gamma = gammas(g); 42 | 43 | [train index_cache] = addNoiseToTraining(hs,original_train,params,original_index_cache); 44 | 45 | c = repmat([1 2],[1 n/2]); 46 | two_post(cond,a,g,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 47 | computeCRP(c,params); 48 | 49 | c = ones(1,n); 50 | one_post(cond,a,g,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 51 | computeCRP(c,params); 52 | 53 | end 54 | end 55 | end 56 | end 57 | 58 | save ../mats/gomez2002.mat 59 | 60 | %% plot 61 | 62 | load ../mats/gomez2002.mat 63 | 64 | gamma = 1; 65 | ones = mean(one_post,4); 66 | twos = mean(two_post,4); 67 | odds = twos-ones; 68 | two_probs = exp(two_post(:,:,gamma,:))./(exp(one_post(:,:,gamma,:))+exp(two_post(:,:,gamma,:))); 69 | one_probs = exp(one_post(:,:,gamma,:))./(exp(one_post(:,:,gamma,:))+exp(two_post(:,:,gamma,:))); 70 | 71 | % luce choice rule 72 | choice_probs = (one_probs .* .5) + two_probs; 73 | mcps = mean(choice_probs,4); 74 | 75 | figure(1) 76 | set(gcf,'Position',[440 358 1000 350]) 77 | clf 78 | 79 | % left half 80 | subplot(1,4,1:2) 81 | set(gca,'Fontsize',12) 82 | title('model 3, \alpha varied, \gamma = 1') 83 | h = plot([2 6 12 24],mcps(:,:),'k--o'); 84 | axis([-1 25 .4 1]) 85 | xlabel('number of X elements') 86 | set(gca,'XTick',[2 6 12 24]) 87 | ylabel('choice probability') 88 | 89 | for i = 1:size(mcps,2) 90 | text(-0.5,mcps(1,i),num2str(alphas(i),'%2.2f')); 91 | end 92 | title('model 3: \alpha varied, \gamma = 1') 93 | set(gca,'Box','off') 94 | 95 | % middle 96 | subplot(1,4,3) 97 | hold on 98 | set(gca,'Fontsize',12) 99 | 100 | bar(mean(choice_probs(:,find(alphas==.4),:,:),4),'FaceColor',[.5 .5 .5]) 101 | title('model 3: \alpha = .4, \gamma = 1') 102 | axis([0 5 .4 1]) 103 | set(gca,'XTickLabel',[2 6 12 24],'XTick',[1 2 3 4]) 104 | 105 | 106 | % right side 107 | trained = [88 87 77 100]; 108 | untrained = [68 54 47 20]; 109 | gomez = mean([trained; 100-untrained]) ./ 100; 110 | sems = [11 12 14 11] ./ 100; 111 | 112 | subplot(1,4,4) 113 | hold on 114 | set(gca,'Fontsize',12) 115 | bar(gomez,'FaceColor',[.5 .5 .5]) 116 | errorbar(1:4,gomez,sems,'.k','MarkerSize',.1) 117 | axis([0 5 .4 1]) 118 | set(gca,'XTickLabel',[2 6 12 24],'XTick',[1 2 3 4]) 119 | title('experimental data') 120 | -------------------------------------------------------------------------------- /experiments/kovacs2009.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 3 2 | % simulations for kovacs & mehler (2009), science 3 | % score alternative hypotheses 4 | 5 | clear all 6 | 7 | params.expt = 'kovacs2009'; 8 | params.lang = ''; 9 | params.alpha = 1; 10 | load('../mats/kovacs2009.mat'); 11 | addpath('../helper') 12 | 13 | %% 14 | gammas = [1e-1 1e-2 1e-3 1e-4 1e-5]; 15 | alphas = [.5:.05:1]; 16 | num_subs = 100; 17 | 18 | [~, original_train, correct, incorrect] = setupWorld(params); 19 | original_index_cache = cacheItems(original_train,correct,incorrect,hs); 20 | n = length(original_train); 21 | 22 | for a = 1:length(alphas) 23 | for g = 1:length(gammas) 24 | for gd = g+1:length(gammas) 25 | for i = 1:num_subs 26 | disp([num2str(a) '-' num2str(g) '-' num2str(gd) '-' num2str(i)]); 27 | [train index_cache] = addNoiseToTraining(hs,original_train,params,original_index_cache); 28 | 29 | % -- two rules -- 30 | c = [1 1 1 1 1 1 2 2 2 2 2 2]; 31 | % bilingual 32 | params.alpha = alphas(a); 33 | params.gamma = gammas(g); 34 | two_post(1,a,g,gd,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 35 | computeCRP(c,params); 36 | 37 | % monolingual 38 | params.alpha = alphas(a); 39 | params.gamma = gammas(gd); 40 | two_post(2,a,g,gd,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 41 | computeCRP(c,params); 42 | 43 | % -- one rule -- 44 | c = [1 1 1 1 1 1 1 1 1 1 1 1]; 45 | % bilingual 46 | params.alpha = alphas(a); 47 | params.gamma = gammas(g); 48 | one_post(1,a,g,gd,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 49 | computeCRP(c,params); 50 | 51 | % monolingual 52 | params.alpha = alphas(a); 53 | params.gamma = gammas(gd); 54 | one_post(2,a,g,gd,i) = computeNoisyLikelihood2(hs,c,train,params,index_cache) + ... 55 | computeCRP(c,params); 56 | end 57 | end 58 | end 59 | end 60 | 61 | save ../mats/kovacs2009-sims.mat one_post two_post 62 | 63 | %% plots 64 | 65 | load ../mats/kovacs2009-sims.mat 66 | one_prob = exp(one_post) ./ (exp(one_post) + exp(two_post)); 67 | two_prob = exp(two_post) ./ (exp(one_post) + exp(two_post)); 68 | 69 | % first_prob = one_prob + two_prob; 70 | % second_prob = two_prob; 71 | 72 | choice_prob = (one_prob .* .5) + two_prob; 73 | diff_score = (choice_prob - .5) .* 2; 74 | mds = mean(diff_score,5); 75 | 76 | 77 | figure(1); 78 | clf 79 | 80 | % full parameter space 81 | subplot(1,3,1:2) 82 | hold on 83 | set(gca,'FontSize',12) 84 | for g = 1:length(gammas) 85 | for gd = g+1:length(gammas) 86 | y = mean(-diff(two_prob(:,:,g,gd,:)),5); 87 | plot(alphas,y,'--ok') 88 | 89 | text(1.05,y(end),[num2str(gammas(g),'%0.e') '/' num2str(gammas(gd),'%0.e')]) 90 | end 91 | end 92 | axis([.5 1.2 0 1]) 93 | set(gca,'XTick',.5:.25:1) 94 | xlabel('\alpha (noise parameter) value') 95 | ylabel('difference in probability of two rules') 96 | title('Model 3: \alpha, \gamma_B, \gamma_M varied') 97 | 98 | a = 9; 99 | g = 1; 100 | gd = 3; 101 | plot(alphas(a),mean(-diff(two_prob(:,a,g,gd,:)),5),'k.','MarkerSize',20) 102 | 103 | % then just one part of it 104 | subplot(1,3,3) 105 | set(gca,'FontSize',12) 106 | h = bar([mean(one_prob(:,a,g,gd,:),5)'; mean(two_prob(:,a,g,gd,:),5)']'); 107 | set(h(1),'FaceColor',[.25 .25 .25]); 108 | set(h(2),'FaceColor',[.75 .75 .75]); 109 | axis([.5 2.5 0 1]) 110 | set(gca,'XTickLabel',{'bilingual','monolingual'}) 111 | ylabel('relative probability') 112 | title(['Model 3: \alpha = ' num2str(alphas(a)) ', \gamma_B = ' ... 113 | num2str(gammas(g)) ', \gamma_M = ' num2str(gammas(gd))]) 114 | legend(h,'one rule','two rules') 115 | set(gca,'Box','off') 116 | -------------------------------------------------------------------------------- /experiments/marcus2007.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 2 2 | % Marcus, Johnson, & Fernandes (2007) simulations 3 | 4 | clear all 5 | addpath('..') 6 | 7 | % parameters 8 | params.expt = 'marcus1999'; 9 | params.lang = 'ABB'; 10 | params.n_subs = 100; 11 | 12 | % initialization 13 | name = ['../mats/' params.expt '.mat']; 14 | [hs train correct incorrect] = setupWorld(params); 15 | load(name); 16 | index_cache = cacheItems(train,correct,incorrect,hs); 17 | 18 | alphas = 0:.1:1; 19 | p_success = nan([length(alphas)-1 length(alphas)-1 4 params.n_subs]); 20 | 21 | for a1 = 2:length(alphas) 22 | % inference with noisy subjects 23 | for a2 = 1:a1-1 % a2 is always less than a1 24 | disp(['*** a1 = ' num2str(alphas(a1)) ' a2 = ' num2str(alphas(a2)) ' ***']) 25 | tic 26 | 27 | for i = 1:params.n_subs 28 | % normal marcus 1999 29 | params.alpha = alphas(a1); 30 | ps = computeNoisyPosterior(hs,train,params,index_cache); 31 | resps = computeTest(hs,ps,correct,incorrect,params,index_cache); 32 | resps = resps - logsumexp(resps'); 33 | p_success(a1-1,a2,1,i) = exp(resps(1)) / sum(exp(resps)); 34 | surprisal(a1-1,a2,1,i) = diff(-resps); 35 | 36 | % a1 for training, a2 for test 37 | params.alpha = alphas(a1); 38 | ps = computeNoisyPosterior(hs,train,params,index_cache); 39 | params.alpha = alphas(a2); 40 | resps = computeTest(hs,ps,correct,incorrect,params,index_cache); 41 | resps = resps - logsumexp(resps'); 42 | p_success(a1-1,a2,2,i) = exp(resps(1)) / sum(exp(resps)); 43 | surprisal(a1-1,a2,2,i) = diff(-resps); 44 | 45 | % a2 for training and test 46 | params.alpha = alphas(a2); 47 | ps = computeNoisyPosterior(hs,train,params,index_cache); 48 | resps = computeTest(hs,ps,correct,incorrect,params,index_cache); 49 | resps = resps - logsumexp(resps'); 50 | p_success(a1-1,a2,3,i) = exp(resps(1)) / sum(exp(resps)); 51 | surprisal(a1-1,a2,3,i) = diff(-resps); 52 | end 53 | 54 | toc 55 | end 56 | end 57 | 58 | save ../mats/marcus2007.mat p_success surprisal 59 | 60 | %% composite figure 61 | load ../mats/marcus2007.mat 62 | mps = mean(surprisal,4); 63 | mpe = stderr(surprisal,4); 64 | 65 | sns_diff = mps(:,:,2) - mps(:,:,3); 66 | sns_diff(sns_diff == 0) = NaN; 67 | 68 | close all 69 | figure(1) 70 | clf 71 | set(gcf,'Position',[440 358 1000 350]) 72 | % set(gcf,'Color','none') 73 | 74 | subplot(1,4,1:2) 75 | set(gca,'FontSize',12) 76 | plot(sns_diff,'ko--'); 77 | xlabel('\alpha_S') 78 | ylabel('difference in surprisal (bits)') 79 | title('Model 2: \alpha_S and \alpha_{NS} varied') 80 | set(gca,'XTickLabel',alphas(1:2:end)) 81 | axis([0 11 0 20]) 82 | set(gca,'Box','off') 83 | 84 | for i = [1 2 3 4 5 6 7 8] 85 | text(10.3,sns_diff(10,i),num2str(alphas(i),'%2.1f')); 86 | end 87 | 88 | hold on 89 | plot(9,sns_diff(9,3),'ok','MarkerFaceColor',[0 0 0]); 90 | 91 | 92 | subplot(1,4,3) 93 | set(gca,'FontSize',12) 94 | bar(squeeze(mps(9,3,:)),'FaceColor',[.5 .5 .5]) 95 | axis([0 4 0 25]) 96 | ylabel('difference in surprisal (bits)') 97 | title('Model 2: \alpha_S = .9, \alpha_{NS} = .2') 98 | set(gca,'Box','off') 99 | set(gca,'XTickLabel',{'S-S','S-NS','NS-NS'}) 100 | rotateticklabel(gca,90); 101 | 102 | subplot(1,4,4) 103 | set(gca,'FontSize',12) 104 | data = [2.1 1.6 .2]; 105 | bar(data,'FaceColor',[.5 .5 .5]) 106 | title('Experimental data') 107 | ylabel('difference in looking times (s)') 108 | set(gca,'Box','off') 109 | set(gca,'XTickLabel',{'S-S','S-NS','NS-NS'}) 110 | rotateticklabel(gca,90); 111 | 112 | 113 | % rotate_xlabel(90,{'S-S','S-NS','NS-NS'}) 114 | 115 | 116 | %% basic figure 117 | 118 | load ../mats/marcus2007.mat 119 | mps = mean(surprisal,4); 120 | mpe = stderr(surprisal,4); 121 | 122 | % t-tests to mark frames 123 | n = 9; 124 | for i = 1:n 125 | for j = 1:n 126 | for k = 1:2 127 | t(i,j,k) = ttest2(surprisal(i,j,k,:),surprisal(i,j,k+1,:)); 128 | end 129 | end 130 | end 131 | 132 | % now make the composite plot 133 | n = 9; 134 | figure(1) 135 | clf 136 | for i = 1:n 137 | for j = 1:n 138 | subplot(n,n,((i-1)*n)+j) 139 | set(gca,'FontSize',8) 140 | data = squeeze(mps(i,j,:)); 141 | err = squeeze(mpe(i,j,:)); 142 | 143 | if ~any(isnan((data))) && any(data>0) 144 | hold on 145 | bar(data,'FaceColor',[.5 .5 .5]); 146 | axis([.25 3.75 0 max(data)*1.3]) 147 | set(gca,'XTick',[],'YTick',[]) 148 | 149 | if t(i,j,2) 150 | text(1.9,(max(data)*1.1),'*','FontSize',12) 151 | end 152 | 153 | if j == 1 154 | text(-5,(max(data)*1.3)/2,['\alpha_S = ' num2str(alphas(i)+.1)]); 155 | end 156 | 157 | if i == n 158 | text(0,-(max(data)*1.7)/2,['\alpha_{NS} = ' num2str(alphas(j))]); 159 | end 160 | 161 | else 162 | axis off 163 | end 164 | end 165 | end 166 | 167 | %% make inset figure (which we use illustrator to paste in) 168 | 169 | -------------------------------------------------------------------------------- /experiments/saffran2007.m: -------------------------------------------------------------------------------- 1 | % RULES MODEL 2 2 | % Saffran et al. (2007) simulations 3 | 4 | clear all 5 | addpath('../helper') 6 | 7 | % parameters 8 | params.expt = 'marcus1999'; 9 | params.lang = 'ABB'; 10 | params.n_subs = 50; 11 | 12 | alphas = .05:.05:.95; 13 | 14 | % initialization 15 | name = ['../mats/' params.expt '.mat']; 16 | [hs train correct incorrect] = setupWorld(params); 17 | load(name); 18 | 19 | %% 20 | % inference with noisy subjects 21 | for a = 1:length(alphas) 22 | tic 23 | params.alpha = alphas(a); 24 | index_cache = cacheItems(train,correct,incorrect,hs); 25 | 26 | 27 | for i = 1:params.n_subs 28 | ps = computeNoisyPosterior(hs,train,params,index_cache); 29 | resps = computeTest(hs,ps,correct,incorrect,params,index_cache); 30 | resps = resps - logsumexp(resps'); 31 | 32 | % luce choice rule 33 | p_success(a,i) = exp(resps(1)) / sum(exp(resps)); 34 | 35 | % surprisal 36 | surprisal(a,i) = diff(-resps); 37 | end 38 | 39 | toc 40 | end 41 | 42 | save ../mats/saffran2007.mat p_success surprisal 43 | 44 | %% plot 45 | load ../mats/saffran2007.mat 46 | 47 | figure(1) 48 | clf 49 | set(gca,'FontSize',12) 50 | xs = repmat(alphas',1,params.n_subs); 51 | plot(xs+rand(size(xs))*.01,surprisal,'ko','MarkerSize',4) 52 | b = regress(reshape(surprisal,[numel(surprisal) 1]),... 53 | [ones(size(reshape(surprisal,[numel(surprisal) 1]))) reshape(xs,[numel(surprisal) 1])]); 54 | line([min(xs) max(xs)],[b(1) + min(xs)*b(2) b(1) + max(xs)*b(2)],'Color',[0 0 0]) 55 | xlabel('\alpha (noise parameter) value') 56 | ylabel('difference in surprisal (bits)') 57 | 58 | [r p] = corr(reshape(xs,[numel(xs) 1]),reshape(surprisal,[numel(xs) 1])); 59 | set(gca,'FontSize',12); 60 | set(gca,'Box','off') -------------------------------------------------------------------------------- /helper/addNoiseToTraining.m: -------------------------------------------------------------------------------- 1 | % noise up the training data 2 | % flip an alpha-weighted coin and change on symbol of the sentence if it 3 | % comes up 1-alpha. 4 | 5 | function [train index_cache] = addNoiseToTraining(hs,train,params,index_cache) 6 | 7 | for i = 1:length(train) 8 | if rand > params.alpha 9 | ind = Randi(length(hs.all_strings)); 10 | train{i} = hs.all_strings{ind}; 11 | index_cache.train(i) = ind; 12 | %find(cellfun(@(x) all(train{i} == x),hs.all_strings)); 13 | end 14 | end -------------------------------------------------------------------------------- /helper/applyRuleToString.m: -------------------------------------------------------------------------------- 1 | % tests whether a rule is true of a string. gets used when caching 2 | % cardinalities. 3 | 4 | function tf = applyRuleToString(r,s) 5 | 6 | tf = [0 0 0]; 7 | 8 | for i = 1:3 9 | c = ((i-1)*2)+1; 10 | 11 | switch r{c} 12 | case 'na' 13 | tfs(i) = 1; 14 | case 'isa' 15 | tfs(i) = r{c+1} == s(i); 16 | case '=' 17 | tfs(i) = s(r{c+1}) == s(i); 18 | case '>' 19 | tfs(i) = s(r{c+1}) < s(i); 20 | case '<' 21 | tfs(i) = s(r{c+1}) > s(i); 22 | end 23 | end 24 | 25 | tf = sum(tfs)==3; -------------------------------------------------------------------------------- /helper/cacheCardinalities.m: -------------------------------------------------------------------------------- 1 | % cache the cardinality (size) of each rule, so that you can look up the 2 | % likelihood rather than having to compute it on the fly. this is the 3 | % fundamental caching step that makes the models quick to compute. we only 4 | % do this once for each model and then save it as a .MAT file for future 5 | % access. 6 | 7 | function hs = cacheCardinalities(hs) 8 | 9 | disp('caching cardinalities for a new experiment.') 10 | disp('warning: if you are running this for an experiment with a large vocabulary,') 11 | disp('e.g. Gomez (2002), this could take a *very* long time (on the order of several days)'); 12 | disp('') 13 | 14 | % get all strings in train vocab 15 | c = 1; 16 | for i = hs.train_vocab 17 | for j = hs.train_vocab 18 | for k = hs.train_vocab 19 | all_strings{c} = [i j k]; 20 | c = c + 1; 21 | end 22 | end 23 | end 24 | 25 | % now for each rule, apply it to each string 26 | tic 27 | disp('testing each rule against each string') 28 | for i = 1:length(hs.hs) 29 | fprintf('%d ',i); 30 | if mod(i,20)==0, fprintf('\n'); end; 31 | 32 | for j = 1:length(all_strings) 33 | true_of(i,j) = applyRuleToString(hs.hs{i},all_strings{j}); 34 | end 35 | end 36 | toc 37 | 38 | % now consolidate logically consistent hypotheses 39 | % do all pairwise comparisons 40 | tic 41 | disp('removing logically consistent hypotheses') 42 | disp('this part can take as long as or longer than testing each rule against each string') 43 | i = 1; 44 | while i < size(true_of,1) 45 | fprintf('%d ',i); 46 | if mod(i,20)==0, fprintf('\n'); end; 47 | 48 | j = i + 1; 49 | while j < size(true_of,1) 50 | if all(true_of(i,:) == true_of(j,:)) 51 | true_of(j,:) = []; 52 | hs.hs(j) = []; 53 | % disp('deleted'); 54 | else 55 | j = j + 1; 56 | end 57 | end 58 | i = i + 1; 59 | end 60 | toc 61 | 62 | hs.all_strings = all_strings; 63 | hs.true_of = sparse(true_of); % store this as a sparse matrix, takes up less space 64 | hs.cardinalities = sum(true_of,2); 65 | hs.probs = 1./hs.cardinalities; 66 | hs.probs(isinf(hs.probs)) = 0; 67 | hs.log_probs = log(hs.probs); 68 | end 69 | -------------------------------------------------------------------------------- /helper/cacheItems.m: -------------------------------------------------------------------------------- 1 | % caches the indices for the training and test items in the hypothesis 2 | % space. useful for speeding up sums over likelihoods. 3 | 4 | function ic = cacheItems(ts,cs,is,hs) 5 | 6 | % consolidate all the strings if train and test are different 7 | if length(hs.test_vocab) == length(hs.train_vocab) && ... 8 | hs.train_vocab(1) == hs.test_vocab(1) 9 | all_strings = hs.all_strings; 10 | true_of = hs.true_of; 11 | else 12 | all_strings = [hs.all_strings hs.all_test_strings]; 13 | true_of = [hs.true_of hs.true_of_test]; 14 | end 15 | 16 | items = [cs is]; 17 | for i = 1:length(ts) 18 | % ic.train(i) = find(cellfun(@(x) all(ts{i} == x),all_strings)); 19 | ic.train(i) = findString(ts{i},all_strings); 20 | end 21 | 22 | for i = 1:length(items) 23 | % ic.items(i) = find(cellfun(@(x) all(items{i} == x),all_strings),1); 24 | ic.items(i) = findString(items{i},all_strings); 25 | end 26 | 27 | end 28 | 29 | % for some reason this method is empirically faster than the cellfuns 30 | % above, perhaps the error checking in cellfun? 31 | function i = findString(s,as) 32 | 33 | for i = 1:length(as) 34 | if s(1) == as{i}(1) && s(2)==as{i}(2) && s(3)==as{i}(3) 35 | return; 36 | end 37 | end 38 | end -------------------------------------------------------------------------------- /helper/cacheTest.m: -------------------------------------------------------------------------------- 1 | % cache whether each rule applies to each test string. (same as 2 | % cacheCardinalities, more or less). 3 | 4 | function hs = cacheTest(hs) 5 | 6 | % done if train and test are the same 7 | if length(hs.test_vocab) == length(hs.train_vocab) && ... 8 | all(hs.test_vocab == hs.train_vocab) 9 | hs.true_of_test = hs.true_of; 10 | hs.all_test_strings = hs.all_strings; 11 | return; 12 | end 13 | 14 | % get all strings in test vocab 15 | c = 1; 16 | for i = hs.test_vocab 17 | for j = hs.test_vocab 18 | for k = hs.test_vocab 19 | hs.all_test_strings{c} = [i j k]; 20 | c = c + 1; 21 | end 22 | end 23 | end 24 | 25 | % now for each rule, apply it to each string 26 | tic 27 | for i = 1:length(hs.hs) 28 | for j = 1:length(hs.all_test_strings) 29 | hs.true_of_test(i,j) = applyRuleToString(hs.hs{i},hs.all_test_strings{j}); 30 | end 31 | end 32 | toc 33 | end 34 | -------------------------------------------------------------------------------- /helper/chooseClass.m: -------------------------------------------------------------------------------- 1 | % choose a class randomly proportional to marginal probability 2 | 3 | function nc = chooseClass(new_scores) 4 | 5 | c = 1:length(new_scores); 6 | new_scores = new_scores - max(new_scores); % add constant to make calculation of ratios possible 7 | ps = exp(new_scores); % calculate relative probabilities 8 | ps = ps / sum(ps); % normalize to 1 9 | cumPs = cumsum(ps); 10 | nc = c(find(rand params.alpha 18 | train{i} = hs.all_strings{randi(length(hs.all_strings))}; 19 | index_cache.train(i) = find(cellfun(@(x) all(train{i} == x),hs.all_strings)); 20 | end 21 | 22 | for r = 1:N_r 23 | if hs.true_of(r,index_cache.train(i)) 24 | ll(r,i) = logsumexp([log_alpha + hs.log_probs(r); ... 25 | log_notalpha + log(hs.cardinalities(r)/N_s) + hs.log_probs(r)]); 26 | else 27 | % ll(r,i) = log_notalpha + log(1 / (N_s - hs.cardinalities(r))); 28 | ll(r,i) = log_notalpha + log(1 / N_s); 29 | end 30 | end 31 | end 32 | 33 | p = sum(ll,2) + log(1/N_r); 34 | 35 | % normalize rule posterior 36 | p = p - logsumexp(p); 37 | end 38 | -------------------------------------------------------------------------------- /helper/computeNoisyPosteriorGerken2010.m: -------------------------------------------------------------------------------- 1 | % gets posterior for model 2 2 | % useful for simulations 3 | 4 | % this is a hack for the Gerken 2010 +5 conditions where some sentences are 5 | % not heard as many times as others; alpha2 is the higher noise parameter 6 | % for the strings that are only heard once. 7 | 8 | % corrected via Florent Meyniel 2/18/14 9 | 10 | function [p ll] = computeNoisyPosteriorGerken2010(hs,train,params,index_cache,alpha2) 11 | 12 | N_s = length(hs.all_strings); 13 | N_r = length(hs.hs); 14 | log_alpha = log(params.alpha); 15 | log_notalpha = log(1-params.alpha); 16 | 17 | % now compute the posterior on these data 18 | for i = 1:length(train) 19 | % assign alpha depending on what condition/sentence it is 20 | switch params.lang 21 | case 'col' 22 | effective_alpha = params.alpha; 23 | case 'col+5' 24 | if i > 4 25 | effective_alpha = alpha2; 26 | else 27 | effective_alpha = params.alpha; 28 | end 29 | case 'music+5' 30 | effective_alpha = alpha2; 31 | end 32 | 33 | % first noise up the training data 34 | % flip an alpha-weighted coin and change on symbol of the sentence if it 35 | % comes up 1-alpha. 36 | if rand > effective_alpha 37 | train{i} = hs.all_strings{Randi(length(hs.all_strings))}; 38 | index_cache.train(i) = find(cellfun(@(x) all(train{i} == x),hs.all_strings)); 39 | end 40 | 41 | for r = 1:N_r 42 | if hs.true_of(r,index_cache.train(i)) 43 | ll(r,i) = logsumexp([log_alpha + hs.log_probs(r); ... 44 | log_notalpha + log(hs.cardinalities(r)/N_s) + hs.log_probs(r)]); 45 | else 46 | ll(r,i) = log_notalpha + log(1 / (N_s)); 47 | end 48 | end 49 | end 50 | 51 | p = sum(ll,2) + log(1/N_r); 52 | 53 | % normalize rule posterior 54 | p = p - logsumexp(p); 55 | end 56 | -------------------------------------------------------------------------------- /helper/computeNoisyPosteriorMultimodal.m: -------------------------------------------------------------------------------- 1 | % gets posterior for model 2 2 | % useful for simulations 3 | 4 | % this is a hack for the Frank 2009 multimodal condition 5 | 6 | % corrected via Florent Meyniel 2/18/14 7 | 8 | function [p ll] = computeNoisyPosteriorMultimodal(hs,train,params,index_cache,cond) 9 | 10 | if strcmp(cond,'multi') % multimodal 11 | N_s = length(hs.all_strings)^2; 12 | else % unimodal 13 | N_s = length(hs.all_strings); 14 | end 15 | 16 | N_r = length(hs.hs); 17 | log_alpha = log(params.alpha); 18 | log_notalpha = log(1-params.alpha); 19 | 20 | % now compute the posterior on these data 21 | for i = 1:length(train) 22 | % first noise up the training data 23 | % flip an alpha-weighted coin and change on symbol of the sentence if it 24 | % comes up 1-alpha. 25 | if rand > params.alpha 26 | train{i} = hs.all_strings{Randi(length(hs.all_strings))}; 27 | index_cache.train(i) = find(cellfun(@(x) all(train{i} == x),hs.all_strings)); 28 | end 29 | 30 | for r = 1:N_r 31 | if hs.true_of(r,index_cache.train(i)) 32 | ll(r,i) = logsumexp([log_alpha + hs.log_probs(r); ... 33 | log_notalpha + log(hs.cardinalities(r)/N_s) + hs.log_probs(r)]); 34 | else 35 | ll(r,i) = log_notalpha + log(1 / (N_s)); 36 | end 37 | end 38 | end 39 | 40 | p = sum(ll,2) + log(1/N_r); 41 | 42 | % normalize rule posterior 43 | p = p - logsumexp(p); 44 | end 45 | -------------------------------------------------------------------------------- /helper/computeNoisyTest.m: -------------------------------------------------------------------------------- 1 | % calculate correct and incorrect probability with noise 2 | % probability of some string is 3 | % sum over rule of p(string | rule) p(rule) 4 | 5 | function resps = computeNoisyTest(hs,p_rule,correct,incorrect,params,index_cache) 6 | 7 | % consolidate all the strings if train and test are different 8 | if length(hs.test_vocab) == length(hs.train_vocab) && ... 9 | hs.train_vocab(1) == hs.test_vocab(1) 10 | all_strings = hs.all_strings; 11 | true_of = hs.true_of; 12 | else 13 | all_strings = [hs.all_strings hs.all_test_strings]; 14 | true_of = [hs.true_of hs.true_of_test]; 15 | end 16 | 17 | % some values for the likelihood 18 | N_r = length(hs.hs); 19 | N_s = length(all_strings); 20 | log_alpha = log(params.alpha); 21 | log_notalpha = log(1 - params.alpha); 22 | 23 | items = [correct incorrect]; % consolidate items for ease 24 | 25 | % sum over all rules 26 | item_p = nan(N_r,length(items)); 27 | 28 | for i = 1:length(items) 29 | % noise up item according to alpha 30 | if rand > params.alpha 31 | items{i} = all_strings{Randi(length(all_strings))}; 32 | index_cache.items(i) = find(cellfun(@(x) all(items{i} == x),all_strings)); 33 | end 34 | 35 | % then relative probability over rules 36 | for r = 1:N_r 37 | if true_of(r,index_cache.items(i)) 38 | p_string_given_rule = logsumexp([log_alpha + hs.log_probs(r); ... 39 | log_notalpha + log(hs.cardinalities(r)/N_s)]); 40 | else 41 | p_string_given_rule = log_notalpha + log(1 / (N_s - hs.cardinalities(r))); 42 | end 43 | 44 | item_p(r,i) = p_string_given_rule + p_rule(r); 45 | end 46 | end 47 | 48 | % resplit items 49 | resps = [logsumexp(sum(item_p(:,1:length(correct)),2)) ... 50 | logsumexp(sum(item_p(:,length(incorrect)+1:end),2))]; 51 | -------------------------------------------------------------------------------- /helper/computePosteriorFromTrainingData.m: -------------------------------------------------------------------------------- 1 | % computes posterior probabilities over rules given training data for 2 | % model 1 3 | 4 | function ps = computePosteriorFromTrainingData(hs,train) 5 | 6 | for i = 1:length(hs.hs) 7 | for j = 1:length(train) 8 | if applyRuleToString(hs.hs{i},train{j}) 9 | ll(i,j) = hs.log_probs(i); 10 | else 11 | ll(i,j) = -Inf; 12 | end 13 | end 14 | 15 | ps(i) = sum(ll(i,:)) + log(1/length(hs.hs)); 16 | end 17 | -------------------------------------------------------------------------------- /helper/computeTest.m: -------------------------------------------------------------------------------- 1 | %% calculate correct and incorrect probability with noise 2 | % probability of some string is 3 | % sum over rule of p(string | rule) p(rule) 4 | 5 | function resps = computeTest(hs,p_rule,correct,incorrect,params,index_cache) 6 | 7 | % consolidate all the strings if train and test are different 8 | if length(hs.test_vocab) == length(hs.train_vocab) && ... 9 | hs.train_vocab(1) == hs.test_vocab(1) 10 | all_strings = hs.all_strings; 11 | true_of = hs.true_of; 12 | else 13 | all_strings = [hs.all_strings hs.all_test_strings]; 14 | true_of = [hs.true_of hs.true_of_test]; 15 | end 16 | 17 | % some values for the likelihood 18 | N_r = length(hs.hs); 19 | N_s = length(all_strings); 20 | log_alpha = log(params.alpha); 21 | log_notalpha = log(1 - params.alpha); 22 | 23 | items = [correct incorrect]; % consolidate items for ease 24 | 25 | % sum over all rules 26 | item_p = nan(N_r,length(items)); 27 | 28 | for i = 1:length(items) 29 | % then relative probability over rules 30 | for r = 1:N_r 31 | if true_of(r,index_cache.items(i)) 32 | p_string_given_rule = logsumexp([log_alpha + hs.log_probs(r); ... 33 | log_notalpha + log(hs.cardinalities(r)/N_s)]); 34 | else 35 | p_string_given_rule = log_notalpha + log(1 / (N_s)); 36 | end 37 | 38 | item_p(r,i) = p_string_given_rule + p_rule(r); 39 | end 40 | end 41 | 42 | % resplit items 43 | resps = [logsumexp(sum(item_p(:,1:length(correct)),2)) ... 44 | logsumexp(sum(item_p(:,length(incorrect)+1:end),2))]; 45 | -------------------------------------------------------------------------------- /helper/computeTestMultimodal.m: -------------------------------------------------------------------------------- 1 | %% calculate correct and incorrect probability with noise 2 | % probability of some string is 3 | % sum over rule of p(string | rule) p(rule) 4 | 5 | function resps = computeTestMultimodal(hs,p_rule,correct,incorrect,params,index_cache,cond) 6 | 7 | % consolidate all the strings if train and test are different 8 | if length(hs.test_vocab) == length(hs.train_vocab) && ... 9 | hs.train_vocab(1) == hs.test_vocab(1) 10 | all_strings = hs.all_strings; 11 | true_of = hs.true_of; 12 | else 13 | all_strings = [hs.all_strings hs.all_test_strings]; 14 | true_of = [hs.true_of hs.true_of_test]; 15 | end 16 | 17 | % some values for the likelihood 18 | N_r = length(hs.hs); 19 | 20 | if strcmp(cond,'multi') % multimodal 21 | N_s = length(hs.all_strings)^2; 22 | else % unimodal 23 | N_s = length(hs.all_strings); 24 | end 25 | log_alpha = log(params.alpha); 26 | log_notalpha = log(1 - params.alpha); 27 | 28 | items = [correct incorrect]; % consolidate items for ease 29 | 30 | % sum over all rules 31 | item_p = nan(N_r,length(items)); 32 | 33 | for i = 1:length(items) 34 | % then relative probability over rules 35 | for r = 1:N_r 36 | % we don't use the noisy model for these simulations 37 | % clean version 38 | if true_of(r,index_cache.items(i)) 39 | p_string_given_rule = hs.log_probs(r); 40 | else 41 | p_string_given_rule = -Inf; 42 | end 43 | 44 | item_p(r,i) = p_string_given_rule + p_rule(r); 45 | end 46 | end 47 | 48 | % resplit items 49 | resps = [logsumexp(sum(item_p(:,1:length(correct)),2)) ... 50 | logsumexp(sum(item_p(:,length(incorrect)+1:end),2))]; 51 | -------------------------------------------------------------------------------- /helper/createHypothesisSpace.m: -------------------------------------------------------------------------------- 1 | % creates the hypothesis space for a language 2 | % time-consuming, so hopefully only do this once. 3 | 4 | function hs = createHypothesisSpace(hs) 5 | 6 | % for each place find out what the primitives are 7 | for i = 1:3 8 | ps{i} = createPrimitiveSet(hs,i); 9 | end 10 | 11 | % now iterate through and create the whole setup 12 | % this could be a recursive function but it's easier to read for the 13 | % finite case when it's written out. 14 | for i = 1:length(ps{3}) 15 | h3{i} = ps{3}{i}; 16 | end 17 | 18 | c = 1; 19 | for i = 1:length(ps{2}) 20 | for j = 1:length(ps{3}) 21 | h2{c} = [ps{2}{i} ps{3}{j}]; 22 | c = c + 1; 23 | end 24 | end 25 | 26 | c = 1; 27 | for i = 1:length(ps{1}) 28 | for j = 1:length(ps{2}) 29 | for k = 1:length(ps{3}) 30 | hs.hs{c} = [ps{1}{i} ps{2}{j} ps{3}{k}]; 31 | c = c + 1; 32 | end 33 | end 34 | end 35 | end 36 | 37 | % sub function to create the set of possible primitives for each slot in the 38 | % rule 39 | function p = createPrimitiveSet(hs,pos) 40 | p = {{'na',0}}; % always have the null element 41 | 42 | for i = 1:length(hs.train_vocab) 43 | p = [p {{'isa',hs.train_vocab(i)}}]; 44 | end 45 | 46 | for j = 3:length(hs.F) 47 | inds = 1:3; 48 | others = inds(inds~=pos); 49 | for k = others % 1:pos-1 for only sequentially later 50 | p = [p {{hs.F{j},k}}]; 51 | end 52 | end 53 | 54 | end 55 | 56 | -------------------------------------------------------------------------------- /helper/crp.m: -------------------------------------------------------------------------------- 1 | % function l = crp(ns, gamma) 2 | % probability of the partition in ns under a CRP with concentration parameter 3 | % gamma (note that gamma here is NOT the gamma function but just a number) 4 | % 5 | % Provided by Charles Kamp 2006 6 | 7 | function l = crp(ns, gamma) 8 | 9 | ns=ns(ns~=0); % only consider classes that are not empty 10 | k = length(ns); % number of classes 11 | n = sum(ns); % number of samples 12 | l = sum(gammaln(ns))+k*log(gamma)+gammaln(gamma)-gammaln(n+gamma); 13 | -------------------------------------------------------------------------------- /helper/displayOutputs.m: -------------------------------------------------------------------------------- 1 | % display model 3 outputs in a pretty format 2 | 3 | % find the maximum likelihood hypothesis for each cluster (because this 4 | % helps you interpret what a cluster means) 5 | [ll mlhs] = findMLHypotheses(c,train,hs,params,index_cache); 6 | pr = computeCRP(c,params); 7 | 8 | for i = 1:length(mlhs) 9 | fprintf('rule %d: %s %d %s %d %s %d\n',i,mlhs{i}{1},mlhs{i}{2},mlhs{i}{3},... 10 | mlhs{i}{4},mlhs{i}{5},mlhs{i}{6}) 11 | end 12 | 13 | disp(['likelihood = ' num2str(ll,'%2.0f') ' / prior = ' num2str(pr,'%2.0f') ... 14 | ' / score = ' num2str(ll+pr,'%2.0f')]); 15 | 16 | fprintf('\n'); 17 | -------------------------------------------------------------------------------- /helper/ent.m: -------------------------------------------------------------------------------- 1 | function h = ent(dist) 2 | % add a small smoothing factor epsilon 3 | dist = (dist + eps) ./ nansum(nansum(dist+eps)); 4 | l_dist = log2(dist); 5 | h = -nansum(nansum(dist .* l_dist)); 6 | -------------------------------------------------------------------------------- /helper/findMLHypotheses.m: -------------------------------------------------------------------------------- 1 | function [ll h] = findMLHypotheses(c,train,hs,params,index_cache) 2 | 3 | N_s = length(hs.all_strings); 4 | N_r = length(hs.hs); 5 | log_alpha = log(params.alpha); 6 | log_notalpha = log(1-params.alpha); 7 | 8 | % now compute the likelihood of these data 9 | for k = 1:max(c) 10 | this_train = train(c==k); 11 | cache_inds = find(c==k); 12 | 13 | noise_vals = log_notalpha + log(1 ./ (N_s - hs.cardinalities)); 14 | lls{k} = repmat(noise_vals,[1 sum(c==k)]); 15 | 16 | % now compute the posterior on these data 17 | for i = 1:length(this_train) 18 | poss_rules = find(hs.true_of(:,index_cache.train(cache_inds(i)))); 19 | for r = 1:length(poss_rules); 20 | lls{k}(poss_rules(r),i) = logsumexp([log_alpha + hs.log_probs(poss_rules(r)); ... 21 | log_notalpha + log(hs.cardinalities(poss_rules(r))/N_s) + hs.log_probs(poss_rules(r))]); 22 | end 23 | end 24 | 25 | p = sum(lls{k},2) + log(1/N_r); 26 | non_0_ps = p(~isinf(p)); 27 | ll = logsumexp(non_0_ps); 28 | 29 | h{k} = hs.hs{p==max(p)}; 30 | end 31 | end -------------------------------------------------------------------------------- /helper/logsumexp.m: -------------------------------------------------------------------------------- 1 | function s = logsumexp(a, dim) 2 | % Returns log(sum(exp(a),dim)) while avoiding numerical underflow. 3 | % Default is dim = 1 (columns). 4 | % logsumexp(a, 2) will sum across rows instead of columns. 5 | % Unlike matlab's "sum", it will not switch the summing direction 6 | % if you provide a row vector. 7 | 8 | % Written by Tom Minka 9 | 10 | if nargin < 2 11 | dim = 1; 12 | end 13 | 14 | % subtract the largest in each column 15 | [y, i] = max(a,[],dim); 16 | dims = ones(1,ndims(a)); 17 | dims(dim) = size(a,dim); 18 | a = a - repmat(y, dims); 19 | s = y + log(sum(exp(a),dim)); 20 | i = find(~isfinite(y)); 21 | if ~isempty(i) 22 | s(i) = y(i); 23 | end 24 | -------------------------------------------------------------------------------- /helper/rotateticklabel.m: -------------------------------------------------------------------------------- 1 | function th=rotateticklabel(h,rot,demo) 2 | %ROTATETICKLABEL rotates tick labels 3 | % TH=ROTATETICKLABEL(H,ROT) is the calling form where H is a handle to 4 | % the axis that contains the XTickLabels that are to be rotated. ROT is 5 | % an optional parameter that specifies the angle of rotation. The default 6 | % angle is 90. TH is a handle to the text objects created. For long 7 | % strings such as those produced by datetick, you may have to adjust the 8 | % position of the axes so the labels don't get cut off. 9 | % 10 | % Of course, GCA can be substituted for H if desired. 11 | % 12 | % TH=ROTATETICKLABEL([],[],'demo') shows a demo figure. 13 | % 14 | % Known deficiencies: if tick labels are raised to a power, the power 15 | % will be lost after rotation. 16 | % 17 | % See also datetick. 18 | 19 | % Written Oct 14, 2005 by Andy Bliss 20 | % Copyright 2005 by Andy Bliss 21 | 22 | %DEMO: 23 | if nargin==3 24 | x=[now-.7 now-.3 now]; 25 | y=[20 35 15]; 26 | figure 27 | plot(x,y,'.-') 28 | datetick('x',0,'keepticks') 29 | h=gca; 30 | set(h,'position',[0.13 0.35 0.775 0.55]) 31 | rot=90; 32 | end 33 | 34 | %set the default rotation if user doesn't specify 35 | if nargin==1 36 | rot=90; 37 | end 38 | %make sure the rotation is in the range 0:360 (brute force method) 39 | while rot>360 40 | rot=rot-360; 41 | end 42 | while rot<0 43 | rot=rot+360; 44 | end 45 | %get current tick labels 46 | a=get(h,'XTickLabel'); 47 | %erase current tick labels from figure 48 | set(h,'XTickLabel',[]); 49 | %get tick label positions 50 | b=get(h,'XTick'); 51 | c=get(h,'YTick'); 52 | %make new tick labels 53 | if rot<180 54 | th=text(b,repmat(c(1)-.1*(c(2)-c(1)),length(b),1),a,'HorizontalAlignment','right','rotation',rot); 55 | else 56 | th=text(b,repmat(c(1)-.1*(c(2)-c(1)),length(b),1),a,'HorizontalAlignment','left','rotation',rot); 57 | end 58 | -------------------------------------------------------------------------------- /helper/setupWorld.m: -------------------------------------------------------------------------------- 1 | % this function encodes all the different training and test sets for the 2 | % various experiments fit by models 1, 2, and 3. 3 | 4 | function [hs train correct incorrect] = setupWorld(params) 5 | 6 | switch params.expt 7 | case 'marcus1999' 8 | hs.F = {'na','isa','='}; 9 | hs.train_vocab = 1:8; 10 | hs.test_vocab = 9:12; 11 | 12 | switch params.lang 13 | case 'ABB' 14 | train = {[1 5 5],[1 6 6],[1 7 7],[1 8 8],... 15 | [2 5 5],[2 6 6],[2 7 7],[2 8 8],... 16 | [3 5 5],[3 6 6],[3 7 7],[3 8 8],... 17 | [4 5 5],[4 6 6],[4 7 7],[4 8 8]}; 18 | 19 | correct = {[9 11 11],[9 12 12],[10 11 11],[10 12 12]}; 20 | incorrect = {[9 11 9],[9 12 9],[10 11 10],[10 12 10]}; 21 | 22 | case 'ABA' 23 | train = {[1 5 1],[1 6 1],[1 7 1],[1 8 1],... 24 | [2 5 2],[2 6 2],[2 7 2],[2 8 2],... 25 | [3 5 3],[3 6 3],[3 7 3],[3 8 3],... 26 | [4 5 4],[4 6 4],[4 7 4],[4 8 4]}; 27 | 28 | correct = {[9 11 9],[9 12 9],[10 11 10],[10 12 10]}; 29 | incorrect = {[9 11 11],[9 12 12],[10 11 11],[10 12 12]}; 30 | 31 | otherwise 32 | error('not a valid experiment.') 33 | end 34 | 35 | case 'gerken2006' 36 | hs.F = {'na','isa','='}; 37 | hs.train_vocab = 1:8; 38 | hs.test_vocab = [5 9:12]; 39 | 40 | switch params.lang 41 | case 'AAB' 42 | train = {[1 1 5],[2 2 6],[3 3 7],[4 4 8]}; 43 | 44 | correct = {[9 9 11],[10 10 12]}; 45 | incorrect = {[9 11 9],[9 12 9]}; 46 | 47 | case 'AAx' 48 | train = {[1 1 5],[2 2 5],[3 3 5],[4 4 5]}; 49 | 50 | correct = {[9 9 11],[10 10 12]}; 51 | incorrect = {[9 11 9],[9 12 9]}; 52 | 53 | case 'ABx' 54 | train = {[1 2 5],[2 3 5],[3 4 5],[4 1 5]}; 55 | 56 | correct = {[9 10 5],[10 9 5]}; 57 | incorrect = {[9 10 11],[10 9 11]}; 58 | 59 | case 'AAx2' 60 | train = {[1 1 5],[2 2 5],[3 3 5],[4 4 5]}; 61 | 62 | correct = {[9 9 5],[10 10 5]}; 63 | incorrect = {[9 5 9],[9 5 9]}; 64 | 65 | otherwise 66 | error('not a valid experiment.') 67 | end 68 | 69 | case 'gerken2010' 70 | hs.F = {'na','isa','='}; 71 | hs.train_vocab = 1:8; 72 | hs.test_vocab = [5 9:12]; 73 | 74 | switch params.lang 75 | case 'col' 76 | train = {[1 1 5],[2 2 5],[3 3 5],[4 4 5]}; 77 | 78 | correct = {[9 9 11],[10 10 12]}; 79 | incorrect = {[9 11 9],[9 12 9]}; 80 | 81 | case 'col+5' 82 | train = {[1 1 5],[2 2 5],[3 3 5],[4 4 5],[1 1 6],[1 1 5],[2 2 7],[3 3 8],[4 4 5]}; 83 | 84 | correct = {[9 9 11],[10 10 12]}; 85 | incorrect = {[9 11 9],[9 12 9]}; 86 | 87 | case 'music+5' 88 | train = {[1 1 6],[1 1 5],[2 2 7],[3 3 8],[4 4 5]}; 89 | 90 | correct = {[9 9 11],[10 10 12]}; 91 | incorrect = {[9 11 9],[9 12 9]}; 92 | otherwise 93 | error('not a valid experiment.') 94 | end 95 | 96 | 97 | case 'endress2007' 98 | hs.F = {'na','isa','=','<','>'}; 99 | hs.train_vocab = 1:12; 100 | hs.test_vocab = 1:12; 101 | 102 | switch params.lang 103 | case 'LHM' 104 | train = {[1 12 11],[2 10 9],[3 8 7],[4 6 5]}; 105 | correct = {[9 12 11]}; 106 | incorrect = {[11 12 9]}; 107 | case 'LMH' 108 | train = {[1 11 12],[2 9 10],[3 7 8],[4 5 6]}; 109 | correct = {[9 11 12]}; 110 | incorrect = {[12 11 9]}; 111 | 112 | 113 | case 'ABB' 114 | train = {[1 12 12],[10 2 2],[3 8 8],[6 4 4]}; 115 | correct = {[9 11 11]}; 116 | incorrect = {[9 11 9]}; 117 | otherwise 118 | error('not a valid experiment.') 119 | 120 | end 121 | 122 | case 'frank2009' 123 | hs.F = {'na','isa','='}; 124 | hs.train_vocab = 1:6; 125 | hs.test_vocab = 7:12; 126 | 127 | switch params.lang 128 | case 'uni' 129 | train = {[1 2 2],[3 4 4],[5 6 6]}; 130 | correct = {[7 8 8],[9 10 10],[11 12 12]}; 131 | incorrect = {[7 8 7],[9 10 9],[11 12 11]}; 132 | 133 | case 'multi' 134 | train = {[1 2 2],[3 4 4],[5 6 6]}; 135 | correct = {[7 8 8],[9 10 10],[11 12 12]}; 136 | incorrect = {[7 8 7],[9 10 9],[11 12 11]}; 137 | otherwise 138 | error('not a valid experiment.') 139 | end 140 | 141 | case 'gomez2002' 142 | hs.F = {'na','isa','='}; 143 | hs.train_vocab = 1:28; 144 | hs.test_vocab = 1:28; 145 | 146 | switch params.lang 147 | case '1x' 148 | train = {[1 5 2],[3 5 4]}; 149 | 150 | correct = {[1 5 2],[3 5 4]}; 151 | incorrect = {[1 5 4],[3 5 2]}; 152 | case '2x' 153 | train = {[1 5 2],[3 5 4],[1 6 2],[3 6 4]}; 154 | 155 | correct = {[1 5 2],[3 5 4]}; 156 | incorrect = {[1 5 4],[3 5 2]}; 157 | case '6x' 158 | train = {[1 5 2],[3 5 4],[1 6 2],[3 6 4],... 159 | [1 7 2],[3 7 4],[1 8 2],[3 8 4],... 160 | [1 9 2],[3 9 4],[1 10 2],[3 10 4]}; 161 | 162 | correct = {[1 5 2],[3 5 4]}; 163 | incorrect = {[1 5 4],[3 5 2]}; 164 | case '12x' 165 | train = {[1 5 2],[3 5 4],[1 6 2],[3 6 4],... 166 | [1 7 2],[3 7 4],[1 8 2],[3 8 4],... 167 | [1 9 2],[3 9 4],[1 10 2],[3 10 4],... 168 | [1 11 2],[3 11 4],[1 12 2],[3 12 4],... 169 | [1 13 2],[3 13 4],[1 14 2],[3 14 4],... 170 | [1 15 2],[3 15 4],[1 16 2],[3 16 4]}; 171 | 172 | correct = {[1 5 2],[3 5 4]}; 173 | incorrect = {[1 5 4],[3 5 2]}; 174 | case '24x' 175 | train = {[1 5 2],[3 5 4],[1 6 2],[3 6 4],... 176 | [1 7 2],[3 7 4],[1 8 2],[3 8 4],... 177 | [1 9 2],[3 9 4],[1 10 2],[3 10 4],... 178 | [1 11 2],[3 11 4],[1 12 2],[3 12 4],... 179 | [1 13 2],[3 13 4],[1 14 2],[3 14 4],... 180 | [1 15 2],[3 15 4],[1 16 2],[3 16 4],... 181 | [1 17 2],[3 17 4],[1 18 2],[3 18 4],... 182 | [1 19 2],[3 19 4],[1 20 2],[3 20 4],... 183 | [1 21 2],[3 21 4],[1 22 2],[3 22 4],... 184 | [1 23 2],[3 23 4],[1 24 2],[3 24 4],... 185 | [1 25 2],[3 25 4],[1 26 2],[3 26 4],... 186 | [1 27 2],[3 27 4],[1 28 2],[3 28 4]}; 187 | 188 | correct = {[1 5 2],[3 5 4]}; 189 | incorrect = {[1 5 4],[3 5 2]}; 190 | otherwise 191 | error('not a valid experiment.') 192 | end 193 | 194 | case 'kovacs2009' 195 | % supplementary materials do not give exact details on training corpus 196 | % so this is an approximate reconstruction 197 | 198 | hs.F = {'na','isa','='}; 199 | hs.train_vocab = 1:6; 200 | hs.test_vocab = 1:6; 201 | 202 | train = {[1 1 4],[1 1 5],[2 2 4] [2 2 6],[3 3 5],[3 3 6],... 203 | [1 4 1],[1 5 1],[2 4 2],[2 6 2],[3 5 3],[3 6 3]}; 204 | 205 | % correct and incorrect are not relevant for the looking time paradigm 206 | % used by Kovacs & Mehler 207 | correct = {[1 1 6]}; 208 | incorrect = {[1 6 1]}; 209 | 210 | otherwise 211 | error('not a valid experiment.') 212 | 213 | end 214 | 215 | -------------------------------------------------------------------------------- /helper/stderr.m: -------------------------------------------------------------------------------- 1 | function se = stderr(data,varargin) 2 | 3 | if nargin > 1 4 | dim = varargin{1}; 5 | else 6 | dim = 1; 7 | end 8 | 9 | d = size(data); 10 | new_d = d; 11 | new_d(dim) = 1; 12 | 13 | denom = sqrt(ones(new_d) .* d(dim)); 14 | se = nanstd(data,0,dim) ./ denom; 15 | -------------------------------------------------------------------------------- /helper/writeResults.m: -------------------------------------------------------------------------------- 1 | %% write the results from model 1 in a compact way 2 | 3 | clear cp 4 | clear ip 5 | 6 | inds = find(ps~=-Inf); 7 | h = hs.hs(inds); 8 | p = ps(inds) - logsumexp(ps(inds),2); 9 | 10 | for i= 1:length(h) 11 | fprintf('%d: %s %d %s %d %s %d: %2.2f\n',inds(i),h{i}{1},h{i}{2},h{i}{3},... 12 | h{i}{4},h{i}{5},h{i}{6},p(i)); 13 | end 14 | 15 | fprintf('posterior entropy: %2.4f\n',ent(exp(p))); 16 | 17 | 18 | %% calculate correct and incorrect probability 19 | 20 | for i = 1:length(correct) 21 | for j = 1:length(h) 22 | if applyRuleToString(h{j},correct{i}) 23 | cp(i,j) = p(j) + hs.log_probs(inds(j)); 24 | else 25 | cp(i,j) = -Inf; 26 | end 27 | 28 | if applyRuleToString(h{j},incorrect{i}) 29 | ip(i,j) = p(j) + hs.log_probs(inds(j)); 30 | else 31 | ip(i,j) = -Inf; 32 | end 33 | end 34 | end 35 | 36 | fprintf('correct probability: %2.2f\n',logsumexp(sum(cp,1),2)); 37 | fprintf('correct probability (rev sum): %2.2f\n',sum(logsumexp(cp,2),1)); 38 | fprintf('incorrect probability: %2.2f\n',logsumexp(sum(ip),2)); 39 | fprintf('correct/incorrect (one item): %2.2f %2.2f\n',... 40 | logsumexp(cp(1,:),2),logsumexp(ip(1,:),2)); 41 | -------------------------------------------------------------------------------- /helper/writeResultsE1.m: -------------------------------------------------------------------------------- 1 | %% calculate correct and incorrect probability 2 | true_of_all_inds = find(true_of_all); 3 | 4 | for i = 1:length(correct) 5 | for j = 1:length(true_of_all_inds) 6 | if applyRuleToString(hs.hs{true_of_all_inds(j)},correct{i}) 7 | cp(i,j) = 1; 8 | else 9 | cp(i,j) = 0; 10 | end 11 | 12 | if applyRuleToString(hs.hs{true_of_all_inds(j)},incorrect{i}) 13 | ip(i,j) = 1; 14 | else 15 | ip(i,j) = 0; 16 | end 17 | end 18 | end 19 | 20 | lcp = log(double(all(cp,2))) + log(1/sum(consistent_strings)); 21 | lip = log(double(all(ip,2))) + log(1/sum(consistent_strings)); 22 | 23 | fprintf('correct probability: %2.2f\n',sum(lcp)); 24 | fprintf('incorrect probability: %2.2f\n',sum(lip)); 25 | fprintf('correct/incorrect (one item): %2.2f %2.2f\n',... 26 | lcp(1),lip(1)); 27 | -------------------------------------------------------------------------------- /helper/writeResultsNoisy.m: -------------------------------------------------------------------------------- 1 | % write the results from model 2 in a compact way 2 | 3 | ps = exp(mean(all_ps,1)); % consolidate across subjects 4 | 5 | inds = find(ps>prctile(ps,95)); 6 | p = ps(inds); 7 | [p ix] = sort(p,2,'ascend'); % sort so it's easier to read 8 | inds = inds(ix); 9 | h = hs.hs(inds); 10 | 11 | for i= 1:length(h) 12 | fprintf('%s %d %s %d %s %d: %2.2f\n',h{i}{1},h{i}{2},h{i}{3},... 13 | h{i}{4},h{i}{5},h{i}{6},p(i)); 14 | end 15 | 16 | fprintf('posterior entropy: %2.2f\n',ent(exp(p))); 17 | fprintf('mean surprisal: %2.2f\n',mean(surprisal)); 18 | -------------------------------------------------------------------------------- /mats/endress2007.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/endress2007.mat -------------------------------------------------------------------------------- /mats/frank2009.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/frank2009.mat -------------------------------------------------------------------------------- /mats/gerken2006.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/gerken2006.mat -------------------------------------------------------------------------------- /mats/gerken2006_2010.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/gerken2006_2010.mat -------------------------------------------------------------------------------- /mats/gerken2010.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/gerken2010.mat -------------------------------------------------------------------------------- /mats/gomez2002.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/gomez2002.mat -------------------------------------------------------------------------------- /mats/kovacs2009-sims.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/kovacs2009-sims.mat -------------------------------------------------------------------------------- /mats/kovacs2009.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/kovacs2009.mat -------------------------------------------------------------------------------- /mats/marcus1999.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/marcus1999.mat -------------------------------------------------------------------------------- /mats/marcus2007.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/marcus2007.mat -------------------------------------------------------------------------------- /mats/saffran2007.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcfrank/rules/0c1a3b90c05cddb4bdf9a0f53fd2e07686c969ab/mats/saffran2007.mat -------------------------------------------------------------------------------- /model1.m: -------------------------------------------------------------------------------- 1 | % MODEL 1 2 | % instantiates the simple rules model of Frank & Tenenbaum 3 | % all examples remembered exaxctly, only one rule 4 | % begun 1/4/10 5 | % submitted 4/7/10 6 | % 7 | % possible experiments: 8 | % - marcus1999: ABB, ABA 9 | % - endress2007: ABB, LHM 10 | % - frank2009: uni, multi 11 | % - gerken2006: AAB, AAx, AAx2 12 | % - gerken2010: col, col+5, music+5 13 | % - gomez2002: 2x, 6x, 12x, 24x 14 | % - kovacs2009 (no conditions) 15 | % see manuscript for more details 16 | 17 | clear all 18 | addpath('helper') 19 | 20 | % parameters 21 | params.expt = 'endress2007'; 22 | params.lang = 'LMH'; 23 | 24 | %% initialization 25 | 26 | name = ['mats/' params.expt '.mat']; 27 | [hs train correct incorrect] = setupWorld(params); 28 | 29 | % either generate or load the hypothesis space 30 | if size(dir(name),1)>0 31 | load(name); 32 | else 33 | hs = createHypothesisSpace(hs); 34 | hs = cacheCardinalities(hs); 35 | hs = cacheTest(hs); 36 | save(name,'hs'); 37 | end 38 | 39 | % make a quick exception for the multimodal condition of frank 2009 40 | % (this fix is the same as computing probabilities when the dimensionality 41 | % is squared) 42 | if strcmp(params.lang,'multi') 43 | hs.log_probs = hs.log_probs*2; 44 | hs.cardinalities = hs.cardinalities.^2; 45 | end 46 | 47 | %% exact posterior inference 48 | 49 | ps = computePosteriorFromTrainingData(hs,train); 50 | writeResults -------------------------------------------------------------------------------- /model2.m: -------------------------------------------------------------------------------- 1 | % MODEL 2 2 | % instantiates the simple rules model of Frank & Tenenbaum 3 | % one rule plus memory noise (via alpha parameter) 4 | % begun 1/4/10 5 | % submitted 4/7/10 6 | % 7 | % possible experiments: 8 | % - marcus1999: ABB, ABA 9 | % - endress2007: ABB, LHM 10 | % - frank2009: uni, multi 11 | % - gerken2006: AAB, AAx, AAx2 12 | % - gerken2010: col, col+5, music+5 13 | % - gomez2002: 2x, 6x, 12x, 24x 14 | % - kovacs2009 (no conditions) 15 | % see manuscript for more details 16 | 17 | clear all 18 | addpath('helper') 19 | 20 | % parameters 21 | params.expt = 'gerken2006'; 22 | params.lang = 'ABx'; 23 | 24 | %% initialization 25 | name = ['mats/' params.expt '.mat']; 26 | [hs train correct incorrect] = setupWorld(params); 27 | 28 | % either generate or load the hypothesis space 29 | if size(dir(name),1)>0 30 | load(name); 31 | else 32 | hs = createHypothesisSpace(hs); 33 | hs = cacheCardinalities(hs); 34 | hs = cacheTest(hs); 35 | save(name,'hs'); 36 | end 37 | 38 | % make a quick exception for the multimodal condition of frank 2009 39 | % (this fix is the same as computing probabilities when the dimensionality 40 | % is squared) 41 | if strcmp(params.lang,'multi') 42 | hs.log_probs = hs.log_probs*2; 43 | hs.cardinalities = hs.cardinalities.^2; 44 | end 45 | 46 | %% inference with memory noise 47 | 48 | display('*** Evaluating noisy model ***'); 49 | params.n_subs = 16; % how many independent runs 50 | params.alpha = .7; % noise parameter 51 | 52 | % make cache of corrupted items 53 | index_cache = cacheItems(train,correct,incorrect,hs); 54 | 55 | for i = 1:params.n_subs 56 | all_ps(i,:) = computeNoisyPosterior(hs,train,params,index_cache); 57 | resps(i,:) = computeTest(hs,all_ps(i,:),correct,incorrect,params,index_cache); 58 | resps(i,:) = resps(i,:) - logsumexp(resps(i,:)'); 59 | p_success(i) = exp(resps(i,1)) / sum(exp(resps(i,:))); 60 | surprisal(i) = diff(-resps(i,:)); 61 | end 62 | writeResultsNoisy -------------------------------------------------------------------------------- /model3.m: -------------------------------------------------------------------------------- 1 | % MODEL 3 2 | % instantiates the simple rules model of Frank & Tenenbaum 3 | % multiple rules plus noise 4 | % begun 1/4/10 5 | % submitted 4/7/10 6 | % 7 | % possible experiments: 8 | % - marcus1999: ABB, ABA 9 | % - endress2007: ABB, LHM 10 | % - gerken2006: AAB, AAx, AAx2 11 | % - gerken2010: col, col+5, music+5 12 | % - gomez2002: 2x, 6x, 12x, 24x 13 | % - kovacs2009 (no conditions) 14 | % see manuscript for more details 15 | 16 | clear all 17 | addpath('helper') 18 | 19 | %% parameters 20 | params.expt = 'kovacs2009'; 21 | params.lang = 'ABB'; 22 | params.alpha = .9; % memory noise parameter 23 | params.gamma = .2; % parameter for chinese restaurant process 24 | params.num_iter = 100; % number of gibbs steps 25 | 26 | %% initialization 27 | name = ['mats/' params.expt '.mat']; 28 | [hs train correct incorrect] = setupWorld(params); 29 | 30 | if size(dir(name),1)>0 31 | load(name); 32 | else 33 | hs = createHypothesisSpace(hs); 34 | hs = cacheCardinalities(hs); 35 | hs = cacheTest(hs); 36 | save(name,'hs'); 37 | end 38 | 39 | % create a cache and then modify it for the noise for this particular 40 | % simulation 41 | index_cache = cacheItems(train,correct,incorrect,hs); 42 | [train index_cache] = addNoiseToTraining(hs,train,params,index_cache); 43 | 44 | %% use gibbs sampler to find cluster assignment 45 | 46 | % initialize with every sentence in its own cluster 47 | n = length(train); 48 | c = 1:n; 49 | c3 = zeros(n,params.num_iter); 50 | 51 | % begin gibbs iterations 52 | for i = 1:params.num_iter 53 | fprintf('gibbs step %d',i); 54 | for j = 1:n 55 | fprintf('.'); if mod(j,50)==0, fprintf('\n'); end; 56 | clear ll h2 c2 prior new_scores 57 | 58 | % try the assignment of this string to every cluster (inc. its own) 59 | for k = 1:max(c)+1 60 | c2{k} = c; 61 | c2{k}(j) = k; 62 | ll(k) = computeNoisyLikelihood2(hs,c2{k},train,params,index_cache); 63 | prior(k) = computeCRP(c2{k},params); 64 | new_scores(k) = prior(k) + ll(k); 65 | end 66 | 67 | % now choose class & clean up if classes are empty 68 | % gibbs step: jump proportional to the relative probability 69 | c(j) = chooseClass(new_scores); 70 | c = cleanUpClasses(c); 71 | end 72 | 73 | % now show what happened 74 | c3(:,i)=sort(c); 75 | imagesc(c3); drawnow; fprintf('\n'); 76 | displayOutputs; 77 | end 78 | -------------------------------------------------------------------------------- /modelE1.m: -------------------------------------------------------------------------------- 1 | % MODEL E1 2 | % designed to try and implement the "common-sense" suggestion of Endress 3 | % (2013) 4 | % 5 | % possible experiments: 6 | % - marcus1999: ABB, ABA 7 | % - endress2007: ABB, LHM 8 | % - frank2009: uni, multi 9 | % - gerken2006: AAB, AAx, AAx2 10 | % - gerken2010: col, col+5, music+5 11 | % - gomez2002: 2x, 6x, 12x, 24x 12 | % - kovacs2009 (no conditions) 13 | % see manuscript for more details 14 | 15 | clear all 16 | addpath('helper') 17 | 18 | % parameters 19 | params.expt = 'endress2007'; 20 | params.lang = 'LMH'; 21 | 22 | %% initialization 23 | 24 | name = ['mats/' params.expt '.mat']; 25 | [hs train correct incorrect] = setupWorld(params); 26 | 27 | % either generate or load the hypothesis space 28 | if size(dir(name),1)>0 29 | load(name); 30 | % else 31 | % hs = createHypothesisSpace(hs); 32 | % hs = cacheCardinalities(hs); 33 | % hs = cacheTest(hs); 34 | % save(name,'hs'); 35 | end 36 | 37 | %% find all rules compatible with all strings 38 | 39 | ll = zeros(length(hs.hs),length(train)); 40 | 41 | for i = 1:length(hs.hs) 42 | for j = 1:length(train) 43 | if applyRuleToString(hs.hs{i},train{j}) 44 | ll(i,j) = 1; 45 | end 46 | end 47 | end 48 | 49 | true_of_all = mean(ll,2)==1; 50 | 51 | %% then find strings consistent with true_of_all 52 | 53 | consistent_strings = zeros(size(hs.all_strings)); 54 | 55 | for i = 1:length(hs.all_strings) 56 | if all(hs.true_of(true_of_all,i)) 57 | consistent_strings(i) = 1; 58 | end 59 | end 60 | 61 | %% write test results 62 | 63 | writeResultsE1 --------------------------------------------------------------------------------