* Bug 15737 fixed: setdiff() dit not support complex numbers
[scilab.git] / scilab / modules / elementary_functions / macros / setdiff.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) INRIA
3 // Copyright (C) DIGITEO - 2011 - Allan CORNET
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 // Copyright (C) 2018 - 2019 - Samuel GOUGEON
6 //
7 // This file is hereby licensed under the terms of the GNU GPL v2.0,
8 // pursuant to article 5.3.4 of the CeCILL v.2.1.
9 // This file was originally licensed under the terms of the CeCILL v2.1,
10 // and continues to be available under such terms.
11 // For more information, see the COPYING file which you should have received
12 // along with this program.
13
14 function [a, ka] = setdiff(a, b, orien)
15     // returns a values which are not in b
16
17     // History:
18     // * 2018 - S. Gougeon : orien="r"|"c" added, including the hypermat case
19     // * 2019 - S. Gougeon : complex numbers supported
20
21     [lhs, rhs] = argn();
22
23     // CHECKING INPUT ARGUMENTS
24     // ========================
25     if rhs < 2 | rhs > 3 then
26         msg = gettext("%s: Wrong number of input argument(s): %d or %d expected.\n");
27         error(msprintf(msg, "setdiff", 2, 3));
28     end
29     // Trivial case _whatever is b_
30     if isempty(a)
31         ka = []
32         return
33     end
34     // orien
35     if ~isdef("orien","l") then
36         orien = 0
37     elseif orien~="r" & orien~="c" & orien~=1 & orien~=2
38         msg = gettext("%s: Argument #%d: Must be in the set {%s}.\n");
39         error(msprintf(msg, "setdiff", 3, "''r'',''c'',1,2"));
40     elseif orien=="c"
41         orien = 2
42     elseif orien=="r"
43         orien = 1
44     end
45     if orien==1 & ~isempty(b) & size(a,2)~=size(b,2) then
46         msg = _("%s: Arguments #%d and #%d: Same numbers of columns expected.\n")
47         error(msprintf(msg, "setdiff", 1, 2))
48     end
49     if orien==2 & ~isempty(b) & size(a,1)~=size(b,1) then
50         msg = _("%s: Arguments #%d and #%d: Same numbers of rows expected.\n")
51         error(msprintf(msg, "setdiff", 1, 2))
52     end
53
54     // PROCESSING
55     // ==========
56     Complexes = (type(a)==1 && ~isreal(a)) | (type(b)==1 && ~isreal(b));
57     // "r" or "c"
58     // ----------
59     if orien then
60         if ndims(a) > 2 then
61             a = serialize_hypermat(a, orien)
62         end
63         if ndims(b) > 2 then
64             b = serialize_hypermat(b, orien)
65         end
66         if lhs > 1
67             [a, ka] = unique(a, orien)
68             if isempty(b)
69                 return
70             end
71             it = inttype(a)
72             b = unique(b, orien)
73             if orien==2
74                 a = a.'
75                 b = b.'
76             end
77             if Complexes
78                 [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
79                                  [b iconvert(ones(b(:,1))*2,it)]], ..
80                                 "lr", ["i" "i"], list(abs, atan))
81             else
82                 [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
83                                  [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
84             end
85             k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
86             if c($,$)==1
87                 k = [k size(c,1)]
88             end
89             ka = ka(kc(k))
90             // a = a(ka,:) // in initial order
91             a = c(k,1:$-1)
92             if orien==2
93                 ka = matrix(ka, 1, -1)
94                 a = a.'
95             end
96         else
97             a = unique(a, orien)
98             if isempty(b)
99                 return
100             end
101             it = inttype(a)
102             b = unique(b, orien)
103             if orien==2
104                 a = a.'
105                 b = b.'
106             end
107             if Complexes
108                 c = gsort([[a iconvert(ones(a(:,1)),it)] ;
109                            [b iconvert(ones(b(:,1))*2,it)]], ..
110                            "lr", ["i" "i"], list(abs, atan))
111             else
112                 c = gsort([[a iconvert(ones(a(:,1)),it)] ;
113                            [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
114             end
115             k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
116             if c($,$)==1
117                 k = [k size(c,1)]
118             end
119             // a = a(ka,:) // in initial order
120             a = c(k,1:$-1)
121             if orien==2
122                 a = a.'
123             end
124         end
125
126     else
127         // by element
128         // ----------
129         if lhs > 1
130             [a,ka] = unique(a);
131         else
132             a = unique(a);
133         end
134         na = size(a,"*");
135         if isempty(b)
136             return
137         end
138         b = unique(b(:));
139         if Complexes
140             [x,k] = gsort([a(:); b], "g", ["i" "i"], list(abs, atan));
141         else
142             [x,k] = gsort([a(:); b], "g", "i");
143         end
144         d = find(x(2:$)==x(1:$-1));  //index of common entries in sorted table
145         if d <> [] then
146             k([d;d+1]) = [];
147         end
148
149         keep = find(k <= na);
150         a = a(k(keep));
151         if lhs > 1
152             ka = ka(k(keep))
153         end
154     end
155 endfunction
156 // ----------------------------------------------------------------------------
157 function h = serialize_hypermat(h, orien)
158     if orien==1 then
159         dims = 1:ndims(h)
160         dims([1 2]) = [2 1]
161         h = permute(h, dims)
162         h = matrix(h, size(h,1), -1).'
163     else
164         h = matrix(h, size(h,1), -1)
165     end
166 endfunction