function runbinary(train_data, test_data, options)

    if (nargin ~= 3)
        if (nargin == 2)
            options = '';
        else
            fprintf('Incorrect number of input parameters\n');
            return;
        end
    end

    if isequal(class(train_data), 'char')
        [y, x, map] = libsvmread_ml(train_data);
        [ty, tx, tmap] = libsvmread_ml(test_data);
    else
        x = train_data.x;
        y = train_data.y;
        map = train_data.map;
        tx = test_data.x;
        ty = test_data.y;
        tmap = test_data.map;
    end

    x = x';
    tx = tx';

    % fill x
    probk = size(x, 1);
    testk = size(tx, 1);
    k = max(probk, testk);
    x = [x; zeros(k-probk, size(y, 1))];
    tx = [tx; zeros(k-testk, size(ty, 1))];

    [w, bias] = train_binary_probs(y, x, options);

    eval(ty, tx, tmap, map, w, bias);

end

function [w, bias] = train_binary_probs(y, x, options)

    d = size(y, 2);

    bias = 0;
    options_split = strsplit(options, ' ');
    tmp = strfind(options_split, '-B');
    for i = 1:size(tmp, 2),
        if tmp{i} == 1,
            bias = str2num(options_split{i+1});
            break;
        end
    end

    if bias > 0
        w = zeros(size(x,1)+1, d);
    else
        w = zeros(size(x,1), d);
    end
    
    for i=1:d
        m = train(2*y(:,i)-1, x, options, 'col');

        % Liblinear flips +1/-1 labels so +1 is always the first label,
        % but not if all labels are -1.
        % For our usage, we need +1 to always be the first label,
        % so the check is necessary.
        if m.Label(1) == -1
            w(:,i) = -m.w';
        else
            w(:,i) = m.w';
        end
    end
end

function eval(ty, tx, tmap, map, w, bias)

    d = size(map,1);
    
    F = 0;
    tp_sum = 0;
    fp_sum = 0;
    fn_sum = 0;
    tn_sum = 0;

    pre_all = zeros(size(w,2), d);
    if (size(w,1) > size(tx,1))
        pre_all = (w'*[tx; bias*ones(1,size(tx,2))])';
    else
        pre_all = (w'*tx)';
    end
    
    
    for i = 1:d
        % deal with this label
        label = map(i);

        test_idx = find(tmap == label);

        if isempty(test_idx)
            orig = zeros(size(ty, 1), 1);
        else
            orig = full(ty(:, test_idx));
        end

        pre = pre_all(:,i)  > 0;

        tp = sum(orig == +1 & pre == +1);
        fn = sum(orig == +1 & pre == 0);

        tn = sum(orig == 0 & pre == 0);
        fp = sum(orig == 0 & pre == +1);

        this_F = 0;
        if tp ~= 0 || fp ~= 0 || fn ~= 0
            this_F = (2*tp) / (2*tp + fp + fn);
        end
        F = F + this_F;

        tp_sum = tp_sum + tp;
        fp_sum = fp_sum + fp;
        fn_sum = fn_sum + fn;
        tn_sum = tn_sum + tn;

        fprintf(1, 'INFO: label %d:\tF %.6f\ttp %d\tfp %d\ttn %d\tfn %d\n', label, this_F, tp, fp, tn, fn);
    end

    micro = (2*tp_sum) / (2*tp_sum + fp_sum + fn_sum);
    macro = F / d;

    fprintf(1, 'INFO: tp_sum %d fp_sum %d fn_sum %d tn_sum %d\n', tp_sum, fp_sum, fn_sum, tn_sum);
    fprintf(1, 'INFO: microaverage: %.6f\n', micro);
    fprintf(1, 'INFO: macroaverage: %.6f\n', macro);

end

