%Hebbian Learning demo BioNB330
%linear (nonspikeing) neurons
%Bruce Land
%Sept2004

clear all
close all

%build the GUI
%define the figure

colordef white

fig=figure(1);
clf
figTop = 650;
figRight = 800;
set(fig,'resize','off',...
    'doublebuffer','on',...
    'color',[1 1 1]*0.8,...
    'position',[100 100 figRight figTop],...
    'name', 'BioNB 330 Hebbian Learning Simulator',...
    'numbertitle','off')

%===Main state controls=================
%define the Run button
x=10; y=figTop-25;

%define the Quit button
quitbutton=uicontrol('style','pushbutton',...
    'string','Quit', ...
    'fontsize',12, ...
    'position',[figRight-65,y,50,20], ...
    'callback','quitit=1;close all;');

y = y-10;
w = 100;
%reset the weights
resetbutton=uicontrol('style','pushbutton',...
    'string','Reset', ...
    'fontsize',14, ...
    'position',[x,y,w,25], ...
    'callback', 'resetW=1;');

x = x+w+10;
%define the learn button
learnFbutton=uicontrol('style','pushbutton',...
    'string','Learn', ...
    'fontsize',14, ...
    'position',[x,y,w,25], ...
    'callback','learnF=1;');

x = x+w+10;
%define the sweep frequencies button
sweepFbutton=uicontrol('style','pushbutton',...
    'string','Sweep', ...
    'fontsize',14, ...
    'position',[x,y,w,25], ...
    'callback','sweepF=1;');

%===now the parameter settings=================
%define the # steps edit field
x=450; y=550; h=50;
LnumberUI=uicontrol('style','edit',...
    'string','5', ...
    'fontsize',14, ...
    'position',[x,y,70,30] ...
    );
uicontrol('style','text',...
    'string','# Training Steps', ...
    'fontsize',14, ...
    'position',[x+70,y,150,25] ...
    );

%define the learning rate edit field
y = y-h;
LrateUI=uicontrol('style','edit',...
    'string','0.2', ...
    'fontsize',14, ...
    'position',[x,y,70,30] ...
    );
uicontrol('style','text',...
    'string','Learning Rate', ...
    'fontsize',14, ...
    'position',[x+70,y,120,25] ...
    );

%define the learning threshold edit field
y = y-h;
LthresholdUI=uicontrol('style','edit',...
    'string','0', ...
    'fontsize',14, ...
    'position',[x,y,70,30] ...
    );
uicontrol('style','text',...
    'string','Learning Threshold', ...
    'fontsize',14, ...
    'position',[x+70,y,180,25] ...
    );

%===define the norm type list box
y = y-h;
uicontrol('style','text',...
    'string','Normalization', ...
    'fontsize',14, ...
    'position',[x,y,120,25] ...
    );
y = y-100; w=90;
NormTypeUI=uicontrol('style','listbox',...
    'string','None|Clip|Sum|Biggest', ...
    'fontsize',12, ...
    'position',[x,y,w,100], ...
    'callback',[...
        'if get(gcbo,''value'')==2;',...
        'set(ClipLevelUI,''enable'',''on'');',...
        'else;set(ClipLevelUI,''enable'',''off'');end;']...
    );
yt = y + 63; xt = x + w + 10;
ClipLevelUI=uicontrol('style','edit',...
    'string','10', ...
    'fontsize',12, ...
    'enable','off', ...
    'position',[xt,yt,70,20] ...
    );
uicontrol('style','text',...
    'string','Clip Level', ...
    'fontsize',12, ...
    'position',[xt+70,yt,80,20] ...
    );

% yt = y + 15; xt = x + w + 10;
% InThresholdUI=uicontrol('style','edit',...
%     'string','0', ...
%     'fontsize',12, ...
%     'enable','off', ...
%     'position',[xt,yt,70,20] ...
%     );
% uicontrol('style','text',...
%     'string','Input Threshold', ...
%     'fontsize',12, ...
%     'position',[xt+70,yt,120,20] ...
%     );

%define the output threshold edit field
y = y-40;
thresholdUI=uicontrol('style','edit',...
    'string','0', ...
    'fontsize',14, ...
    'position',[x,y,70,30] ...
    );
