function x = simple_mlp_optimGD(initX, uFunc, uPar, ...
				 stepsize, maxIter, fgoal, gnsgoal)
% A simple gradient descent method for training an MLP.
%
% uFunc = "user function", in our case MLP evaluator, but could be anything
% uPar  = "user parameters", in our case training data, but could be
%         anything
%
% This method is extremely simple: We take small steps against the
% gradient. If the step size is small enough, we must (slowly) end
% up in a local minimum of the function. This is the 'good old'
% algorithm that is slow and dependent on the step size selection.

x = initX;
for iter=1:maxIter
  
  [f, grad] = uFunc(x, uPar);     % Evaluate cost and its gradient

  gns = sum(grad .^ 2);           % Gradient norm squared.
  
  if f <= fgoal, break, end;      % Stop if f is small enough
  if gns <= gnsgoal, break, end;  % Stop if gradient small.
  
  x = x - stepsize * grad;        % Take the small step downhill
end
disp(sprintf('%d/%d: f=%.17f  gns=%.17f', iter, maxIter, f, gns));
