%PLM_DEMO -- Getting started with the Hebbian Perceptual Learning Model
%
% See also PERCLEARN_INSTALL, PLM_HEBB2, PLM_PARAMS, PLFRONTEND.

% Original coding by Alex Petrov, Ohio State University
% $Revision: 1.1.1 $  $Date: 2008-12-12 $
%
% Part of the Hebbian Perceptual Learning Model version 1.1 for MATLAB.
% http://alexpetrov.com/proj/plearn/
% Copyright (c) Alexander Petrov 1999-2008, http://alexpetrov.com
% Please read the LICENSE and NO WARRANTY statement in PercLearn_license.m

cstr = 'Type ''return'' and press Enter to continue.\n' ;

%-- Print herald
more off ;
home ;

fprintf('\nHello!\n\n') ;

fprintf('Hebbian Perceptual Learning Model, Release 1.1.1, 2008-02-22.\n\n') ;

fprintf('Copyright (c) Alexander Petrov 1999-2008, http://alexpetrov.com \n\n') ;

fprintf('This script is intended to get you started with the Hebbian\n') ;
fprintf('perceptual learning model. It assumes you have already run\n') ;
fprintf('PercLearn_install, which has updated the MATLAB path.\n\n') ;

fprintf('The model and experiments are described in the following articles:\n');
fprintf('Petrov, A., Dosher, B. & Lu, Z.-L. (2005).\n') ;
fprintf('  The dynamics of perceptual learning: An incremental reweighting model.\n') ;
fprintf('  Psychological Review, 102 (4), 715-743.\n') ;
fprintf('Petrov, A., Dosher, B., & Lu, Z.-L. (2006)\n') ;
fprintf('  Perceptual learning without feedback in non-stationary contexts: Data and model.\n') ;
fprintf('  Vision Research, 46, 3177-3197.\n') ;
fprintf('Abstracts and reprints available on-line:\n') ;
fprintf('  http://alexpetrov.com/pub/perclearn/\n') ;

fprintf('New information may be available on the PLM project web site:\n') ;
fprintf('  http://alexpetrov.com/proj/plearn/\n\n') ;

PLM_path = PLM_pathstr ;
cd(PLM_path) ;
fprintf('Changing current dir to %s\n',PLM_path) ;

fprintf('It is recommended that you open the file PLM_demo.m in the MATLAB Editor\n') ;
fprintf('and inspect the code as you follow along. The file should now be open...\n') ;
edit PLM_demo ;

fprintf(cstr) ; keyboard ;

%-- Generate sample stimuli
fprintf('\n*******  Let us make two sample stimuli first.\n') ;
fprintf('The stimuli are created by the function MAKE_PLE_STIM, which is\n') ;
fprintf('part of the software that administered the experiment dubbed PLExp1\n') ;
fprintf('and reported in the Psych Review article cited above.\n\n') ;

fprintf('As a general rule, the parameters needed to do something are bundled in some\n') ;
fprintf('parameter structure, which is then passed to the functions that do the real job.\n') ;
fprintf('There are functions with names ending in ''_params'' that generate default params\n') ;
fprintf('from scratch. It is conventional to store the PLExp1 in the variable P:\n') ;
P = PLExp1_params

fprintf('Let us make a left Gabor target in Context L, easiest difficulty level (target contrast):\n') ;
orient = 1 ;
diff = 1 ;
context = 1 ;
stimL = make_PLE_stim(P,orient,diff,context) ;
figure(1) ; clf ; imagesc1(stimL) ;
title('Left target in Context L') ;

whos
fprintf(cstr) ; keyboard ;

fprintf('\nContrast that with a right target in the same Context L:\n') ;
orient = 2 ;
stimR = make_PLE_stim(P,orient,diff,context) ;
figure(2) ; clf ; imagesc1(stimR) ;
title('Right target in Context L') ;

fprintf(cstr) ; keyboard ;

%-- Representational subsystem
fprintf('\n*******  Representational subsystem...\n') ;
fprintf('The parameters of the representational subsystem of the model are:\n') ;
Idef = PLM_input_params

fprintf('Before we can run PLFRONTEND, we must call MAKE_PLFRONTEND on the Idef structure.\n') ;
Idef = make_PLFrontEnd(Idef) ;
or = Idef.D_orient ;     % The set of orientations used
f  = Idef.D_spfreq ;     % The set of spatial frequencies used

fprintf('PLFRONTEND can now be used to transform any 64x64 image into a 35-element representation:\n') ;
repL = PLFrontend(stimL,Idef) ;
repR = PLFrontend(stimR,Idef) ;

