www.gusucode.com > bigdata 工具箱 matlab源码程序 > bigdata/+matlab/+bigdata/+internal/+util/EndMarker.m
%EndMarker Helper class for tall indexing expressions involving 'end'. % Copyright 2015 The MathWorks, Inc. classdef (Sealed, Hidden) EndMarker properties (SetAccess = immutable) % Offset can be a scalar or vector indicating the number of elements away from % the actual end to select. Typically this value will be <= 0. Values >= % 0 imply indexing off the end of the array. Offset = 0 % ColonForm holds information about the beginning and end of the range, and the % offset. If present, it is 2x3 where the first row represents absolute % values, or NaN, and the second row represents relative values, or % NaN. In other words, % "2:2:end" --> [2, 2, NaN; NaN, NaN, 0] % "end - 3:end" --> [NaN, 1, NaN; -3, NaN, 0] % Note that the increment is always only present in the first row. ColonForm = [] % AbsoluteValue is used when concatenating EndMarkers with numeric values. AbsoluteValue = [] end methods function obj = EndMarker(offset, colonForm, absValue) if nargin > 0 obj.Offset = offset; end if nargin > 1 obj.ColonForm = colonForm; end if nargin > 2 obj.AbsoluteValue = absValue; end % We must have exactly one non-empty field. assert(sum(cellfun(@isempty, ... {obj.Offset, obj.ColonForm, obj.AbsoluteValue})) == 2); end function disp(obj) if isscalar(obj) if ~isempty(obj.Offset) fprintf('%s\n', iFormatEndOffset(obj.Offset)); elseif ~isempty(obj.Offset) cf = obj.ColonForm; Astr = iFormatOffsetOrNumber(cf(:,1)); if cf(1,2) == 1 Dstr = ''; else Dstr = sprintf('%d:', cf(1,2)); end Bstr = iFormatOffsetOrNumber(cf(:,3)); fprintf('%s:%s%s\n', Astr, Dstr, Bstr); else disp(obj.AbsoluteValue) end else builtin('disp', obj); end end function obj = uminus(varargin) %#ok<STOUT> error(message('MATLAB:bigdata:array:InvalidIndexingWithEnd', 'UMINUS')); end function obj = times(varargin) %#ok<STOUT> error(message('MATLAB:bigdata:array:InvalidIndexingWithEnd', 'TIMES')); end function obj = mtimes(varargin) %#ok<STOUT> error(message('MATLAB:bigdata:array:InvalidIndexingWithEnd', 'MTIMES')); end function obj = rdivide(varargin) %#ok<STOUT> error(message('MATLAB:bigdata:array:InvalidIndexingWithEnd', 'RDIVIDE')); end function obj = mrdivide(varargin) %#ok<STOUT> error(message('MATLAB:bigdata:array:InvalidIndexingWithEnd', 'MRDIVIDE')); end function obj = horzcat(varargin) obj = cat(2, varargin{:}); end function obj = vertcat(varargin) obj = cat(1, varargin{:}); end function obj = cat(dim, varargin) import matlab.bigdata.internal.util.EndMarker; args = varargin; for idx = 1:numel(args) if ~iIsEndMarker(args{idx}) args{idx} = EndMarker([], [], args{idx}); end end obj = builtin('cat', dim, args{:}); end function obj = plus(A, B) import matlab.bigdata.internal.util.EndMarker; % Ensure numeric args are 'double' - g1372212 A = iMaybeDouble(A); B = iMaybeDouble(B); if iIsEndMarker(A) && iIsEndMarker(B) % No good can come of this - no way to create a valid index by adding together % two indexing expressions that involve END. Of course, for % ordinary MATLAB arrays, you can do this. error(message('MATLAB:bigdata:array:InvalidEndPlusEnd')); else if iIsEndMarker(A) obj = A; incr = B; else obj = B; incr = A; end if ~isscalar(incr) error(message('MATLAB:bigdata:array:InvalidEndPlusNonScalar')); end % Update Offset/ColonForm/AbsoluteValue as appropriate for idx = 1:numel(obj) offset = obj(idx).Offset; colonForm = obj(idx).ColonForm; absValue = obj(idx).AbsoluteValue; if ~isempty(offset) offset = offset + incr; end if ~isempty(colonForm) colonForm(:,[1,3]) = colonForm(:,[1,3]) + incr; end if ~isempty(absValue) absValue = absValue + incr; end obj(idx) = EndMarker(offset, colonForm, absValue); end end end function obj = minus(A, B) % Ensure numeric args are 'double' - g1372212 A = iMaybeDouble(A); B = iMaybeDouble(B); obj = plus(A, uminus(B)); end function obj = colon(A, D, B) if nargin == 2 B = D; D = 1; end if islogical(D) % Mimic the warning issued by MATLAB warning(message('MATLAB:colon:logicalInput')); D = double(D); else D = iMaybeDouble(D); end A = iMaybeDouble(A); B = iMaybeDouble(B); if ~isnumeric(D) error(message('MATLAB:bigdata:array:EndNumericIncrement')); end % Resolve args - this might throw rangeStart = iResolveColonEndpoint(A); % Note that we do simpy extract the first value from D in the case where the % user specified a non-scalar D. rangeIncr = [D(1); NaN]; rangeEnd = iResolveColonEndpoint(B); range = [rangeStart, rangeIncr, rangeEnd]; obj = matlab.bigdata.internal.util.EndMarker([], range); end function tf = isEquivalentToLiteralColon(objs) %TRUE if objs is scalar, and represents '1:end'. tf = false; if isscalar(objs) oneColonEndForm = [1, 1, NaN; NaN, NaN, 0]; tf = isequaln(objs.ColonForm, oneColonEndForm); end end function [tf, n, reverse] = isValidTallEndExpression(objs) % Must represent end-k:end, or end:-1:end-k. n = 0; reverse = false; % First off, check that we don't have any absolute values - they cannot be valid % in combination with END. for idx = 1:numel(objs) if ~isempty(objs(idx).AbsoluteValue) tf = false; return elseif ~isempty(objs(idx).ColonForm) cf = objs(idx).ColonForm; if ~all(isnan(cf(1,[1,3]))) tf = false; return end end end % Use 'resolve' to compute *relative* offsets from the END by feeding it a size % of zero. szVec = [0 0]; dim = 1; relIdxVec = resolve(objs, szVec, dim); relIdxVec = relIdxVec(:); % Now check that it's unit offset ending/beginning at the END. if isempty(relIdxVec) tf = true; reverse = false; n = 0; else d = diff(relIdxVec); tf = (all(d == 1) || all(d == -1)) && max(relIdxVec) == 0; reverse = all(d == -1); n = numel(relIdxVec); end end function [n, reverse] = getTrailingNumRows(obj) [tf, n, reverse] = isValidTallEndExpression(obj); assert(tf); end function absIdxVec = resolve(objs, sz, dim) %RESOLVE resolve an EndMarker into an index vector for the provided chunkSize. resultCell = cell(size(objs)); for idx = 1:numel(objs) obj = objs(idx); szInDim = sz(dim); if ~isempty(obj.ColonForm) cf = obj.ColonForm; if ~isnan(cf(1,1)) A = cf(1,1); else A = szInDim + cf(2,1); end D = cf(1,2); if ~isnan(cf(1,3)) B = cf(1,3); else B = szInDim + cf(2,3); end absIdxVec = A:D:B; elseif ~isempty(obj.Offset) % Simple offset absIdxVec = szInDim + obj.Offset; else absIdxVec = obj.AbsoluteValue; end resultCell{idx} = absIdxVec; end try absIdxVec = cell2mat(resultCell); catch E % Get here if the sizes didn't conform error(message('MATLAB:bigdata:array:SizeMismatchIndexingWithEnd')); end end end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Resolve all numeric and logical inputs to double. function x = iMaybeDouble(x) if isnumeric(x) || islogical(x) x = double(x); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Resolve end-point values for colon operations. Reject all cases where the % end-point is non-scalar (this is different to MATLAB which uses the first % value - but we cannot be sure we know the first value in all cases). % % The return value is a 2-element column vector of [absoluteValue; % relativeValue]. One element is NaN, the other is non-NaN. function x = iResolveColonEndpoint(obj) absValue = NaN; relValue = NaN; if ~isscalar(obj) error(message('MATLAB:bigdata:array:EndScalarColonEndpoints')); end if iIsEndMarker(obj) if ~isempty(obj.Offset) relValue = obj.Offset; elseif ~isempty(obj.AbsoluteValue) absValue = obj.AbsoluteValue; else error(message('MATLAB:bigdata:array:EndScalarColonEndpoints')); end else absValue = obj; end if ~isscalar(absValue) || ~isscalar(relValue) error(message('MATLAB:bigdata:array:EndScalarColonEndpoints')); else x = [absValue; relValue]; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function tf = iIsEndMarker(x) tf = isa(x, 'matlab.bigdata.internal.util.EndMarker'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function s = iFormatEndOffset(offset) if isscalar(offset) if offset > 0 s = sprintf('end+%d', offset); elseif offset < 0 s = sprintf('end%d', offset); else s = 'end'; end else strs = arrayfun(@iFormatEndOffset, offset, ... 'UniformOutput', false); s = ['[', strjoin(strs, ','), ']']; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function s = iFormatOffsetOrNumber(col) if ~isnan(col(1)) s = sprintf('%d', col(1)); else s = iFormatEndOffset(col(2)); end end