* Bugs 16340 16451 fixed: setdiff('','') & 'c'|'r' with strings. + booleans + sparse 26/21426/19
Samuel GOUGEON [Mon, 2 Mar 2020 18:37:55 +0000 (19:37 +0100)]
  http://bugzilla.scilab.org/16340
  http://bugzilla.scilab.org/16451 : extension to booleans
  http://bugzilla.scilab.org/15868 : extension to sparse matrices

Change-Id: I6299184cf25918c3afadc1082c479af27994a882

scilab/CHANGES.md
scilab/modules/elementary_functions/help/en_US/setoperations/setdiff.xml
scilab/modules/elementary_functions/help/ru_RU/setoperations/setdiff.xml
scilab/modules/elementary_functions/macros/setdiff.sci
scilab/modules/elementary_functions/tests/nonreg_tests/bug_16340.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/setdiff.tst
scilab/modules/elementary_functions/tests/unit_tests/setdiff_boolean.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/setdiff_sparse.tst [new file with mode: 0644]

index 6f7f44d..f0b7113 100644 (file)
@@ -217,6 +217,7 @@ Feature changes and additions on 6.1.1
 * `clock` now returns the milliseconds, the time zone, and the daylight saving time.
 * `mapsound` upgraded to have a colormap argument
 * `mprintf`, `msprintf` and `mfprintf` can now print input booleans, as `0`|`1` or as `T`|`F`.
+* `setdiff` now supports input booleans and sparse matrices (boolean or numeric).
 
 Help pages:
 -----------
