e7e8180d3a85ae019613e46ab6c980901368894f
[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 - 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 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 & 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 & 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         it = inttype(a)
59         if ndims(a)>2 then
60             a = serialize_hypermat(a, orien)
61         elseif orien==2
62             a = a.'
63         end
64         // Trivial case
65         if b == [] then
66             ka = 1:size(a,orien);
67             if orien==1
68                 ka = ka'
69             end
70             return
71         end
72         if ndims(b)>2 then
73             b = serialize_hypermat(b, orien)
74         elseif orien==2
75             b = b.'
76         end
77         [a, ka] = unique(a, "r")
78         b = unique(b, "r")
79         [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
80                          [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
81         k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
82         if c($,$)==1
83             k = [k size(c,1)]
84         end
85         ka = ka(kc(k))
86         // a = a(ka,:) // in initial order
87         a = c(k,1:$-1)
88         if orien==2
89             ka = ka'
90             a = a.'
91         end
92     else
93         // by element
94         // ----------
95         [a,ka] = unique(a);
96         na = size(a,"*");
97     
98         b = unique(b(:));
99     
100         [x,k] = gsort([a(:); b], "g", "i");
101         d = find(x(2:$)==x(1:$-1));  //index of common entries in sorted table
102         if d <> [] then
103             k([d;d+1]) = [];
104         end
105     
106         keep = find(k <= na);
107         a = a(k(keep));
108         ka = ka(k(keep));
109     end
110 endfunction
111 // ----------------------------------------------------------------------------
112 function h = serialize_hypermat(h, orien)
113     if orien==1 then
114         dims = 1:ndims(h)
115         dims([1 2]) = [2 1]
116         h = permute(h, dims)
117     end
118     h = matrix(h, size(h,1), -1).'
119 endfunction