figure(1) ; clf ; 
plot(or,reshape(repL,7,5),'.-') ; 
set(gca,'xtick',or) ; xlabel('Orientation [deg]') ;
ylabel('Bottom-up input to the representation units') ;
for k=1:length(f) l{k}=sprintf('f = %4.1f',f(k)) ; end ; legend(l) ;
title('Representation of a Left target in Context L') ;

Hparams = Hinton_params ;
figure(2) ; clf ; 
Hinton_diag(repL,Hparams) ;
title('Hinton diagram corresponding to Figure 1') ;

fprintf(cstr) ; keyboard ;

%-- Cached representations
fprintf('\n*******  PLM_CACHE\n') ;
fprintf('The perceptual subsystem involves computer-intensive convolutions.\n') ;
fprintf('It is therefore convenient to generate a large cache of representations,\n') ;
fprintf('store them in the global variable PLM_CACHE, and reuse them over and over again.\n') ;
fprintf('The function CACHE_INPUTS is the tool to do that. It would take several hours\n') ;
fprintf('to generate a sufficient number of samples, however, so let us just load it\n') ;
fprintf('from the file PLM_CACHE.mat instead:\n') ;
global PLM_CACHE ;
load PLM_CACHE ;

fprintf('PLM_CACHE is a structure array with 12 elements, one for each stimulus type.\n') ;
fprintf('There are 5000 samples of each kind. For example:\n') ;
PLM_CACHE(1)

fprintf('Note that these ''representations'' do not yet contain internal noise and have not been\n') ;
fprintf('passed through the saturating nonlinearity of the activation function of the representaiton units.\n') ;
fprintf('The functions AGGREG_CACHE and HEBB_STATS facilitate the statistical analysis of these caches.\n') ;

fprintf(cstr) ; keyboard ;

%-- Presentation sequences
fprintf('\n*******  Non-stationary stimulus presentation sequences\n') ;
fprintf('Experiments PLExp1 and PLExp2 involve presentation schedules that alternate the\n') ;
fprintf('predominant background orientation in an alternating non-stationary manner.\n') ;
fprintf('The functions EXPAND_BLOCK_SPEC and BLOCK_FROM_CACHE are the tools to generate such schedules.\n') ;
fprintf('See the documentation section of these files for details, particularly Example 3 in BLOCK_FROM_CACHE.M\n') ;
fprintf('For our present purposes, let us just load the schedule descriptors from the file SCHED.MAT:\n') ;
load sched ;

fprintf('The variable sched1 defines Schedule 1, and the variable sched2 defines Schedule 2, as described\n') ;
fprintf('in Petrov, Dosher, & Lu (2005). There are 32 blocks of 300 trials each. Each block contains 50\n') ;
fprintf('replications of 6 stimulus kinds: 2 Gabor orientations X 3 Gabor contrasts. The context is fixed\n') ;
fprintf('within each block but changes in 8-block-long epochs depending on the schedule. For example, block 1') ;
fprintf('in Schedule 1 has the following specification. The first 3 columns correspond to the arguments of\n') ;
fprintf('MAKE_PLE_STIM and the .arg field in PLM_CACHE. Note that everything is in context L=1 in this case.\n') ;
sched1{1}

fprintf(cstr) ; keyboard ;

fprintf('\nWe are now in a position to generate some stimulus sequences (or ''descriptors'').\n') ;
fprintf('The first ten trials in the sequence are as follows:\n') ;
descr = block_from_cache(sched1,PLM_CACHE) ;
descr = cat(1,descr{:}) ;       % [9600x5 double]
descr(1:10,:)

fprintf('The variable DESCR has 9600 trials (rows) and 5 columns, as documented in BLOCK_FROM_CACHE.\n') ;
fprintf('The last two columns specify the cache index (1-12) and the replication index (1-5000) in the\n') ;
fprintf('global variable PLM_CACHE, respectively.  PLModel2 pulls the corresponding representation from\n') ;
fprintf('representation on each simulated trial, avoiding any calls to PLFRONTEND.\n') ;

fprintf(cstr) ; keyboard ;

%-- Running the perceptual learning model
fprintf('\n*******  Running the perceptual learning model...\n') ;
fprintf('With all this infrastructure at hand, we''re finally ready to run the learning component of the model.\n') ;
fprintf('The function PLM_PARAMS generates a default parameter structure, with parameter values reported in the\n') ;
fprintf('Vision Research article cited above. (Use PLM_PARAMS1 for the values in the Psych Review article.)\n') ;
Mparams = PLM_params

fprintf(cstr) ; keyboard ;

fprintf('\nPLM_HEBB2 implements the most recent version of the model (as of July 2005).\n') ;
fprintf('It uses soft clamping to introduce feedback, and introduces it only on error.\n') ;
fprintf('See the Vision Research article for discussion.  PLM_HEBB1 implements a slightly\n') ;
fprintf('different version used in the Psych Review article (Petrov, Dosher, & Lu, 2005).\n') ;
fprintf('(PLM_HEBB1 is a special case of PLM_HEBB2 when Mparams.fdbk_wgt=Inf and .fdbk_mode=1.)\n\n') ;

