function rp=cosmo_randperm(n,varargin)
% generate random permutation of integers
%
% cosmo_randperm(n[,count][,'seed',seed])
%
% Inputs:
% n Maximum value of output
% count (optional) number of elements to return; count
% must not be larger than n.
% Default: count=n
% 'seed',seed (optional) use seed for determistic
% pseudo-random number generation. If provided
% then subsequent calls to this function with the
% same input arguments will always give the same
% output. If not provided, then subsequent calls
% will almost always give different outputs
%
% Output:
% rp row vector with count elements, with all
% numbers in the range 1:n. Numbers are sampled
% from 1:n without replacement, in other words rp
% does not contain repeats.
%
[n,k,seed]=process_input(n,varargin{:});
if isempty(seed)
seed_arg={};
else
seed_arg={'seed',seed};
end
[unused,rp]=sort(cosmo_rand(1,n,seed_arg{:}));
if ~isempty(k)
if k>n
error('second argument cannot be larger than first argument');
end
rp=rp(1:k);
end
function [n,k,seed]=process_input(n,varargin)
k=[];
seed=[];
ensure_is_int(n,'n');
% progress remaining arguments
n_arg=numel(varargin);
j=0;
while j<n_arg
j=j+1;
arg=varargin{j};
if isnumeric(arg)
ensure_is_int(arg,'count');
if ~isempty(k)
error('count argument provided multiple times');
end
k=arg;
elseif ischar(arg)
if j+1>n_arg
error('missing value after ''%s'' argument',arg);
end
switch arg
case 'seed'
if ~isempty(seed)
error('seed argument provided multiple times');
end
j=j+1;
value=varargin{j};
ensure_is_int(value,arg);
seed=value;
otherwise
error('illegal keyword ''%s''',arg);
end
else
error('illegal argument type %s at position %d',...
class(arg),j);
end
end
function ensure_is_int(value,label)
if ~(isnumeric(value) && ...
isscalar(value) && ...
value>=0 && ...
round(value)==value);
error('''%s'' argument must be non-negative integer',label)
end