% hopRelaxNet_callback.m
%
%  Relaxation of a Hopfield network.
%  kornel laskowski & dave touretzky (c) 2004
%  cmu 15-782 artificial neural networks

global hTab;
global boltzmannPopup;
global unitsPopup;

N = length(hTab);

if get(boltzmannPopup,'Value') == 1

	% hopfield net

	while 1

		sTab = cell2mat( get( hTab, 'UserData' ) );

		% originally, to duplicate the results
		% from the reference (using 0/1 units):
		%  1. check for active neighbors
		%  2. compute new state
		%  3. update state if have active neighbors
		%     else leave as before
		%
		% actNeigh = (abs(W) * sTab) > 0;
		% candSTab = ((W * sTab) >= 0);
		% newSTab = or( ...
		%		and(actNeigh,candSTab), ...
		%		and(not(actNeigh),sTab) ...
		%	);

		if get(unitsPopup,'Value') == 2
			% 0/+1 units
			newSTab = (W * sTab) > 0;
		else
			% -1/+1 units
			sTab = 2 * sTab - 1;
			newSTab = sign(W * sTab);
			newSTab0Idx = find(newSTab == 0);
			newSTab(newSTab0Idx) = 1;
		end

		% if stable, leave
		if newSTab == sTab
			hopEnergy(1);
			break;
		end

		% choose one to update
		idx = ceil(N * rand(1)); % index of current state 
		if sTab(idx,1) ~= newSTab(idx,1)
			hopToggleUnitVal( hTab(idx) );

			if relax_step == 0
				break;
			else
				pause(0.1);
			end
		end
	end

elseif get(boltzmannPopup,'Value') == 2

	% boltzmann machine

	% if doing a single step, do not randomize first
	% otherwise randomize
	if relax_step ~= 0
		hopRandNet_callback;
	end

	global T;
	global nT;
	global Tmax;
 
	while 1

		sTab = cell2mat( get( hTab, 'UserData' ) );

		if get(unitsPopup,'Value') == 2
			% 0/+1 units
			% no change
		else
			% -1/+1 units
			sTab = 2 * sTab - 1;
		end

		net_inTab = W * sTab;
		energyGapTab = -net_inTab;
		P_1Tab = 1 ./ ( 1 + exp( energyGapTab / T ) );
		randVarTab = rand(N,1);

		if get(unitsPopup,'Value') == 2
			% 0/+1 units
			flipIdx = find( or( ...
					and(P_1Tab > randVarTab, sTab == 0), ...
					and(P_1Tab < randVarTab, sTab > 0)  ...
				) > 0 );
		else
			% -1/+1 units
			flipIdx = find( or( ...
					and(P_1Tab > randVarTab, sTab < 0), ...
					and(P_1Tab < randVarTab, sTab >= 0)  ...
				) > 0 );
		end

		hopToggleUnitVal( hTab( flipIdx ) );
		
		nT = nT + 1;
		if nT == 2*N
			nT = 0;
			T = 0.9 * T;
			hopTemperature;
		end

		if relax_step == 0
			break;
		else
			if T < .01 * Tmax
				hopEnergy(1);
				break;
			else
				pause(0.02);
			end
		end
	end	

else

	% mean field boltzmann machine

	% if doing a single step, do not randomize first
	% otherwise randomize
	if relax_step ~= 0
		hopRandNet_callback;
	end

    global T;
    global nT;
    global Tmax;

	while 1

		sTab = cell2mat( get( hTab, 'UserData' ) );
		net_inTab = W * sTab;

		if get(unitsPopup,'Value') == 2
			% 0/+1 units
			newSTab = 1 ./ ( 1 + exp( - net_inTab/T ) );
			convSTab = 2*newSTab - 1;
		else
			% -1/+1 units
			newSTab = tanh( net_inTab/T );
			convSTab = newSTab;
		end

		hopSetUnitVal( hTab, newSTab );

		nT = nT + 1;
		if nT == 2
			nT = 0;
			T = 0.99 * T;
			hopTemperature;
		end

		if relax_step == 0
			break;
		else
			if min(abs(convSTab)) > 0.8
				hopEnergy(1);
				break;
			else
				pause(0.02);
			end
		end
	end
end

