1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 // Copyright (C) 2012 - 2016 - Scilab Enterprises
4 // Copyright (C) 2018 - 2020 - Samuel GOUGEON
6 // This file is hereby licensed under the terms of the GNU GPL v2.0,
7 // pursuant to article 5.3.4 of the CeCILL v.2.1.
8 // This file was originally licensed under the terms of the CeCILL v2.1,
9 // and continues to be available under such terms.
10 // For more information, see the COPYING file which you should have received
11 // along with this program.
13 function [x, ki, ko, nb] = unique(x, varargin)
14 // extract unique components of a vector, matrix, or hypermatrix
15 // varargin : orient=1|2|"r"|"c", "uniqueNan", "keepOrder"
18 // * 2019 - S. Gougeon :
19 // - add uniqueNan option: http://bugzilla.scilab.org/15522
20 // - add keepOrder option: http://bugzilla.scilab.org/15795
21 // - add nb output option: http://bugzilla.scilab.org/8418
22 // * 2020 - S. Gougeon :
23 // - add ku output indices: http://bugzilla.scilab.org/16337
28 newInf = [] // init Inf substitute in case of "uniqueNan" and or(x==%inf)
34 // CHECKING INPUT ARGUMENTS
35 // ------------------------
37 i = 2; // index of the current input argument
43 if typeof(a)=="string"
60 msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
61 error(msprintf(msg, "unique", i, "1,2,""r"",""c"",""keepOrder"",""uniqueNan"""))
66 if or(orient==["r" "c"]) & ndims(x)>2 then
67 msg = _("%s: Argument #%d: ''%s'' not allowed for an hypermatrix.\n")
68 error(msprintf(msg, "unique", 2, orient))
71 while size(in)>0 & i<5 then
73 if typeof(a)=="string"
82 msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
83 error(msprintf(msg, "unique", i, """keepOrder"",""uniqueNan"""))
88 uniqueNan = uniqueNan & or(type(x)==[1 5])
91 if size(x, orient)==1 then
98 [x, newInf] = uniqueProcessNan(x, [], "removeNan")
100 getK = argn(1) > 1 | keepOrder
106 return // ki, ko, nb are already []. x is [] or sparse([])
111 areComplex = or(type(x)==[1 5]) && ~isreal(x, 0)
116 [x,ki] = gsort(x,"g",["i" "i"], list(abs, atan));
118 [x,ki] = gsort(x,"g","i");
120 keq = x(2:$) == x(1:$-1);
123 ko(ki) = cumsum(~[%F ; keq(:)])
129 nb = [0 find(~keq) size(x,"*")]
130 nb = nb(2:$) - nb(1:$-1)
135 if keq <> [] then keq = keq + 1; end
140 x = gsort(x,"g",["d" "d"], list(abs, atan));
142 x = gsort(x,"g","d");
145 x( find(x(2:$) == x(1:$-1)) ) = [];
147 if sx(1) > 1 | length(sx) > 2
154 if orient==2 | orient=="c" then
159 [x,ki] = gsort(x,"lr",["i" "i"], list(abs, atan));
161 [x,ki] = gsort(x,"lr","i");
163 keq = and(x(2:$,:) == x(1:$-1,:),"c")
165 ko(ki) = cumsum(~[%F ; keq(:)])
168 nb = [0 find(~keq) size(x,1)]
169 nb = nb(2:$) - nb(1:$-1)
174 if keq <> [] then keq = keq + 1;end
179 x = gsort(x,"lr",["i" "i"], list(abs, atan));
181 x = gsort(x,"lr","i");
183 x( find(and(x(2:$,:) == x(1:$-1,:),"c")),:) = [];
185 if orient==2 | orient=="c" then
187 ki = matrix(ki, 1, -1)
194 x = uniqueProcessNan(x, newInf, "restoreNan")
198 [ki, kk] = gsort(ki,"g","i")
209 [?, kk2] = gsort(kk,"g","i")
215 // -------------------------------------------------------------------
217 // To consider Nan mutually equal, we replace all of them with a "regular" substitute.
218 // Since Nan are sorted as > Inf, we must use anyway Inf as the Nan substitute.
219 // If the original array have already some Inf, we must priorly replace them with
220 // a decimal greater than the finite maximum of the array values.
221 // After processing, we restore Inf => Nan (, and maxNum => Inf).
223 function [x, newInf] = uniqueProcessNan(x, newInf, way)
225 if way=="removeNan" & or(isnan(x)) then
231 m = max([1 max(x(~b))])
255 elseif way=="restoreNan"