function [all_theta] = mlr_batch(X, y, num_labels, lambda)

% Some useful variables
m = size(X, 1);
n = size(X, 2);

% You need to return the following variables correctly 
all_theta = zeros(num_labels, n + 1);

% Add ones to the X data matrix
X = [ones(m, 1) X];

% MLR code
errold = 1000000;
tic
for epoch = 1:1000
    fprintf('training epoch %d\n', epoch);
    lrate = 0.0005;
    thincr = zeros(size(all_theta));
    for nex = 1:m
        Z = sum(exp(all_theta * X(nex,:)'));
        for c = 1:(num_labels - 1)
            thincr(c,:) = thincr(c,:) - lrate * (X(nex,:) * ...
                (exp(all_theta(c,:) * X(nex,:)')/Z - (c == y(nex))) + ...
                lambda / m / m * all_theta(c,:));
        end
    end
    all_theta = all_theta + thincr;
    errnew = 0;
    for nex = 1:m
        errnew = errnew - log(exp(all_theta(y(nex),:) * X(nex,:)') / ...
            sum(exp(all_theta * X(nex,:)')));
    end
    for c = 1:(num_labels - 1)
        errnew = errnew + (lambda / (2 * m)) * sum(sum(all_theta.^2));
    end
    if (abs(errnew - errold) / (abs(errnew) + abs(errold))) < 0.001
        break;
    else
        errold = errnew;
    end
end
toc

% =========================================================================


end