uicontrol('style','text',...
    'string','Output Threshold', ...
    'fontsize',14, ...
    'position',[x+70,y,160,25] ...
    );

%define the output threshold edit field
y = y-40;
sweepRateUI=uicontrol('style','edit',...
    'string','20', ...
    'fontsize',14, ...
    'position',[x,y,70,30]...
    );
uicontrol('style','text',...
    'string','Sweep Rate', ...
    'fontsize',14, ...
    'position',[x+70,y,160,25] ...
    );

%===input regions===============================
x=150; y=450;
for i=1:5
    inUI(i) = uicontrol('style','pushbutton',...
        'string',num2str(i), ...
        'fontsize',14, ...
        'userdata', 0, ...
        'backgroundcolor', 'k', ...
        'ForegroundColor', 'w', ...
        'position',[x,y,50,50]);
    y=y-80;
end
usUI = uicontrol('style','pushbutton',...
        'string','US', ...
        'fontsize',14, ...
        'userdata', 0, ...
        'backgroundcolor', 'k', ...
        'ForegroundColor', 'w', ...
        'position',[350,400,50,50]);

%===the receptive fields=========================
INaxes = axes('position',[.0 .15 .15 .70]);
xF=linspace (500, 2200, 2200-500);
bestF = [800 1100 1400 1700 2000];
sigma = 150 ;
hold on
for i=1:5 
    yF = 1 - exp(-(xF-bestF(i)).^2/(4*sigma^2));
    plot(yF,xF,'w')
end
set(gca, 'color','k','YAxisLocation','right','ydir','reverse')
set(gca, 'xlim', [0 1], 'xtick',[],'fontsize',8)
axis tight
sweepLine = line([0 1], [500 500],'color','r','linewidth',3,'visible','off');

%===output regions===============================
x=350; y=300;
out1UI = uicontrol('style','pushbutton',...
    'string','Out', ...
    'fontsize',14, ...
    'userdata', 0, ...
    'backgroundcolor', 'k', ...
    'ForegroundColor', 'w', ...
    'position',[x,y,50,50]);

%===Connections===============================
lineax = axes('position',[0 0 1 1]);
axis off
set(lineax,'xlim',[0 figRight],'ylim',[0 figTop],'color','none')
offset=550 ; delta=80;
%line from input i to output j
for i = 1:5
        lh(i) = line([200 350],[offset-i*delta 325],'color','k');
end
%unconditioned stimulus to output
line([375 375], [400 300],'color','r')

%===set button states===========================
quitit = 0;
resetW=0;
learnF=0;
sweepF=0;
sweepErase=0;
sweepStarted=0;
in = [0 0 0 0 0];
out = 0;
weight = zeros(1,5);
trainF = 1400;
sweepNumber=1;
%===Sweep plot output=============================
sweepAxis = axes('position',[.35 .05 .6 .2]);
set(gca,'xlim',[500 2200])
set(gca,'ylim',[0 10])
ylabel('Output')
Title('Frequency Sweep Results')
sweepNormUI = uicontrol('style','checkbox',...
    'string','Normalized', ...
    'fontsize',12, ...
    'position',[630,165,100,20]);
sweepEraseUI = uicontrol('style','pushbutton',...
    'string','Erase plot', ...
    'fontsize',12, ...
    'callback','sweepErase=1',...
    'position',[300,165,100,20]);
