ConsolidateIntervals - Consolidate intervals. Consolidate overlapping intervals, e.g. replace [10,20] [15,25] with [10,25]. USAGE [consolidated,target] = ConsolidateIntervals(intervals,<options>) intervals list of intervals <options> optional list of property-value pairs (see table below) ========================================================================= Properties Values ------------------------------------------------------------------------- 'strict' intervals with common bounds are consolidated ('off') or kept separate ('on') (default = 'off') 'epsilon' intervals with close enough bounds (distance lesser than epsilon) are also consolidated (default = 0) ========================================================================= OUTPUT consolidated consolidated intervals target for each original interval, the index of the consolidated interval to which it belongs (empty intervals yield NaN) SEE See also SubtractIntervals, ExcludeIntervals, InIntervals, Restrict, FindInInterval, CountInIntervals, PlotIntervals.
0001 function [consolidated,target] = ConsolidateIntervals(intervals,varargin) 0002 0003 %ConsolidateIntervals - Consolidate intervals. 0004 % 0005 % Consolidate overlapping intervals, e.g. replace [10,20] [15,25] with [10,25]. 0006 % 0007 % USAGE 0008 % 0009 % [consolidated,target] = ConsolidateIntervals(intervals,<options>) 0010 % 0011 % intervals list of intervals 0012 % <options> optional list of property-value pairs (see table below) 0013 % 0014 % ========================================================================= 0015 % Properties Values 0016 % ------------------------------------------------------------------------- 0017 % 'strict' intervals with common bounds are consolidated ('off') 0018 % or kept separate ('on') (default = 'off') 0019 % 'epsilon' intervals with close enough bounds (distance lesser than 0020 % epsilon) are also consolidated (default = 0) 0021 % ========================================================================= 0022 % 0023 % OUTPUT 0024 % 0025 % consolidated consolidated intervals 0026 % target for each original interval, the index of the consolidated 0027 % interval to which it belongs (empty intervals yield NaN) 0028 % 0029 % SEE 0030 % 0031 % See also SubtractIntervals, ExcludeIntervals, InIntervals, Restrict, 0032 % FindInInterval, CountInIntervals, PlotIntervals. 0033 0034 0035 % Copyright (C) 2004-2011 by Michaƫl Zugaro 0036 % 0037 % This program is free software; you can redistribute it and/or modify 0038 % it under the terms of the GNU General Public License as published by 0039 % the Free Software Foundation; either version 3 of the License, or 0040 % (at your option) any later version. 0041 0042 % Default values 0043 strict = 'off'; 0044 epsilon = 0; 0045 0046 if nargin < 1, 0047 error('Incorrect number of parameters (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).'); 0048 end 0049 0050 if mod(length(varargin),2) ~= 0, 0051 error('Incorrect number of parameters (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).'); 0052 end 0053 0054 % Parse options 0055 for i = 1:2:length(varargin), 0056 if ~ischar(varargin{i}), 0057 error(['Parameter ' num2str(i+firstIndex) ' is not a property (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).']); 0058 end 0059 switch(lower(varargin{i})), 0060 case 'strict', 0061 strict = lower(varargin{i+1}); 0062 if ~isastring(strict,'on','off'), 0063 error('Incorrect value for property ''strict'' (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).'); 0064 end 0065 case 'epsilon', 0066 epsilon = varargin{i+1}; 0067 if ~isdscalar(epsilon,'>0'), 0068 error('Incorrect value for property ''epsilon'' (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).'); 0069 end 0070 otherwise, 0071 error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help <a href="matlab:help ConsolidateIntervals">ConsolidateIntervals</a>'' for details).']); 0072 end 0073 end 0074 0075 original = intervals; 0076 0077 % Mark already consolidated intervals to avoid retesting them 0078 done = logical(zeros(size(intervals(:,1)))); 0079 0080 if strcmp(strict,'on'), 0081 for i = 1:size(intervals,1), 0082 if done(i), continue; end 0083 % Lower (L) and upper (U) interval bounds 0084 L = intervals(:,1); 0085 U = intervals(:,2); 0086 % Current interval is I = [l u], but we replace it with [l-e u+e] to take parameter 'epsilon' into account 0087 l = L(i)-epsilon;u = U(i)+epsilon; 0088 % Find all intervals that overlap with I: 0089 % 1) one of their bounds is strictly inside I 0090 % (their upper bound is greater than l, and their lower bound is lower than u) 0091 intersect = (U > l & L < u); 0092 % 2) they contain I 0093 if u == l, 0094 % Special case: I is a singleton 0095 intersect = intersect | (L < l & U > u); 0096 else 0097 intersect = intersect | (L <= l & U >= u); 0098 end 0099 % Determine smallest enclosing interval 0100 m = min(L(intersect)); 0101 M = max(U(intersect)); 0102 % Consolidate 0103 intervals(intersect,:) = repmat([m M],sum(intersect),1); 0104 done(intersect) = 1; 0105 end 0106 else 0107 % (same as above, but replacing e.g. < with <=) 0108 for i = 1:size(intervals,1), 0109 if done(i), continue; end 0110 % Lower (L) and upper (U) interval bounds 0111 L = intervals(:,1); 0112 U = intervals(:,2); 0113 % Current interval is I = [l u], but we replace it with [l-e u+e] to take parameter 'epsilon' into account 0114 l = L(i)-epsilon;u = U(i)+epsilon; 0115 % Find all intervals that overlap with I: 0116 % 1) one of their bounds is inside I 0117 % (their upper bound is greater than or equal to l, and their lower bound is lower than or equal to u) 0118 intersect = (U >= l & L <= u); 0119 m = min(L(intersect)); 0120 M = max(U(intersect)); 0121 % Consolidate 0122 intervals(intersect,:) = repmat([m M],sum(intersect),1); 0123 done(intersect) = 1; 0124 end 0125 end 0126 0127 % Sort intervals in ascending order (and store reordering information so we can reuse it later) 0128 [intervals,order] = sortrows(intervals,1); 0129 0130 % Assign each consolidated interval an ID (in ascending order) 0131 transitions = [1;find(diff(intervals(:,1))~=0)+1;length(intervals(:,1))]; 0132 for i = 1:length(transitions)-1, 0133 target(transitions(i):transitions(i+1)) = repmat(i,transitions(i+1)-transitions(i)+1,1); 0134 end 0135 0136 % Reorder consolidated interval IDs 0137 target(order) = target; 0138 target = target'; 0139 0140 consolidated = unique(intervals,'rows'); 0141 0142 % Remove empty intervals from output... 0143 empty = diff(consolidated,1,2) < 0; 0144 consolidated(empty,:) = []; 0145 % ... and update target IDs 0146 empty = diff(original,1,2) < 0; 0147 [t,i] = sortrows([target empty]); 0148 target(i) = t(:,1)-cumsum(t(:,2)); 0149 0150 % Empty intervals belong to none 0151 target(empty) = NaN;