@@ -336,6 +337,7 @@ Bug Fixes
 * [#15280](https://bugzilla.scilab.org/15280): `gsort` was unable to sort any hypermatrix along dimensions > "r"|"c".
 * [#15839](https://bugzilla.scilab.org/15839): `gsort`: the only sparse possible input were real or complex vectors, and only with the `g` method.
 * [#15842](https://bugzilla.scilab.org/15842): `unique` could not process 2D sparse matrices.
+* [#15868](https://bugzilla.scilab.org/15868): `setdiff(s,s2)` yielded an error when `s` or/and `s2` is sparse encoded.
 * [#15954](https://bugzilla.scilab.org/15954): `mfile2sci` abusively added a 6 lines `mode(0); ieee(1)` header to every converted file.
 * [#16069](https://bugzilla.scilab.org/16069): [].figure_name crashes Scilab.
 * [#16106](https://bugzilla.scilab.org/16106): Xcos sciblk4 user-defined blocks did not handle opar and odstate/oz correctly.
@@ -347,6 +349,7 @@ Bug Fixes
 * [#16274](https://bugzilla.scilab.org/16274): assert_checkequal() did not considered equal matching Nan or void elements in (nested) containers.
 * [#16297](https://bugzilla.scilab.org/16297): After function test(), e={}, endfunction; macr2tree(test)  crashes Scilab.
 * [#16337](https://bugzilla.scilab.org/16337): The 3rd output of `[U,km,ku] = unique(..)` was not implemented.
+* [#16340](https://bugzilla.scilab.org/16340): `setdiff("","")` produced `""` instead of `[]`. The `"c"` and `"r"` options yielded an error for string inputs. Input arguments were poorly checked.
 * [#16342](https://bugzilla.scilab.org/16342): `strcat()` was much slower in Scilab 6.0.2.
 * [#16350](https://bugzilla.scilab.org/16350): in if/while conditions, the empty sparse boolean was considered as TRUE.
 * [#16358](https://bugzilla.scilab.org/16358): `isdef([],..)` yielded an error instead of returning [].
@@ -370,6 +373,7 @@ Bug Fixes
 * [#16445](https://bugzilla.scilab.org/16445): `colorbar(..)` ignored how to guess `umin` and `umax` for a Champ object (with .colored="on").
 * [#16449](https://bugzilla.scilab.org/16449): Insertion of implicit vector in Cell was crahsing Scilab
 * [#16450](https://bugzilla.scilab.org/16450): Concatenating encoded integers with decimal or complex numbers was not possible.
+* [#16451](https://bugzilla.scilab.org/16451): `setdiff(a,b,"r"|"c")` with a and b boolean yielded an error.
 * [#16452](https://bugzilla.scilab.org/16452): `setdiff(sparse([1 3 0 2]), sparse([3 7]))` missed returning 0, and wrongly returned 3.
 * [#16454](https://bugzilla.scilab.org/16454): `gsort` yielded an error when sorting any sparse vector including some NaN.
 * [#16458](https://bugzilla.scilab.org/16458): `mean()` did not handle sparse numerical matrices.
index 6df05ff..248adf4 100644 (file)
                 <term>a, b</term>
                 <listitem>
                     <para>
-                        vectors, matrices or hypermatrices of real or complex numbers, or encoded
-                        integers, or strings. Both must have the same data types (and integer types).
+                        vectors, matrices or hypermatrices of real or complex numbers, encoded
+                        integers, booleans, or strings. Sparse-encoded inputs are accepted.
+                        Both <varname>a</varname> and <varname>b</varname> must have the same
+                        data type (and integer type), but may mix dense and sparse encoding.
                     </para>
                     <para>
-                        If the option <literal>orien="r"</literal> is used, <literal>a</literal>
-                        and <literal>b</literal> must have the same number of columns.
+                        If the option <literal>orien="r"</literal> is used, <varname>a</varname>
+                        and <varname>b</varname> must have the same number of columns.
                         If the <literal>orien="c"</literal> is used, they must have the same
                         number of rows.
                     </para>
                     <itemizedlist>
                         <listitem>
                             <literal>"r"</literal>: rows of
-                            <literal>a</literal> are searched among <literal>b</literal> ones.
+                            <varname>a</varname> are searched among <varname>b</varname> ones.
                         </listitem>
                         <listitem>
                             <literal>"c"</literal>: columns of
-                            <literal>a</literal> are searched among <literal>b</literal> ones.
+                            <varname>a</varname> are searched among <varname>b</varname> ones.
                         </listitem>
                         <listitem>
-                            no orien: elements of <literal>a</literal> are searched among
-                            <literal>b</literal> ones.
+                            no orien: elements of <varname>a</varname> are searched among
+                            <varname>b</varname> ones.
                         </listitem>
                     </itemizedlist>
                 </listitem>
             <varlistentry>
                 <term>v</term>
                 <listitem>
+                    Array with <varname>a</varname>'s data type and encoding:
                     <itemizedlist>
                         <listitem>
-                            sorted vector of <literal>a</literal>'s components that are not in
-                            <literal>b</literal>.
+                            sorted vector of <varname>a</varname>'s components that are not in
+                            <varname>b</varname>.
                         </listitem>
                         <listitem>
-                            <literal>orien="r"</literal>: matrix of rows of <literal>a</literal>
-                            that are not in <literal>b</literal>, sorted in lexicographic order.
+                            <literal>orien="r"</literal>: matrix of rows of <varname>a</varname>
+                            that are not in <varname>b</varname>, sorted in lexicographic order.
                         </listitem>
                         <listitem>
-                            <literal>orien="c"</literal>: matrix of columns of <literal>a</literal>
-                            that are not in <literal>b</literal>, sorted in lexicographic order.
+                            <literal>orien="c"</literal>: matrix of columns of <varname>a</varname>
+                            that are not in <varname>b</varname>, sorted in lexicographic order.
                         </listitem>
                     </itemizedlist>
                 </listitem>
@@ -92,7 +95,7 @@
                 <term>ka</term>
                 <listitem>
                     <para>
-                        vector of linear indices of selected  <literal>a</literal>'s components,
+                        vector of linear indices of selected  <varname>a</varname>'s components,
                         rows, or columns, such that
                         <itemizedlist>
                             <listitem>
         <title>Description</title>
         <para>
             <literal>setdiff(a, b,..)</literal> computes and returns the elements or rows or columns
-            of <literal>a</literal> that are NOT in <literal>b</literal>.
+            of <varname>a</varname> that are NOT in <varname>b</varname>.
         </para>
         <para>
-            All duplicates (elements or rows or columns) are removed from <literal>a</literal> and
-            from <literal>b</literal> before processing.
+            All duplicates (elements or rows or columns) are removed from <varname>a</varname> and
+            from <varname>b</varname> before processing.
         </para>
         <para>
-            If <literal>a</literal> is an hypermatrix and the <literal>"r"</literal> option is used,
-            <literal>a</literal> is replaced with the matrix of all its rows over all its higher
+            If <varname>a</varname> is an hypermatrix and the <literal>"r"</literal> option is used,
+            <varname>a</varname> is replaced with the matrix of all its rows over all its higher
             dimensions, before processing.
-            Same thing if <literal>b</literal> is an hypermatrix.
-            If the <literal>"c"</literal> option is used, <literal>a</literal> or/and
+            Same thing if <varname>b</varname> is an hypermatrix.
+            If the <literal>"c"</literal> option is used, <varname>a</varname> or/and
             <literal>"b"</literal> are replaced with the respective matrices of all their columns.
         </para>
         <para>
             The format of results is presented in the following table, according to the shape of
-            <literal>a</literal> and the <literal>orien</literal> option. In all cases, if all
-            entities of <literal>a</literal> are in <literal>b</literal>,
-            <literal>[]</literal> is returned for <literal>v</literal> as for <literal>ka</literal>:
+            <varname>a</varname> and the <varname>orien</varname> option. In all cases, if all
+            entities of <varname>a</varname> are in <varname>b</varname>,
+            <literal>[]</literal> is returned for <varname>v</varname> as for <varname>ka</varname>:
             <table>
                 <tr>
                     <th align="right">orien →</th>
             </table>
         </para>
         <para>
-            <literal>v</literal> and <literal>ka</literal> become empty <literal>[]</literal>
-            if <literal>a</literal> is empty (whatever is <literal>b</literal>), or if all
-            <literal>a</literal> elements are in <literal>b</literal>.
+            <varname>v</varname> and <varname>ka</varname> become empty
+            if <varname>a</varname> is empty (whatever is <varname>b</varname>), or if all
+            <varname>a</varname> elements are in <varname>b</varname>.
+        </para>
+        <para>
+            For booleans, <literal>setdiff(…)</literal> is useful mainly with the "r" or "c" options.
         </para>
     </refsection>
     <refsection>
@@ -317,7 +323,13 @@ r, k
             <revision>
                 <revnumber>6.1.0</revnumber>
                 <revdescription>
-                    Complex numbers are now accepted.
+                    Extension to complex numbers.
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Boolean inputs and sparse inputs (boolean or numeric) are now accepted.
                 </revdescription>
             </revision>
         </revhistory>
index 742bc24..4e21d1d 100644 (file)
                 <listitem>
                     <para>
                         векторы, матрицы или гиперматрицы действительных или комплексных чисел,
-                        или закодированные целые числа, или строки.
-                        Оба должны иметь одинаковые типы данных (или типы целых чисел).
+                        закодированные целые числа, логические значения или строки.
+                        Допускаются закодированные разрежённые входные данные.
+                        Как <varname>a</varname> так и <varname>b</varname> должны иметь одинаковые
+                        типы данных (или типы целых чисел), но можно смешивать плотные и разрежённые.
                     </para>
                     <para>
                         Если используется опция <literal>orien="r"</literal>, то
-                        <literal>a</literal> и <literal>b</literal> должны иметь одинаковое
+                        <varname>a</varname> и <varname>b</varname> должны иметь одинаковое
                         количество столбцов. Если используется <literal>orien="c"</literal>, то
                         они должны иметь одинаковое количество строк.
                     </para>
                     направленная обработка:
                     <itemizedlist>
                         <listitem>
-                            <literal>"r"</literal>: строки из <literal>a</literal> ищутся среди
-                            строк в <literal>b</literal>.
+                            <literal>"r"</literal>: строки из <varname>a</varname> ищутся среди
+                            строк в <varname>b</varname>.
                         </listitem>
                         <listitem>
-                            <literal>"c"</literal>: столбцы из <literal>a</literal> ищутся среди
-                            столбцов в <literal>b</literal>.
+                            <literal>"c"</literal>: столбцы из <varname>a</varname> ищутся среди
+                            столбцов в <varname>b</varname>.
                         </listitem>
                         <listitem>
-                            <varname>orien</varname> не указано: элементы из <literal>a</literal>
-                            ищутся среди элементов <literal>b</literal>.
+                            <varname>orien</varname> не указано: элементы из <varname>a</varname>
+                            ищутся среди элементов <varname>b</varname>.
                         </listitem>
                     </itemizedlist>
                 </listitem>
             <varlistentry>
                 <term>v</term>
                 <listitem>
+                    Массив с типом данных как у <varname>a</varname> и кодированный:
                     <itemizedlist>
                         <listitem>
-                            сортированный вектор из компонентов <literal>a</literal>, которые
-                            отсутствуют в <literal>b</literal>.
+                            сортированный вектор из компонентов <varname>a</varname>, которые
+                            отсутствуют в <varname>b</varname>.
                         </listitem>
                         <listitem>
-                            <literal>orien="r"</literal>: матрица строк из <literal>a</literal>,
-                            которые отсутствуют в <literal>b</literal>, отсортированный в
+                            <literal>orien="r"</literal>: матрица строк из <varname>a</varname>,
+                            которые отсутствуют в <varname>b</varname>, отсортированный в
                             лексикографическом порядке.
                         </listitem>
                         <listitem>
                             <literal>orien="c"</literal>: матрица столбцов из
-                            <literal>a</literal>, которые отсутствуют в <literal>b</literal>,
+                            <varname>a</varname>, которые отсутствуют в <varname>b</varname>,
                             отсортированный в лексикографическом порядке.
                         </listitem>
                     </itemizedlist>
@@ -96,7 +99,7 @@
                 <listitem>
                     <para>
                         вектор линейный индексов выбранных элементов, строк, столбцов из
-                        <literal>a</literal> таких, что
+                        <varname>a</varname> таких, что
                         <itemizedlist>
                             <listitem>
                                 <literal>v = a(ka)</literal> либо
         <title>Описание</title>
         <para>
             <literal>setdiff(a, b,..)</literal> вычисляет и возвращает элементы либо строк либо
-            столбцов из <literal>a</literal> которые ОТСУТСТВУЮТ в <literal>b</literal>.
+            столбцов из <varname>a</varname>, которые ОТСУТСТВУЮТ в <varname>b</varname>.
         </para>
         <para>
-            Все дупликаты (элементы или строк или столбцов) удаляются из <literal>a</literal> и
-            из <literal>b</literal> перед обработкой.
+            Все дупликаты (элементы или строк или столбцов) удаляются из <varname>a</varname> и
+            из <varname>b</varname> перед обработкой.
         </para>
         <para>
-            Если <literal>a</literal> - гиперматрица и используется опция <literal>"r"</literal>,
-            то перед обработкой <literal>a</literal> заменяется матрицей, состоящией из строк по
+            Если <varname>a</varname> - гиперматрица и используется опция <literal>"r"</literal>,
+            то перед обработкой <varname>a</varname> заменяется матрицей, состоящией из строк по
             всем своим более высоким размерностям. То же самое и в случае, если
-            <literal>b</literal> является гиперматрицей. Если исползуется опция
-            <literal>"c"</literal>, то <literal>a</literal> или/и <literal>"b"</literal>
+            <varname>b</varname> является гиперматрицей. Если исползуется опция
+            <literal>"c"</literal>, то <varname>a</varname> или/и <literal>"b"</literal>
             заменяются соответствующими матрицами, состоящими из всех своих столбцов.
         </para>
         <para>
             Формат результатов представлен в следующей таблице, в соответствии с формой
-            <literal>a</literal> и опцией <literal>orien</literal>. Во всех случаях, если все
-            элементы <literal>a</literal> находятся в <literal>b</literal>, возвращается
-            <literal>[]</literal> для <literal>v</literal> как для <literal>ka</literal>:
+            <varname>a</varname> и опцией <varname>orien</varname>. Во всех случаях, если все
+            элементы <varname>a</varname> находятся в <varname>b</varname>, возвращается
+            <literal>[]</literal> для <varname>v</varname> как для <varname>ka</varname>:
             <table>
                 <tr>
                     <th align="right">orien →</th>
             </table>
         </para>
         <para>
-            <literal>v</literal> и <literal>ka</literal> становятся пустыми
-            <literal>[]</literal>, если <literal>a</literal> пуста (либо <literal>b</literal>),
-            или все элементы <literal>a</literal> находятся в <literal>b</literal>.
+            <varname>v</varname> и <varname>ka</varname> становятся пустыми
+            <literal>[]</literal>, если <varname>a</varname> пуста (либо <varname>b</varname>),
+            или все элементы <varname>a</varname> находятся в <varname>b</varname>.
+        </para>
+        <para>
+            Для логических значений, <literal>setdiff(…)</literal> полезна главным образом с опциями
+            <literal>"r"</literal> или <literal>"c"</literal>.
         </para>
     </refsection>
     <refsection>
@@ -314,6 +321,12 @@ r, k
                     Теперь допускаются комплексные числа.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Теперь допускаются логические и разрежённые (логические или числовые) входные данные.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index 0ddf120..3520687 100644 (file)
@@ -2,7 +2,7 @@
 // Copyright (C) INRIA
 // Copyright (C) DIGITEO - 2011 - Allan CORNET
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
-// Copyright (C) 2018 - 2019 - Samuel GOUGEON
+// Copyright (C) 2018 - 2020 - Samuel GOUGEON
 //
 // This file is hereby licensed under the terms of the GNU GPL v2.0,
 // pursuant to article 5.3.4 of the CeCILL v.2.1.
@@ -19,43 +19,62 @@ function [a, ka] = setdiff(a, b, orien)
     // * 2019 - S. Gougeon : complex numbers supported
 
     [lhs, rhs] = argn();
+    ka = []
 
+    // ========================
     // CHECKING INPUT ARGUMENTS
     // ========================
     if rhs < 2 | rhs > 3 then
-        msg = gettext("%s: Wrong number of input argument(s): %d or %d expected.\n");
-        error(msprintf(msg, "setdiff", 2, 3));
+        msg = _("%s: Wrong number of input argument(s): %d or %d expected.\n")
+        error(msprintf(msg, "setdiff", 2, 3))
     end
-    // Trivial case _whatever is b_
-    if isempty(a)
-        ka = []
-        return
+    typa = type(a)
+    if ~or(typa == [1 4 5 6 8 10]) then
+        msg = _("%s: Argument #%d: Unsupported type %s.\n")
+        error(msprintf(msg, "setdiff", 1, typeof(a)))
+    end
+
+    if size(a,"*") <> 0 & size(b,"*") <> 0 & typa==10 & type(b) <> 10 then
+        msg = _("%s: Arguments #%d and #%d: Same types expected.\n")
+        error(msprintf(msg, "setdiff", 1, 2))
+    end
+    if typa == 8 & type(b) == 8 & inttype(a) <> inttype(b) then
+        msg = _("%s: Arguments #%d and #%d: Same integer types expected.\n")
+        error(msprintf(msg, "setdiff", 1, 2))
     end
     // orien
     if ~isdef("orien","l") then
         orien = 0
-    elseif orien~="r" & orien~="c" & orien~=1 & orien~=2
-        msg = gettext("%s: Argument #%d: Must be in the set {%s}.\n");
-        error(msprintf(msg, "setdiff", 3, "''r'',''c'',1,2"));
-    elseif orien=="c"
-        orien = 2
-    elseif orien=="r"
+    elseif orien == "r"
         orien = 1
+    elseif orien == "c"
+        orien = 2
+    elseif orien ~= 1 & orien ~= 2
+        msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+        error(msprintf(msg, "setdiff", 3, "''r'',''c'',1,2"))
     end
-    if orien==1 & ~isempty(b) & size(a,2)~=size(b,2) then
+    // Trivial case, whatever is b
+    if size(a,"*")==0
+        return
+    end
+    //
+    if orien==1 & size(b,"*")<>0 & size(a,2)~=size(b,2) then
         msg = _("%s: Arguments #%d and #%d: Same numbers of columns expected.\n")
         error(msprintf(msg, "setdiff", 1, 2))
     end
-    if orien==2 & ~isempty(b) & size(a,1)~=size(b,1) then
+    if orien==2 & size(b,"*")<>0 &  size(a,1)~=size(b,1) then
         msg = _("%s: Arguments #%d and #%d: Same numbers of rows expected.\n")
         error(msprintf(msg, "setdiff", 1, 2))
     end
 
+    // ==========
     // PROCESSING
     // ==========
-    Complexes = (type(a)==1 && ~isreal(a)) | (type(b)==1 && ~isreal(b));
+    Complexes = (or(typa   ==[1 5]) && ~isreal(a)) | ..
+                (or(type(b)==[1 5]) && ~isreal(b));
+
     // "r" or "c"
-    // ----------
+    // ==========
     if orien then
         if ndims(a) > 2 then
             a = serialize_hypermat(a, orien)
@@ -65,95 +84,63 @@ function [a, ka] = setdiff(a, b, orien)
         end
         if lhs > 1
             [a, ka] = unique(a, orien)
-            if isempty(b)
-                return
-            end
-            it = inttype(a)
-            b = unique(b, orien)
-            if orien==2
-                a = a.'
-                b = b.'
-            end
-            if Complexes
-                [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
-                                 [b iconvert(ones(b(:,1))*2,it)]], ..
-                                "lr", ["i" "i"], list(abs, atan))
-            else
-                [c, kc] = gsort([[a iconvert(ones(a(:,1)),it)] ;
-                                 [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
-            end
-            k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
-            if c($,$)==1
-                k = [k size(c,1)]
-            end
-            ka = ka(kc(k))
-            // a = a(ka,:) // in initial order
-            a = c(k,1:$-1)
-            if orien==2
-                ka = matrix(ka, 1, -1)
-                a = a.'
-            end
         else
             a = unique(a, orien)
-            if isempty(b)
-                return
-            end
-            it = inttype(a)
-            b = unique(b, orien)
-            if orien==2
-                a = a.'
-                b = b.'
-            end
-            if Complexes
-                c = gsort([[a iconvert(ones(a(:,1)),it)] ;
-                           [b iconvert(ones(b(:,1))*2,it)]], ..
-                           "lr", ["i" "i"], list(abs, atan))
-            else
-                c = gsort([[a iconvert(ones(a(:,1)),it)] ;
-                           [b iconvert(ones(b(:,1))*2,it)]], "lr","i")
-            end
-            k = find(or(c(1:$-1,1:$-1)~=c(2:$,1:$-1),"c") & c(1:$-1,$)==1)
-            if c($,$)==1
-                k = [k size(c,1)]
-            end
-            // a = a(ka,:) // in initial order
-            a = c(k,1:$-1)
-            if orien==2
-                a = a.'
+        end
+        if size(b,"*")==0
+            return
+        end
+        b = unique(b, orien)
+        if orien==2
+            a = a.'
+            b = b.'
+        end
+        if Complexes
+            [c, kc] = gsort([a ; b], "lr", ["i" "i"], list(abs, atan))
+        else
+            [c, kc] = gsort([a ; b], "lr", "i")
+        end
+        k = find(and(c(1:$-1,:) == c(2:$,:), "c"))
+        if k <> []
+            a(kc([k k+1]),:) = []
+            if lhs > 1
+                ka(kc([k k+1])) = []
             end
         end
+        if orien==2
+            ka = matrix(ka, 1, -1)
+            a = a.'
+        end
 
     else
         // by element
-        // ----------
+        // ==========
         if lhs > 1
-            [a,ka] = unique(a);
+            [a, ka] = unique(a);
         else
             a = unique(a);
         end
-        na = size(a,"*");
-        if isempty(b)
+        if size(b,"*")==0
             return
         end
         b = unique(b(:));
         if Complexes
-            [x,k] = gsort([a(:); b], "g", ["i" "i"], list(abs, atan));
+            [x, k] = gsort([a(:) ; b], "g", ["i" "i"], list(abs, atan));
         else
-            [x,k] = gsort([a(:); b], "g", "i");
+            [x, k] = gsort([a(:) ; b], "g", "i");
         end
-        d = find(x(2:$)==x(1:$-1));  //index of common entries in sorted table
-        if d <> [] then
-            k([d;d+1]) = [];
-        end
-
-        keep = find(k <= na);
-        a = a(k(keep));
-        if lhs > 1
-            ka = ka(k(keep))
+        e = find(x(2:$)==x(1:$-1));
+        if e <> []
+            a(k([e e+1])) = []
+            if lhs > 1
+                ka(k([e e+1])) = []
+            end
         end
     end
 endfunction
+
 // ----------------------------------------------------------------------------
+
 function h = serialize_hypermat(h, orien)
     if orien==1 then
         dims = 1:ndims(h)
diff --git a/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16340.tst b/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16340.tst
new file mode 100644 (file)
index 0000000..b6a21d7
--- /dev/null
@@ -0,0 +1,22 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2020 - Samuel GOUGEON
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+
+// <-- Non-regression test for bug 16340 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/16340
+//
+// <-- Short Description -->
+// setdiff("", "") yielded "" instead of []
+
+assert_checkequal(setdiff("",""), []);
+assert_checkequal(setdiff("",[]), "");
+assert_checkequal(setdiff([],""), []);
+assert_checkequal(setdiff("",["1" "2" ""]), []);
index af354f4..e039d35 100644 (file)
@@ -1,15 +1,19 @@
-// =============================================================================
+// ===================================================================
 // Scilab ( http://wwwscilaborg/ ) - This file is part of Scilab
 // Copyright (C) 2009 - DIGITEO - Allan CORNET
-// Copyright (C) 2018 - 2019 - Samuel GOUGEON
+// Copyright (C) 2018 - 2020 - Samuel GOUGEON - Le Mans Université
 //
 //  This file is distributed under the same license as the Scilab package
-// =============================================================================
+// ===================================================================
 // <-- CLI SHELL MODE -->
 // <-- NO CHECK REF -->
 // <-- ENGLISH IMPOSED -->
-// =============================================================================
-
+// ===================================================================
+//
+// unit tests of setdiff(), except for
+//    booleans: => tested in setdiff_boolean.tst
+//    sparses : => tested in setdiff_sparse.tst
+//
 a = [223;111;2;4;2;2];
 b = [2;3;21;223;123;22];
 REF_K = [4 ; 2];
@@ -20,15 +24,15 @@ for f = list(double, int8, uint8, int16, uint16, int32, uint32, int64, uint64)
     assert_checkequal(k, REF_K);
 end
 
-// =============================================================================
+// ===================================================================
 
 REF_V = ['111' ; '4'];
 REF_K = [2; 4];
 [v,k] = setdiff(string(a),string(b));
-if and(v == REF_V) <> %t then pause,end
-if and(k == REF_K) <> %t then pause,end
+assert_checkequal(v, REF_V);
+assert_checkequal(k, REF_K);
 
-// =============================================================================
+// ===================================================================
 s  = 7;
 s2 = 5;
 r  = [14   0  4  7   8  15   7  17  15  12];
@@ -48,65 +52,77 @@ h2 = cat(3, m([2 1],1:6), m2([2 1],1:6));
 L  = list(s,  r,  c,  m,  h);
 L2 = list(s2, r2, c2, m2, h2);
 
-// With a=[] , orien = none|"r"|"c"
-// --------------------------------
-for i = 1:length(L)
-    o = L(i);
-    [va, ka] = setdiff([], o);
-    assert_checkequal(va, []);
-    assert_checkequal(ka, []);
-    [va, ka] = setdiff([], o, "r");
-    assert_checkequal(va, []);
-    assert_checkequal(ka, []);
-    [va, ka] = setdiff([], o, "c");
-    assert_checkequal(va, []);
-    assert_checkequal(ka, []);
-end
+for fun = list(double, string)
 
-// With b=[] , orien = none|"r"|"c"
-// --------------------------------
-for i = 1:length(L)
-    o = L(i);
-    [va, ka] = setdiff(o,[]);
-    [var,kar]= unique(o);
-    assert_checkequal(va, var);
-    assert_checkequal(ka, kar);
-    if ndims(o)>2
-        [var,kar] = unique(matrix(permute(o,[2 1 3]),6,-1)', "r");
-    else
-        [var,kar] = unique(o, "r")
+    // With a=[] , orien = none|"r"|"c"
+    // --------------------------------
+    for i = 1:length(L)
+        o = fun(L(i));
+        [va, ka] = setdiff([], o);
+        assert_checkequal(va, []);
+        assert_checkequal(ka, []);
+    
+        [va, ka] = setdiff([], o, "r");
+        assert_checkequal(va, []);
+        assert_checkequal(ka, []);
+        [va, ka] = setdiff([], o, "c");
+        assert_checkequal(va, []);
+        assert_checkequal(ka, []);
     end
-    [va, ka] = setdiff(o, [], "r");
-    assert_checkequal(va, var);
-    assert_checkequal(ka, kar);
-    [va, ka] = setdiff(o, [], "c");
-    if ndims(o)>2
-        [var,kar] = unique(matrix(o,2,-1), "c");
-    else
-        [var,kar] = unique(o, "c")
+
+    // With b=[] , orien = none|"r"|"c"
+    // --------------------------------
+    for i = 1:length(L)
+        o = fun(L(i));
+        [va, ka] = setdiff(o,[]);
+        [var,kar]= unique(o);
+        assert_checkequal(va, var);
+        assert_checkequal(ka, kar);
+
+        if ndims(o)>2
+            [var,kar] = unique(matrix(permute(o,[2 1 3]),6,-1)', "r");
+        else
+            [var,kar] = unique(o, "r")
+        end
+        [va, ka] = setdiff(o, [], "r");
+        assert_checkequal(va, var);
+        assert_checkequal(ka, kar);
+        [va, ka] = setdiff(o, [], "c");
+        if ndims(o)>2
+            [var,kar] = unique(matrix(o,2,-1), "c");
+        else
+            [var,kar] = unique(o, "c")
+        end
+        assert_checkequal(va, var);
+        assert_checkequal(ka, kar);
     end
-    assert_checkequal(va, var);
-    assert_checkequal(ka, kar);
 end
 
 // "r" and "c" options
 // -------------------
-for f = list(double, int8, uint8, int16, uint16, int32, uint32, int64, uint64)
+for f = list(string, double, int8, uint8, int16, uint16, int32, uint32, int64, uint64)
+    if f==string then
+        vref = ["12" "14" "17" "4" "8"]
+        kvref = [ 10    1    8   3   5]
+    else
+        vref = [4  8  12  14  17]
+        kvref = [3  5  10   1   8]
+    end
     // With row vectors
     [rr,k] = setdiff(f(r), f([r2 0 2]), "r");
     assert_checkequal(rr, f(r));
     assert_checkequal(k, 1);
     [rc,k] = setdiff(f(r), f(r2), "c");
-    assert_checkequal(rc, f([4  8  12  14  17]));
-    assert_checkequal(k,    [3  5  10   1   8]);
+    assert_checkequal(rc, f(vref));
+    assert_checkequal(k,  kvref);
 
     // With column vectors
     [rc,k] = setdiff(f(r'), f([r2 0 2]'), "c");
     assert_checkequal(rc, f(r'));
     assert_checkequal(k, 1);
     [rr,k] = setdiff(f(r'), f(r2'), "r");
-    assert_checkequal(rr, f([4  8  12  14  17]'));
-    assert_checkequal(k,    [3  5  10   1  8]');
+    assert_checkequal(rr, f(vref'));
+    assert_checkequal(k,  kvref');
 
     // With matrices
     [mc,k] = setdiff(f(m), f(m2), "c");
@@ -115,8 +131,8 @@ for f = list(double, int8, uint8, int16, uint16, int32, uint32, int64, uint64)
     assert_checkequal(k,    [4  1  8  2]);
     [mr,k] = setdiff(f(m'), f(m2'), "r");
     assert_checkequal(mr, f([0  1  2  3
-                            1  1  3  3]'));
-    assert_checkequal(k,   [4  1  8  2]');
+                             1  1  3  3]'));
+    assert_checkequal(k,    [4  1  8  2]');
 
     // With hypermatrices
     [hc,k] = setdiff(f(h), f(h2), "c");
@@ -132,7 +148,7 @@ for f = list(double, int8, uint8, int16, uint16, int32, uint32, int64, uint64)
     assert_checkequal(k,    [7 11]');
 end
 
-// =============================================================================
+// ===================================================================
 // Error messages
 msg = "%s: Wrong number of input argument(s): %d or %d expected.\n";
 assert_checkerror("setdiff()", msg , [], "setdiff", 2, 3);
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/setdiff_boolean.tst b/scilab/modules/elementary_functions/tests/unit_tests/setdiff_boolean.tst
new file mode 100644 (file)
index 0000000..1b384e5
--- /dev/null
@@ -0,0 +1,185 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2020 - Samuel GOUGEON - Le Mans Université
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+
+//
+// <-- Short Description -->
+// Unit tests for setdiff() with dense input booleans
+// Sparse booleans are tested in setdiff_sparse.tst
+//
+// See also:
+//   Bug 16451 : http://bugzilla.scilab.org/16451
+//               setdiff(a, b, "r"|"c") yields an error when a & b are boolean
+// --------------------------------------------------------------------------
+
+// ===========
+// By elements
+// ===========
+// No k requested
+// --------------
+// b = []
+assert_checkequal(setdiff([], []), []);
+assert_checkequal(setdiff(%t, []), %t);
+assert_checkequal(setdiff(%f, []), %f);
+assert_checkequal(setdiff([%f %t], []), [%f %t]);
+assert_checkequal(setdiff([%t %f], []), [%f %t]);
+assert_checkequal(setdiff([%t %f %t], []), [%f %t]);
+
+assert_checkequal(setdiff([%f %t]', []), [%f %t]');
+assert_checkequal(setdiff([%t %f]', []), [%f %t]');
+assert_checkequal(setdiff([%t %f %t]', []), [%f %t]');
+
+assert_checkequal(setdiff([%f %t ; %f %f], []), [%f %t]');
+
+// b <> []
+assert_checkequal(setdiff([], %f), []);
+assert_checkequal(setdiff([], [%t %f]), []);
+assert_checkequal(setdiff(%t, %f), %t);
+assert_checkequal(setdiff(%f, %t), %f);
+assert_checkequal(setdiff(%f, [%t %f]), []);
+assert_checkequal(setdiff([%f %t], [%t %f]), []);
+assert_checkequal(setdiff([%f %t], %t), %f);
+assert_checkequal(setdiff([%f %t], %f), %t);
+
+// k requested
+// -----------
+[d, k] = setdiff([], []);
+assert_checkequal(d, []);
+[d, k] = setdiff(%t, []);
+assert_checkequal(d, %t);
+[d, k] = setdiff(%f, []);
+assert_checkequal(d, %f);
+[d, k] = setdiff([%f %t], []);
+assert_checkequal(d, [%f %t]);
+[d, k] = setdiff([%t %f], []);
+assert_checkequal(d, [%f %t]);
+[d, k] = setdiff([%t %f %t], []);
+assert_checkequal(d, [%f %t]);
+
+[d, k] = setdiff([%f %t]', []);
+assert_checkequal(d, [%f %t]');
+[d, k] = setdiff([%t %f]', []);
+assert_checkequal(d, [%f %t]');
+[d, k] = setdiff([%t %f %t]', []);
+assert_checkequal(d, [%f %t]');
+
+[d, k] = setdiff([%f %t ; %f %f], []);
+assert_checkequal(d, [%f %t]');
+
+// b <> []
+[d, k] = setdiff([], %f);
+assert_checkequal(d, []);
+assert_checkequal(k, []);
+[d, k] = setdiff([], [%t %f]);
+assert_checkequal(d, []);
+assert_checkequal(k, []);
+[d, k] = setdiff(%t, %f);
+assert_checkequal(d, %t);
+assert_checkequal(k, 1);
+[d, k] = setdiff(%f, %t);
+assert_checkequal(d, %f);
+assert_checkequal(k, 1);
+[d, k] = setdiff(%f, [%t %f]);
+assert_checkequal(d, []);
+assert_checkequal(k, []);
+[d, k] = setdiff([%f %t], [%t %f]);
+assert_checkequal(d, []);
+assert_checkequal(k, []);
+[d, k] = setdiff([%f %t], %t);
+assert_checkequal(d, %f);
+assert_checkequal(k, 1);
+[d, k] = setdiff([%f %t], %f);
+assert_checkequal(d, %t);
+assert_checkequal(k, 2);
+
+
+// ==========
+// "r" or "c"
+// ==========
+a  = [
+  %T %F %F %T %F %T %F
+  %T %T %T %T %T %F %T
+  %F %F %T %T %F %T %T
+  ];
+b = [
+  %F %T %F %T %T %T %F
+  %T %F %F %T %T %F %T
+  %T %T %T %T %T %F %T
+ ];
+// No ka requested
+// ---------------
+d = setdiff(a, [], "c");
+assert_checkequal(d, unique(a,"c"));
+d = setdiff(a, [], "r");
+assert_checkequal(d, unique(a,"r"));
+d = setdiff(a, b, "c");
+assert_checkequal(d, [0 1 0 ; 1 1 0]'==1);
+d = setdiff(a', b', "r");
+assert_checkequal(d, [0 1 0 ; 1 1 0]==1);
+d = setdiff(a, b, "r");
+assert_checkequal(d, [0 0 1 1 0 1 1 ; 1 0 0 1 0 1 0]==1);
+
+// ka requested
+// ------------
+[d, k] = setdiff(a, [], "c");
+assert_checkequal(d, unique(a,"c"));
+assert_checkequal(k, [2 3 6 1 4]);
+[d, k] = setdiff(a, [], "r");
+assert_checkequal(d, unique(a,"r"));
+assert_checkequal(k, [3 1 2]');
+
+[d, k] = setdiff(a, b, "c");
+assert_checkequal(d, [0 1 0 ; 1 1 0]'==1);
+assert_checkequal(k, [2 1]);
+[d, k] = setdiff(a', b', "r");
+assert_checkequal(d, [0 1 0 ; 1 1 0]==1);
+assert_checkequal(k, [2 1]');
+[d, k] = setdiff(a, b, "r");
+assert_checkequal(d, [0 0 1 1 0 1 1 ; 1 0 0 1 0 1 0]==1);
+assert_checkequal(k, [3 1]');
+
+// ===================
+// Boolean hypermatrix
+// ===================
+T = %T; F = %F;
+b  = [
+  F F T F F T T T T F
+  T T F F T F F T T F
+  T F F F F F F T F T
+  T F T F T F F F F T ];
+h = cat(3 , [
+  T F T T
+  F F F F
+  F T F T
+  F T T F ], [
+  T F F F
+  F F F F
+  F T F T
+  T F F F ]);
+
+// By elements
+// -----------
+assert_checkequal(setdiff(h, b), []);
+assert_checkequal(setdiff(b, h), []);
+
+// With "r" and "c"
+// ----------------
+ref = [
+  F T
+  F F
+  T T
+  F F ];
+assert_checkequal(setdiff(h, b, "c"), ref);
+assert_checkequal(setdiff(cat(3, h(:,:,1)', h(:,:,2)'), b', "r"), ref');
+ref = [
+  F F F T T
+  T T T T T
+  F F T F T
+  F T T F F ];
+assert_checkequal(setdiff(b, h, "c"), ref);
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/setdiff_sparse.tst b/scilab/modules/elementary_functions/tests/unit_tests/setdiff_sparse.tst
new file mode 100644 (file)
index 0000000..b1f68ee
--- /dev/null
@@ -0,0 +1,83 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2020 - Samuel GOUGEON - Le Mans Université
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+
+//
+// <-- Short Description -->
+// Unit tests for setdiff() with boolean sparse or numerical sparse matrices
+
+// See also : http://bugzilla.scilab.org/15867
+
+eb = sparse(%t); eb(1) = [];
+
+// Element-wise processing
+// -----------------------
+objects = list(sparse([]), sparse(0), sparse(5), sparse([2 0 -3 0 4]), ..
+    sparse([2 0 -3 0 4]'), sparse([0 2 -1 ; 3 0 2]), ..
+    eb, sparse(%t), sparse(%f), sparse([%t %f %f %t %f]), ..
+    sparse([%t %f %f %t %f]'), sparse([%t %f %t ; %t %t %f]));
+for a = objects
+    typeref = 1
+    for b = objects
+        [dref, kref] = setdiff(full(a), full(b))
+        d = setdiff(a, b);
+        assert_checktrue(issparse(d));
+        assert_checkequal(full(d), dref);
+        [d, k] = setdiff(a, b);
+        assert_checkequal(k, kref);
+    end
+end
+// orientation "c"
+// ---------------
+m = [1  0  0  1  1  0  0  1  0  1
+     1  0  0  1  1  1  0  1  1  0
+     0  0  1  0  1  0  0  0  0  1
+    ];
+sm = sparse(m);
+m2 = [0  1  1  1  0
+      1  1  1  1  0
+      1  1  0  0  0
+     ];
+sm2 = sparse(m2);
+
+objects = list([], sparse([]), sparse(5), sparse([2 0 -3 0 4]), ..
+    sparse([2 0 -3 0 4]'), sparse([0 2 -1 ; 3 0 2]), m, sm, m2, sm2, ..
+    eb, sparse(%t), sparse(%f), sparse([%t %t %t]), ..
+    sparse([%f %f %f]'), sparse([%t %f %t ; %t %t %f]), ..
+    m==1, sm==1, m2==1, sm2==1);
+for a = objects
+    for b = objects
+        if (size(a,1)<>0 & size(b,1)<>0 & size(a,1)<>size(b,1)) | ..
+            (~issparse(a) & ~issparse(b))
+            continue
+        end
+        [dref, kref] = setdiff(full(a), full(b), "c");
+
+        d = setdiff(a, b, "c");
+        try
+        assert_checkequal(issparse(d), issparse(a));
+        if issparse(a)
+            dref = sparse(dref);
+            if type(a)==6 & dref==sparse([])
+                dref = eb
+            end
+        end
+        assert_checkequal(d, dref);
+
+        [d, k] = setdiff(a, b, "c");
+        assert_checkequal(issparse(d), issparse(a));
+        assert_checkequal(d, dref);
+        assert_checkequal(k, kref);
+    catch
+        pause
+    end
+
+    end
+end
+