test sample unique

function test_suite = test_sample_unique
% tests for cosmo_sample_unique
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_sample_unique_basics
    aet=@(varargin)assertExceptionThrown(@()...
                    cosmo_sample_unique(varargin{:}),'');

    for k=from_range_randomly(10,5)
        for n=from_range_randomly(10,5);
            for count=[0,from_range_randomly(100,10)];
                if count==0
                    args={k,n};
                    ncol=1;
                else
                    args={k,n,count};
                    ncol=count;
                end

                if k>n
                    % n too large; should throw error
                    aet(args{:});
                    continue;
                else
                    i=cosmo_sample_unique(args{:});
                    assertEqual(sort(i,1),i);

                    % check size
                    assert(isequal(size(i),[k,ncol]))

                    % check contents
                    i_vec=i(:);
                    assert(all(i_vec>=1 | i_vec<=n | round(i_vec)==i_vec));

                    % each element must be select about equally often,
                    % and each column must have unique elements
                    i_s=sort(i,1);

                    % each element unique
                    assert(all(all(diff(i_s,1,1)>0)));

                    % check counts
                    counts=zeros(n,1);
                    for col=1:ncol
                        counts(i(:,col))=counts(i(:,col))+1;
                    end

                    % counts differ at most by one
                    assert(min(counts)+1>=max(counts));
                end
            end
        end
    end

function test_sample_unique_full_randperm()
    k=2+from_range_randomly(10);
    n=k;
    c=5+from_range_randomly(10);

    i=cosmo_sample_unique(k,n,c);
    assertEqual(sort(i,1),repmat((1:k)',1,c));

function test_sample_unique_difference_sequences()
    k=2+from_range_randomly(10);
    n=k+from_range_randomly(10);
    c=5+from_range_randomly(10);

    seed=1+from_range_randomly(1e5);
    last_args={{'seed',seed},{'seed',[]'},{}};
    for k=1:numel(last_args)
        all_same=true;

        last_arg=last_args{k};
        use_seed=numel(last_arg)==2 && ~isempty(last_arg{2});

        for tries=1:5
            i=cosmo_sample_unique(k,n,c,last_arg{:});
            if tries==1
                i_first=i;
            elseif ~isequal(i_first,i)
                all_same=false;
                break;
            end
        end

        if xor(all_same,use_seed)
            assertFalse(true,'randomness mismatch with respect to seed');
        end
    end


function test_sample_unique_exceptions
    aet=@(varargin)assertExceptionThrown(@()...
                    cosmo_sample_unique(varargin{:}),'');

    bad_args={-1, 1.5, [1 1], struct(), false};
    for k=1:numel(bad_args)
        bad_arg=bad_args{k};

        for j=1:3
            all_args={1,1,1};
            all_args{j}=bad_arg;
            aet(all_args{:});
        end
    end




function vs=from_range_randomly(n, count)
    if nargin<=2
        count=1;
    end

    assert(n>=count);
    vals=1:n;

    rp=randperm(n);
    vs=vals(rp(1:count));