uniquetol

PURPOSE ^

C = uniquetol(A,TOL): unique values in A using tolerance TOL.

SYNOPSIS ^

function out = uniquetol(in, tol, varargin)

DESCRIPTION ^

 C = uniquetol(A,TOL):  unique values in A using tolerance TOL.
 For recent versions (>=2015a) call built in function. Otherwise
 find a alternate solve, using either different matlab builtin
 functions, or the uniquetol provided by code (C) Siyi Deng 2010.

 Only provides the functions of 
   C = uniquetol(A,tol,'ByRows',true,'DataScale',1);
 TODO:
 -  Remove this function once octave has uniquetol
 Notes: the problem of a stable defintion of
 uniquetol is unsolved. Worse, Matlab doesn't
 define which value it chooses. See:
 https://stackoverflow.com/questions/46101271/what-does-uniquetol-do-exactly

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function out = uniquetol(in, tol, varargin)
0002 % C = uniquetol(A,TOL):  unique values in A using tolerance TOL.
0003 % For recent versions (>=2015a) call built in function. Otherwise
0004 % find a alternate solve, using either different matlab builtin
0005 % functions, or the uniquetol provided by code (C) Siyi Deng 2010.
0006 %
0007 % Only provides the functions of
0008 %   C = uniquetol(A,tol,'ByRows',true,'DataScale',1);
0009 % TODO:
0010 % -  Remove this function once octave has uniquetol
0011 % Notes: the problem of a stable defintion of
0012 % uniquetol is unsolved. Worse, Matlab doesn't
0013 % define which value it chooses. See:
0014 % https://stackoverflow.com/questions/46101271/what-does-uniquetol-do-exactly
0015 
0016 
0017 % (C) Andy Adler 2015 Licenced under GPL v2 or v3
0018 % $Id: uniquetol.m 6369 2022-05-05 15:08:30Z aadler $
0019 
0020 if ischar(in) && strcmp(in,'UNIT_TEST'); do_unit_test; return; end
0021 
0022 DEBUG = eidors_debug('query','eidors:uniquetol');
0023 
0024 if DEBUG==1 || exist('uniquetol','builtin')
0025    if DEBUG;   disp('using builtin uniquetol'); end
0026    out = builtin('uniquetol',in, tol, varargin{:});
0027    return;
0028 end
0029 
0030 % Now we provide a backup, but only if byrows and Datascale
0031 if length(varargin)<4
0032    error('ByRows and DataScale must be provided')
0033 end
0034 for i=1:2:length(varargin);
0035    switch varargin{i}
0036      case 'ByRows'
0037        if ~varargin{i+1};   error('Only support the ByRows option'); end
0038      case 'DataScale'
0039        if varargin{i+1}~=1; error('DataScale must by 1'); end
0040      otherwise 
0041        error('Option %s not supported',varargin{i});
0042    end
0043 end
0044 
0045 out = eidors_uniquetol(in, tol);
0046 
0047 
0048 %Fom code by
0049 % Siyi Deng; 03-19-2010; 05-15-2010; 10-29-2010;
0050 
0051 % Licence:
0052 % Copyright (c) 2010, Siyi Deng
0053 % All rights reserved.
0054 %
0055 % Redistribution and use in source and binary forms, with or without
0056 % modification, are permitted provided that the following conditions are
0057 % met:
0058 %
0059 %     * Redistributions of source code must retain the above copyright
0060 %       notice, this list of conditions and the following disclaimer.
0061 %     * Redistributions in binary form must reproduce the above copyright
0062 %       notice, this list of conditions and the following disclaimer in
0063 %       the documentation and/or other materials provided with the distribution
0064 %
0065 % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0066 % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0067 % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0068 % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0069 % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0070 % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0071 % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0072 % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0073 % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0074 % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0075 % POSSIBILITY OF SUCH DAMAGE.
0076 function out = eidors_uniquetol(in, tol)
0077 % first run unique
0078 out = unique(in,'rows');
0079 
0080 % all pairwise combinations
0081 nRows = size(out,1);
0082 if nRows <= 1
0083    return
0084 end
0085 idx = nchoosek(1:nRows,2);
0086 
0087 % compare each column individually
0088 d = out(idx(:,1),:) - out(idx(:,2),:);
0089 d = abs(d) <= tol;
0090 
0091 same = all(d,2);
0092 
0093 legacy = false; try unique([],'legacy'); catch, legacy = true; end
0094    
0095 % replace each equal row with the first match
0096 if legacy
0097    [~,ii] = unique(idx(same,2),'first');
0098 else
0099    [~,ii] = unique(idx(same,2));
0100 end
0101 jj = find(same);
0102 ii = jj(ii);
0103 
0104 out(idx(ii,2),:) = out(idx(ii,1),:);
0105 
0106 % run unique to eliminate the now exactly matching rows
0107 out = unique(out,'rows');
0108       
0109 
0110 
0111 
0112 
0113 function [z,ii,jj] = uniquetol_repl(x,tol,varargin)
0114 %UNIQUETOL Unique element within a tolerance.
0115 %   [Y,I,J] = UNIQUETOL(X,TOL) is very similar to UNIQUE, but allows an
0116 %   additional tolerance input, TOL. TOL can be taken as the total absolute
0117 %   difference between similar elements. TOL must be a none negative
0118 %   scalar. If not provided, TOL is assumed to be 0, which makes UNIQUETOL
0119 %   identical to UNIQUE.
0120 %
0121 %   UNIQUETOL(...,'ROWS')
0122 %   UNIQUETOL(...,'FIRST')
0123 %   UNIQUETOL(...,'LAST')
0124 %   These expressions are identical to the UNIQUE counterparts.
0125 %
0126 %   See also UNIQUE.
0127 
0128 
0129 if size(x,1) == 1, x = x(:); end
0130 if nargin < 2 || isempty(tol) || tol == 0
0131     [z,ii,jj] = unique(x,varargin{:});
0132     return;
0133 end
0134 [y,ii,jj] = unique(x,varargin{:});
0135 if size(x,2) > 1
0136     [~,ord] = sort(sum(x.^2,1),2,'descend');
0137     [y,io] = sortrows(y,ord);
0138     [~,jo] = sort(io);
0139     ii = ii(io);
0140     jj = jo(jj);
0141 end
0142 d = sum(abs(diff(y,1,1)),2);
0143 
0144 isTol = [true;d > tol];
0145 z = y(isTol,:);
0146 bin = cumsum(isTol); % [n,bin] = histc(y,z);
0147 jj = bin(jj);
0148 ii = ii(isTol);
0149 
0150 % UNIQUETOL;
0151    
0152 function do_unit_test
0153    testvec{1} = [1 2; 1.06 2; 1.1 2; 1.1 2.03];
0154    testvec{2} = [ ...
0155    -0.488223373148967243473350663407, ...
0156    -0.488223373148967243473350663407, ...
0157    -0.488223373148967243473350663407, ...
0158    -0.488223373148967243473350663407, ...
0159    -0.488223373148967243473350663407, ...
0160    -0.488223373148967243473350663407;
0161    -0.999999999999999666933092612453, ...
0162    -0.999999999999999888977697537484, ...
0163    -0.999999999999999888977697537484, ...
0164    -0.999999999999999888977697537484, ...
0165    -0.999999999999999888977697537484, ...
0166    -0.905678339894304240687006313237;
0167    -0.232963663178817920185181833403, ...
0168    -0.232963663178818003451908680290, ...
0169    -0.116481831589409029481529955774, ...
0170    -0.232963663178818086718635527177, ...
0171    -0.116481831589409043359317763588, ...
0172    -0.156131398552380479261003642932]';
0173    testvec{3} = testvec{2}';
0174    testvec{4} = [100,200;106,200;112,202;113,205;113,200;113,201;113,204;113,204;110,200;110,203]/100;
0175 
0176 
0177    for i=1:length(testvec)
0178      eidors_msg('TEST%d============',i,1);
0179      x = testvec{i};
0180       for tol = logspace(-4,1,6);
0181          uu = uniquetol(x,tol,'ByRows',true,'DataScale',1);
0182          ur = uniquetol_repl(x,tol,'rows','first');
0183          ue = eidors_uniquetol(x,tol);
0184          fprintf('Testing for tol=%f\n',tol);
0185 %        unit_test_cmp('uu=ur (not used)',uu,ur);
0186          unit_test_cmp('um=ue           ',uu,ue,tol/2);
0187       end
0188    end

Generated on Fri 30-Dec-2022 19:44:54 by m2html © 2005