* Bug 15967 fixed: setdiff(a,[],..) had troubles
[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
20     rhs = argn(2);
21
22     // CHECKING INPUT ARGUMENTS
23     // ========================
24     if rhs < 2 | rhs > 3 then
25         msg = gettext("%s: Wrong number of input argument(s): %d or %d expected.\n");
26         error(msprintf(msg, "setdiff", 2, 3));
27     end
28     // Trivial case _whatever is b_
29     if isempty(a)
30         ka = []
31         return
32     end
33     // orien
34     if ~isdef("orien","l") then
35         orien = 0
36     elseif orien~="r" & orien~="c" & orien~=1 & orien~=2
37         msg = gettext("%s: Argument #%d: Must be in the set {%s}.\n");
38         error(msprintf(msg, "setdiff", 3, "''r'',''c'',1,2"));
39     elseif orien=="c"
40         orien = 2
41     elseif orien=="r"
42         orien = 1
43     end
44     if orien==1 & ~isempty(b) & size(a,2)~=size(b,2) then
45         msg = _("%s: Arguments #%d and #%d: Same numbers of columns expected.\n")
46         error(msprintf(msg, "setdiff", 1, 2))
47     end
48     if orien==2 & ~isempty(b) & size(a,1)~=size(b,1) then
49         msg = _("%s: Arguments #%d and #%d: Same numbers of rows expected.\n")
50         error(msprintf(msg, "setdiff", 1, 2))
51     end
52
53     // PROCESSING
54     // ==========
55     // "r" or "c"
56     // ----------
57     if orien then
58         if ndims(a) > 2 then
59             a = serialize_hypermat(a, orien)
60         end
61         if ndims(b) > 2 then
62             b = serialize_hypermat(b, orien)
63         end
64         [a, ka] = unique(a, orien)
65         if isempty(b)
66             return
67         end
68         it = inttype(a)
69         b = unique(b, orien)
70         if orien==2
71             a = a.'
72             b = b.'
73         end
74         [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
75                          [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
76         k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
77         if c($,$)==1
78             k = [k size(c,1)]
79         end
80         ka = ka(kc(k))
81         // a = a(ka,:) // in initial order
82         a = c(k,1:$-1)
83         if orien==2
84             ka = matrix(ka, 1, -1)
85             a = a.'
86         end
87     else
88         // by element
89         // ----------
90         [a,ka] = unique(a);
91         na = size(a,"*");
92         if isempty(b)
93             return
94         end
95
96         b = unique(b(:));
97
98         [x,k] = gsort([a(:); b], "g", "i");
99         d = find(x(2:$)==x(1:$-1));  //index of common entries in sorted table
100         if d <> [] then
101             k([d;d+1]) = [];
102         end
103
104         keep = find(k <= na);
105         a = a(k(keep));
106         ka = ka(k(keep));
107     end
108 endfunction
109 // ----------------------------------------------------------------------------
110 function h = serialize_hypermat(h, orien)
111     if orien==1 then
112         dims = 1:ndims(h)
113         dims([1 2]) = [2 1]
114         h = permute(h, dims)
115         h = matrix(h, size(h,1), -1).'
116     else
117         h = matrix(h, size(h,1), -1)
118     end
119 endfunction