fprintf('The model can be invoked in several different ways, as documented in PLM_HEBB2.M\n') ;
fprintf('The simplest syntax is [o,Wh] = PLM_Hebb2(descr,Mparams):\n') ;
[o,Wh] = PLM_Hebb2(descr,Mparams) ;

o(1:10,:)

fprintf('\nThe leftmost column in the matrix O is the behavioral response of the model (1="Left", 2="Right").\n') ;
fprintf('The other columns keep track of various internal quantities. The printout above lists the first 10 trials of a 9600-trial run.\n') ;

fprintf(cstr) ; keyboard ;

fprintf('\nThe variable Wh keeps the weight history of the run. See PLM_HEBB2.M for details.\n') ;
figure(1) ; clf ;
foo=Wh(:,1:10:end) ;  % plot only one dot for every 10 trials
for k=1:5 
    subplot(2,3,k) ; 
    plot(foo([1:7]+7*k-7,:)','b') ; 
    axis([0 970 -.5 +.5]) ; 
    set(gca,'xtick',[0:120:960],'xticklabel',[],'ytick',[-.5:.1:+.5]) ; 
    title(['Weights at ' l{k}]) ; grid on ; 
end
subplot(2,3,6) ;
plot(foo(36,:),'r') ; 
axis([0 970 -.5 +.5]) ; 
set(gca,'xtick',[0:120:960],'xticklabel',[],'ytick',[-.5:.1:+.5]) ; 
title('Top-down bias') ; grid on ; 

fprintf(cstr) ; keyboard ;

%-- Calculate d' learning curves
fprintf('\n*******  Calculate d'' learning curves\n') ;
fprintf('The function PLM_STATS converts the long sequence of binary responses into z-transformed\n') ;
fprintf('probabilities of correct response for congruent and incongruent stimuli in each block.\n') ;
fprintf('This is analogous to the analysis of the behavioral data (see PLEDATA_BY_SBJ and PLE2_STATS).\n') ;
fprintf('PLM_STATS can analyze a whole batch of runs at once, which are then averaged by PLM_SUMMARY.\n') ;
fprintf('In our case we have just a single run to analyze:\n') ;
stats = PLM_stats(descr,o(:,1,:),o(:,2,:),o(:,3,:)) ;
sumstats = PLM_summary(stats)

fprintf(cstr) ; keyboard ;

%-- Plot model performance against human data
fprintf('\n*******  Plot the model performance against PLExp1 data.\n') ;
fprintf('The file HUMAN_ZCONGR.MAT contains the group averages of the z-probability profiles of\n') ;
fprintf('the first perceptual learning experiment (PLExp1, with feedback). See PLEDATA_BY_SBJ for details.\n') ;
global HUMAN_ZCONGR ;
load HUMAN_ZCONGR ;

fprintf('PLOT_PLM_FIT can then be used to plot the model data against the human data from PLExp1.\n') ;
fprintf('(Use PLOT_PLM_FIT2 with ../PLExp2/modelfits/HUMAN_ZCONGR.mat for the no-feedback condition.)\n') ;
figure(2) ; clf ;
plot_PLM_fit({sumstats.zP_congr',sumstats.zP_incon'}) ;

fprintf(cstr) ; keyboard ;

%-- Wrap up and finish
fprintf('\n*******  Where to go from here.\n') ;
fprintf('This illustrates the main functions involved in running the multichannel perceptual learning model\n') ;
fprintf('with default parameters.  There are specialized utilities for parameter search -- see in particular\n') ;
fprintf('the functions PLM_ZCONGR2, MAKE_CHEV, PLM_SEARCH_PARAMS, and the Paramsearch Toolbox.\n') ;
fprintf('The README files and the numerous .txt notes in various directories under PLModel1 contain transcripts\n') ;
fprintf('of most simulations and data fits reported in the two journal articles listed in the beginning of this tutorial.\n') ;
fprintf('The notes in PLModel1/newsimul/*.txt are the most recent ones.\n') ;
fprintf('There is also quite a bit of documentation in the preambles of the .m functions that implement the model.\n\n') ;

fprintf('Thank you for your interest in this work.\n') ;
fprintf('If you have any questions, please contact Alex Petrov, http://alexpetrov.com \n') ;
fprintf('Check the PLM project web site for recent updates:  http://alexpetrov.com/proj/plearn/ \n\n') ;
fprintf('End of PLM_DEMO.  Last updated 2008-02-22.\n\n') ;


%%%%% End of file PLM_DEMO.M
