function R = randpermbreak(N,BP, bpfixed)
% RANDPERMBREAK - randomize the order of elements within sections of a vector
%
% R = RANDPERMBREAK(N, BP) returns a random permutation of the numbers 1
% to N in sections, using the breakpoints specified by the indices BP.
% If BP is a scalar, the first part of R contains a random permutation of
% the numbers 1 to BP(1) and the second part a random permutation of the
% numbers BP(1)+1 to N. Example:
%
% randpermbreak(10,5)
% % could return 1 5 3 4 2 10 8 7 6 9
%
% If BP contains more indices, the indices are used in sorted order, and
% R consists of a random permutation of 1 to BP(1), BP(1)+1 to BP(2), ...
% and BP(N) to N. Example:
%
% randpermbreak(12,[4 8])
% % 3 2 4 1 6 5 7 8 12 9 11 10
%
% RANDPERMBREAK(X,BP,'fixed') excludes the break point indiced from being
% permuted. Example:
%
% randpermbreak(7,4,'fixed')
% % a random permutation of 1 to 3, 4 and a permutation of 5-7
% % 3 1 2 4 7 5 6
%
% This function can be used to arbitrarily permute a list of characters,
% like in this example:
% T = ['Uijt!jt!bo!jmmvtusbujpo!pg!uif!fggfdu!pg!qfsnvujoh!mfuuf' ...
% 'st!xjuijo!xpset!' char(14) '!fydfqu!gps!uif!gjstu!boe!mbtu!mfuufs!/' ...
% '!Ep!zpv!uijol!uiftf!tfoufodft!' char(14) '!bsf!tujmm!sfbebcmf!@'] ;
% i = find(T == 33) ;
% r = randpermbreak(numel(T),[1 i-1 i i+1 numel(T)],'fixed') ;
% char(T(r)-1)
%
% Notes:
% - Break point indices smaller than 1 or larger than the number of
% elements in N are ignored.
% - If BP is empty, the result will be a random permutation of the
% numbers 1 to N, just like randperm.
%
% See also RANDPERM, RAND, SORT
% SHAKE, RANDSWAP, SORTBREAK (File Exchange)
% for Matlab R13 and up
% version 1.1 (nov 2008)
% (c) Jos van der Geest
% email: jos@jasen.nl
% History
% Created: nov 2008
% 1.1 fixed error in sentence example
% check input arguments
error(nargchk(2,3,nargin)) ;
if nargin == 2,
bpfixed = false ;
elseif strcmpi(bpfixed,'fixed')
bpfixed = true ;
else
error([mfilename ':InvalidArgument'], ...
'The third argument should be the string ''fixed''.') ;
end
if numel(N) ~= 1 || ~isreal(N) || N ~= fix(N) || N < 1,
error([mfilename ':NotRealInt'], ...
'First argument should be a positive integer.') ;
end
if ~isreal(BP) || any(fix(BP) ~= BP) && any(BP<1),
error([mfilename ':BreakpointNotRealPositiveIntegers'],...
'Breaks points should be positive integers') ;
end
if any(BP(:)>N) || any(BP(:)<1),
warning([mfilename ':BreakpointTooLarge'],...
'Break points smaller than one or\nlarger than the number of elements of X are ignored.') ;
end
% only use valid break points
BP = BP(BP <= N & BP > 0) ;
if isempty(BP),
[R,R] = sort(rand(1,N)) ; % trivial, simply randperm
else
% mark the sections: section one is 2, section two is 4, etc.
R = zeros(1,N) ;
R(BP(BP<N)+1) = 2 ; % sections are labeled 0, 2, 4, ...
% take care of BP = N
R = cumsum(R) ;
if bpfixed,
% if break points are not to be randomly permuted, these will
% be treated as separate sections with labels 1, 3, 5, ...
R(BP) = R(BP) + 1 ;
end
% we add a random number between 0 and 1.
R = R + rand(1,N) ;
% Note that floor(R) returns the section number. If we sort these
% random numbers, the sections will stay in place.
[R, R] = sort(R) ; % the trick used by randperm
end