function breast_cancer_classification_skeleton
load('breast_cancer.tsv')
num_features = size(breast_cancer, 2) - 1;
num_instances = size(breast_cancer, 1);
training_instances = round(0.8*num_instances);
X_train = breast_cancer(1:training_instances, 2:num_features);
y_train = 2 *breast_cancer(1:training_instances, num_features+1) - 1;

X_test = breast_cancer(training_instances+1:end, 2:num_features);
y_test = 2 * breast_cancer(training_instances+1:end, num_features+1) - 1;

for lr=[0.1, 0.01, 0.001]
  w_final = log_reg(X_train, y_train, lr, 300);
  accuracy = evaluate(w_final, (X_test), y_test);
  printf('The evaluated model obtains a %.4f accuracy with learning rate %f.\n', accuracy, lr);
endfor

fprintf("\nNow let us see the effects of some preprocessing... (Press a key to continue)\n\n")
pause

for lr=[0.1, 0.01, 0.001]
  w_final = log_reg(centralize(X_train), y_train, lr, 300);
  accuracy = evaluate(w_final, centralize(X_test), y_test);
  printf('The evaluated model obtains a %.4f accuracy with learning rate %f.\n', accuracy, lr);
endfor
endfunction

function result=centralize(input_matrix)
    % we want to make sure that the expected value of each feature is zero
    result = input_matrix - mean(input_matrix);  %% you should change this line
endfunction

function result=standardize(input_matrix)
    % we want to make sure that the expected value of each feature is zero and it has a standard deviation of 1
    result = input_matrix;  %% you should change this line
endfunction

function decorrelated_data=decorrelate_data(input_matrix)
    % transform the matrix so that any pair of disjoint columns show 0 correlation with each other.
    % (Hint: think of Mahanabolis distance).
    decorrelated_data = input_matrix;
endfunction

function result=length_normalize(input_matrix)
    % we want to make sure each row in the dataset has unit length
    % extra kudos if you manage to do it without a for loop
    result = input_matrix;  %% you should change this line
endfunction

function result=min_max_normalize(input_matrix)
    %% turn each feature (column) between 0 and 1
    result = input_matrix;  %% you should change this line
endfunction

function w=log_reg(training_data, target_data, learning_rate, max_iters=500, log_frequency=1000)
%%
%% Performs logistic regression learning.
%% Mandatory arguments are the training data matrix and the training gold class labels in a column vector format.
%%
    w = zeros(size(training_data, 2), 1);
    grad = zeros(1, size(training_data, 2));
    for iteration = 0:max_iters
        probs = max(1e-11, 1./(1+exp(-target_data.*(training_data*w))-1e-11));  % the probability assigned for the correct classlabel
        acc = sum(probs>0.5) / size(target_data, 1);
        cost = -sum(log(probs));
        if iteration > 0
            grad = sum(learning_rate*repmat(-target_data.*(1-probs), 1, size(training_data, 2)).*training_data);
        end
        w -= grad';
        if mod(iteration, log_frequency) == 0 && iteration > 1
            %printf('Iter %d cost: %.2f, weight norm: %.2f, gradient norm: %.2f, training acc: %.2f\n', iteration, cost, norm(w), norm(grad), acc);
            printf('Iter %d cost: %.2f, norm: %.2f, training acc: %.2f\n', iteration, cost,norm(w), acc);
        endif
    endfor
endfunction

function accuracy=evaluate(model_weights, observations, expected_labels)
    predictions = 2 * (observations * model_weights > 0) - 1;
    correct_predictions = sum(predictions == expected_labels);
    accuracy = correct_predictions / size(observations, 1);
endfunction