sweepColors = jet(10);
%===main event loop===============================
while (quitit==0)
    %
    sweepRate = str2num(get(sweepRateUI,'string'));
    Lnumber = str2num(get(LnumberUI,'string'));
    Lrate = str2num(get(LrateUI,'string'));
    OutThreshold = str2num(get(thresholdUI,'string'));
    ClipLevel = str2num(get(ClipLevelUI,'string'));
    Lthreshold = str2num(get(LthresholdUI,'string'));
    NormType = get(NormTypeUI,'value');
    sweepNorm = get(sweepNormUI,'value');
    
    %scan the input and plot output
    if sweepF
        if sweepStarted %continuing the sweep
            %move the line
            sweepLineY = sweepLineY + sweepRate;
            set(sweepLine,'ydata',[sweepLineY sweepLineY],'visible','on')
            %set the color of the inputs
            for i = 1:5 %once for each input
                lcol =  [exp(-(sweepLineY-bestF(i)).^2/(4*sigma^2)), 0, 0];
                set(inUI(i),'backgroundcolor',lcol);
            end
            %compute the output
            output = sum(weight .* exp(-(sweepLineY-bestF).^2/(4*sigma^2)));
            output = (output>OutThreshold)*(output-OutThreshold);
            %and plot it
            set(gcf,'currentaxes',sweepAxis)
            if sweepNorm
                Poutput = output/outputPeak ;
            else
                Poutput = output;
            end
            plot(sweepLineY,Poutput,'o',...
                'markeredgecolor','black',...
                'markerfacecolor',sweepColors(mod(sweepNumber,10)+1,:))
            hold on
            if sweepNorm
                set(gca,'ylim',[0 1])
            else
                set(gca,'ylim',[0 10])
            end
            set(gca,'xlim',[500 2200])
            ylabel('Output')
            Title('Frequency Sweep Results')
            
            if sweepLineY==2200 %at end frequency
                sweepStarted=0; 
                sweepF=0;
                set(sweepLine,'visible','off')
                %clear input colors to black
                for i = 1:5
                    set(inUI(i),'backgroundcolor',[0 0 0]);
                end
                sweepNumber = sweepNumber + 1;
            end
        else %starting the sweep
            sweepLineY = 500;
            sweepStarted = 1;
            sumWeight = sum(weight);
            outputPeak = sum(weight .* exp(-(trainF-bestF).^2/(4*sigma^2)));
            outputPeak = (outputPeak>OutThreshold)*(outputPeak-OutThreshold);
        end   
    end
    
    %modify the weights
    if learnF
        set(gcf, 'pointer', 'watch')       
        for j = 1:Lnumber %for each training step 
            %stimuli
            set(sweepLine,'ydata',[trainF trainF],'visible','on')
            set(usUI,'backgroundcolor','g')
            drawnow
            pause(.2)
            %current output = weight inputs plus unconditioned stimulus
            output = sum(weight .* exp(-(trainF-bestF).^2/(4*sigma^2))) + 1;
            %get the training weight change
            for i = 1:5 %for each input
                inputI = exp(-(trainF-bestF(i)).^2/(4*sigma^2))
                weight(i) = weight(i) + ...
                        Lrate * ((inputI>Lthreshold)*(inputI-Lthreshold)) * output ;
            end
            switch NormType
                case 1 %none
                    lwidth = min(100,max(1,weight/2));
                case 2 %clip
                    weight = min(weight,ClipLevel);
                    lwidth = max(1,weight/2);
                case 3 %sum
                    weight = weight/sum(weight);
                    lwidth = min(20,max(1,weight*10));
                case 4 %biggest
                    weight = weight/max(weight);
                    lwidth = min(20,max(1,weight*10));
                case 5 %input threshold
                    
            end
            %animate connections
            for i=1:5               
                lcol =  [weight(i)>0, 0, 0];
                set(lh(i),'color',lcol,'linewidth',lwidth(i));
            end
            weight
            set(sweepLine,'ydata',[trainF trainF],'visible','off')
            set(usUI,'backgroundcolor','k')
            drawnow
            pause(.4)
        end %each training loop
        learnF = 0;
        set(gcf, 'pointer', 'arrow')
    end
    
    if resetW
        resetW = 0;
        weight = zeros(1,5);
        for i = 1:5 %for each input
            lcol =  [weight(i)>0, 0, 0];
            lwidth = max(1,weight(i)/10);
            set(lh(i),'color',lcol,'linewidth',lwidth);   
        end
    end
    
    if sweepErase
        sweepErase = 0;
        set(gcf,'currentaxes',sweepAxis)
        cla
        set(gca,'xlim',[500 2200])
        set(gca,'ylim',[0 10])
        ylabel('Output')
        Title('Frequency Sweep Results')
    end
    
    drawnow    
end %main while loop



