* Bug 15841 fixed: intersect() now accepts sparse 34/21634/5
Samuel GOUGEON [Sun, 6 Dec 2020 00:38:39 +0000 (01:38 +0100)]
  http://bugzilla.scilab.org/15841
  Updated page: (en_US PDF)

Change-Id: I6d9db4a5dd49c3a28f39de2c3510166d87d4e7f9

scilab/CHANGES.md
scilab/modules/elementary_functions/help/en_US/setoperations/intersect.xml
scilab/modules/elementary_functions/help/fr_FR/setoperations/intersect.xml
scilab/modules/elementary_functions/help/ru_RU/setoperations/intersect.xml [new file with mode: 0644]
scilab/modules/elementary_functions/macros/intersect.sci
scilab/modules/elementary_functions/tests/unit_tests/intersect.tst
scilab/modules/elementary_functions/tests/unit_tests/intersect_sparse.tst [new file with mode: 0644]

index f0b7113..9e8c116 100644 (file)
@@ -218,6 +218,7 @@ Feature changes and additions on 6.1.1
 * `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).
+* `intersect` is extended to any sparse boolean or numeric arrays, in all simple, 'c' or 'r' modes.
 
 Help pages:
 -----------
@@ -336,6 +337,7 @@ Bug Fixes
 * [#15226](https://bugzilla.scilab.org/15226): The `get` page needed to be overhauled: `get(0)`, `get(0,prop)`, `get(tag)`, `get(tag,prop)` and other features were not documented.
 * [#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.
+* [#15841](https://bugzilla.scilab.org/15841): `intersect` did not support neither sparse boolean nor sparse numeric inputs.
 * [#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.
index 6bc8ad1..b27d588 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * 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.
@@ -21,7 +20,7 @@
     <refnamediv>
         <refname>intersect</refname>
         <refpurpose>
-            returns the unduplicated elements or rows or columns met in both input arrays
+            elements or rows or columns met in both input arrays, without duplicates
         </refpurpose>
     </refnamediv>
     <refsynopsisdiv>
             <varlistentry>
                 <term>a, b</term>
                 <listitem>
-                    vectors, matrices or hypermatrices of encoded integers, real or complex
-                    numbers, or text. <varname>a</varname> and <varname>b</varname> must have
-                    the same datatype, but have independent sizes.
+                    vectors, matrices or hypermatrices of booleans, encoded integers, real or
+                    complex numbers, or text. <varname>a</varname> and <varname>b</varname> must
+                    have the same datatype.
                     For text inputs, UTF characters are accepted.
+                    Sparse numeric or boolean matrices are accepted : Either <varname>a</varname> or
+                    <varname>b</varname> or both <varname>a</varname> and <varname>b</varname> may
+                    be sparse.
                     <para/>
                 </listitem>
             </varlistentry>
                             </listitem>
                         </itemizedlist>
                     </para>
+                    <para>
+                        <varname>M</varname> is sparse as soon as either <varname>a</varname> or
+                        <varname>b</varname> is sparse and none is empty.
+                    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>ka</term>
                 <listitem>
-                    row vector of indices in <varname>a</varname>.
+                    Dense row vector of indices in <varname>a</varname>.
                     <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>kb</term>
                 <listitem>
-                    row vector of indices in <varname>b</varname>.
+                    Dense row vector of indices in <varname>b</varname>.
                     <para/>
                 </listitem>
             </varlistentry>
     <refsection>
         <title>Description</title>
         <para>
-            <literal>intersect(a,b)</literal> returns a row vector of unduplicated values
+            <literal>intersect(a,b)</literal> returns a row vector of unique values
             present in both <literal>a</literal> and <literal>b</literal> arrays. Values are
             sorted in increasing order
             <itemizedlist>
@@ -258,6 +264,47 @@ M, ka, kb
  kb  =
    2.   3.   4.
 ]]></screen>
+    <para/>
+    <para>
+        <literal>intersect()</literal> for booleans is mainly useful with the "r" or "c" option.
+        Here is an example with a sparse boolean matrix:
+    </para>
+    <programlisting role="example"><![CDATA[
+[F, T] = (%f, %t);
+A = [F F T F T F ; T F F T T T ; T T F T F F]
+B = [F T F T F F ; T F F F T F ; F T F F T F]
+[M,ka,kb] = intersect(A, sparse(B), "c");
+issparse(M), full(M), ka, kb
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = [F F T F T F ; T F F T T T ; T T F T F F]
+ A  =
+  F F T F T F
+  T F F T T T
+  T T F T F F
+
+--> B = [F T F T F F ; T F F F T F ; F T F F T F]
+ B  =
+  F T F T F F
+  T F F F T F
+  F T F F T F
+
+--> [M,ka,kb] = intersect(A, sparse(B), "c");
+--> issparse(M), full(M), ka, kb
+ ans  =
+  T
+
+ ans  =
+  F F T
+  T T F
+  F T F
+
+ ka  =
+   6.   1.   3.
+
+ kb  =
+   1.   5.   4.
+]]></screen>
     </refsection>
     <refsection role="see also">
         <title>See also</title>
@@ -282,7 +329,13 @@ M, ka, kb
             <revision>
                 <revnumber>6.1.0</revnumber>
                 <revdescription>
-                    complex numbers are now accepted.
+                    Complex numbers are now accepted.
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Sparse matrices are now accepted (numbers or booleans).
                 </revdescription>
             </revision>
         </revhistory>
index 7ba3b1b..ea04a85 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * 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.
             <varlistentry>
                 <term>a, b</term>
                 <listitem>
-                    vecteurs, matrices ou hypermatrices d'entiers encodés, de nombres réels ou
-                    complexes, ou de texte. <varname>a</varname> et <varname>b</varname> doivent
-                    être du même type de données, mais ont des tailles indépendantes.
+                    vecteurs, matrices ou hypermatrices de booléens, d'entiers encodés, de nombres
+                    réels ou complexes, ou de texte. <varname>a</varname> et <varname>b</varname>
+                    doivent être du même type de données, mais ont des tailles indépendantes.
                     Pour les données texte, les caractères UTF sont admis.
+                    Les matrices creuses booléennes ou numériques sont acceptées :
+                    <varname>a</varname> ou <varname>b</varname> ou les deux peuvent être creuses.
                     <para/>
                 </listitem>
             </varlistentry>
                             </listitem>
                         </itemizedlist>
                     </para>
+                    <para>
+                        <varname>M</varname> est creuse dés que <varname>a</varname> ou
+                        <varname>b</varname> est creuse et aucune n'est vide.
+                    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>ka</term>
                 <listitem>
-                    Vecteur ligne d'indices dans <varname>a</varname>.
+                    Vecteur ligne dense d'indices dans <varname>a</varname>.
                     <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>kb</term>
                 <listitem>
-                    Vecteur lignes d'indices dans <varname>b</varname>.
+                    Vecteur ligne dense d'indices dans <varname>b</varname>.
                     <para/>
                 </listitem>
             </varlistentry>
@@ -260,6 +265,47 @@ M, ka, kb
  kb  =
    2.   3.   4.
 ]]></screen>
+    <para/>
+    <para>
+        Pour des booléens, <literal>intersect()</literal> est utile essentiellement avec l'option
+        "r" ou "c". Voici un exemple avec une matrice booléenne creuse :
+    </para>
+    <programlisting role="example"><![CDATA[
+[F, T] = (%f, %t);
+A = [F F T F T F ; T F F T T T ; T T F T F F]
+B = [F T F T F F ; T F F F T F ; F T F F T F]
+[M,ka,kb] = intersect(A, sparse(B), "c");
+issparse(M), full(M), ka, kb
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = [F F T F T F ; T F F T T T ; T T F T F F]
+ A  =
+  F F T F T F
+  T F F T T T
+  T T F T F F
+
+--> B = [F T F T F F ; T F F F T F ; F T F F T F]
+ B  =
+  F T F T F F
+  T F F F T F
+  F T F F T F
+
+--> [M,ka,kb] = intersect(A, sparse(B), "c");
+--> issparse(M), full(M), ka, kb
+ ans  =
+  T
+
+ ans  =
+  F F T
+  T T F
+  F T F
+
+ ka  =
+   6.   1.   3.
+
+ kb  =
+   1.   5.   4.
+]]></screen>
     </refsection>
     <refsection role="see also">
         <title>Voir aussi</title>
@@ -284,7 +330,13 @@ M, ka, kb
             <revision>
                 <revnumber>6.1.0</revnumber>
                 <revdescription>
-                    Les nombres complexes sont désormais acceptés.
+                    Nombres complexes désormais acceptés.
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Matrices creuses numériques ou booléennes désormais acceptées.
                 </revdescription>
             </revision>
         </revhistory>
diff --git a/scilab/modules/elementary_functions/help/ru_RU/setoperations/intersect.xml b/scilab/modules/elementary_functions/help/ru_RU/setoperations/intersect.xml
new file mode 100644 (file)
index 0000000..f8e2507
--- /dev/null
@@ -0,0 +1,357 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2008 - INRIA
+ * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * 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.
+ * This file was originally licensed under the terms of the CeCILL v2.1,
+ * and continues to be available under such terms.
+ * For more information, see the COPYING file which you should have received
+ * along with this program.
+ *
+ -->
+<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
+        xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml"
+        xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook"
+        xmlns:scilab="http://www.scilab.org" xml:id="intersect" xml:lang="ru">
+    <refnamediv>
+        <refname>intersect</refname>
+        <refpurpose>
+            элементы, либо строки либо столбцы, имеющиеся в обоих входных массивах, без повторов
+        </refpurpose>
+    </refnamediv>
+    <refsynopsisdiv>
+        <title>Синтаксис</title>
+        <synopsis>
+            M = intersect(a, b)
+            M = intersect(a, b, orient)
+            [M, ka] = intersect(..)
+            [M, ka, kb] = intersect(..)
+        </synopsis>
+    </refsynopsisdiv>
+    <refsection>
+        <title>Аргументы</title>
+        <variablelist>
+            <varlistentry>
+                <term>a, b</term>
+                <listitem>
+                    векторы, матрицы или гиперматрицы логических значений,
+                    кодированных целых чисел, вещественных или комплексных чисел,
+                    или текста. <varname>a</varname> и <varname>b</varname> должны
+                    иметь одинаковый тип данных.
+                    Для текстовых входных данных принимаются символы UTF.
+                    Принимаются разреженные числовые или логические матрицы: либо
+                    <varname>a</varname> либо <varname>b</varname> либо как
+                    <varname>a</varname>, так и <varname>b</varname> могут быть
+                    разрежёнными.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>orient</term>
+                <listitem>
+                    флаг с возможными значениями: 1 или "r", 2 или "c". Не может
+                    использоваться, если <varname>a</varname> или/и <varname>b</varname>
+                    являются гиперматрицами.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>M</term>
+                <listitem>
+                    <para>
+                        матрица того же типа данных, что и <varname>a</varname> и
+                        <varname>b</varname>.
+                        <itemizedlist>
+                            <listitem>
+                                Без <varname>orient</varname>: <varname>M</varname>
+                                является вектором-строкой.
+                            </listitem>
+                            <listitem>
+                                С <literal>orient="r"|1</literal>: <varname>M</varname>
+                                является матрицей, накапливающей общие строки
+                                <varname>a</varname> и <varname>b</varname>.
+                            </listitem>
+                            <listitem>
+                                С <literal>orient="c"|2</literal>: <varname>M</varname>
+                                является матрицей, накапливающей общие столбцы
+                                <varname>a</varname> и <varname>b</varname>.
+                            </listitem>
+                        </itemizedlist>
+                    </para>
+                    <para>
+                        <varname>M</varname> является разрежённой, если либо
+                        <varname>a</varname> или <varname>b</varname> являются
+                        разрежёнными и ни одна не является пустой.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>ka</term>
+                <listitem>
+                    Плотный вектор-строка индексов в <varname>a</varname>.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>kb</term>
+                <listitem>
+                    Плотный вектор-строка индексов в <varname>b</varname>.
+                    <para/>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsection>
+    <refsection>
+        <title>Описание</title>
+        <para>
+            <literal>intersect(a,b)</literal> возвращает вектор-строку уникальных
+            значений, присутствующих как в массиве <literal>a</literal> так и в
+            массиве <literal>b</literal>. Значения отсортированы в порядке возрастания
+            <itemizedlist>
+                <listitem>
+                    для комплексных чисел: сначала в порядке возрастания амплитуды, затем в порядке возрастания фазы;
+                </listitem>
+                <listitem>
+                    для текстов: в алфавитном порядке.
+                </listitem>
+            </itemizedlist>
+        </para>
+        <warning>
+            Два элемента <literal>NaN</literal> всегда считаются разными. Так,
+            <literal>NaN</literal> или строки или столбцы, имеющие <literal>NaN</literal>,
+            никогда не окажутся в результирующей <literal>M</literal>.
+        </warning>
+        <para>
+            <literal>[M, ka, kb] = intersect(a,b)</literal> дополнительно возвращает
+            векторы индексов <literal>ka</literal> и <literal>kb</literal> в
+            <literal>a</literal> и в <literal>b</literal> выбранных компонентов,
+            первых попавшихся так, что <literal>M=a(ka)</literal> и
+            <literal>M=b(kb)</literal>.
+        </para>
+        <refsect3>
+            <title>Общие строки или столбцы</title>
+        <para>
+            Когда указан аргумент <varname>orient</varname>, сравнение выполняется
+            между строками <literal>a</literal> и <literal>b</literal> -- каждая
+            из которых рассматривается как целое --, или между их столбцами.
+        </para>
+        <para>
+            <literal>intersect(a,b,"r")</literal> или <literal>intersect(a,b,1)</literal>
+            будет возвращать матрицу накопленных неповторяющихся строк, встреченных
+            как в  <literal>a</literal>, так и в <literal>b</literal>, сортированных
+            в лексикографическом порядке возрастания.
+            Если <literal>a</literal> и <literal>b</literal> не имеют одинаковое
+            количество столбцов, то будет возвращено <literal>[]</literal> без
+            сравнения величин.
+        </para>
+        <para>
+            <literal>[M,ka,kb] = intersect(a,b,"r")</literal> дополнительно возвращает
+            векторы <literal>ka</literal> и <literal>kb</literal> минимальных индексов
+            общих строк, соответственно в <literal>a</literal> и <literal>b</literal>,
+            так что <literal>M=a(ka,:)</literal> и <literal>M=b(kb,:)</literal>.
+        </para>
+        <para>
+            <literal>intersect(a,b,"c")</literal> или <literal>intersect(a,b,2)</literal>
+            делает то же самое, но для столбцов.
+        </para>
+        </refsect3>
+    </refsection>
+    <refsection>
+        <title>Примеры</title>
+        <programlisting role="example"><![CDATA[
+A = grand(3, 3, "uin", 0, 9)
+B = grand(2, 4, "uin", 0, 9)
+intersect(A, B)
+[N, ka, kb] = intersect(A,B);
+ka, kb
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = grand(3, 3, "uin", 0, 9)
+ A  =
+   0.   6.   4.
+   6.   6.   6.
+   2.   7.   9.
+
+--> B = grand(2, 4, "uin", 0, 9)
+ B  =
+   1.   8.   0.   2.
+   6.   2.   2.   1.
+
+--> intersect(A, B)
+ ans  =
+   0.   2.   6.
+
+--> [N, ka, kb] = intersect(A,B);
+--> ka, kb
+ ka  =
+   1.   3.   2.
+ kb  =
+   5.   4.   2.
+]]></screen>
+    <para>
+        В вышеприведённом примере обратите внимание, что 6 встречена четыре раза
+        в <varname>A</varname> с индексами [2 4 5 8].
+        Только минимальный индекс 2 возвращается в <varname>ka</varname>. Та же
+        ситуация для 2 в <varname>B</varname>.
+    </para>
+    <para/>
+    <para>
+    Значения <literal>NaN</literal> никогда не могут быть в результате:
+    </para>
+    <programlisting role="example"><![CDATA[
+%nan == %nan
+intersect([1 -2 %nan 3 6], [%nan 1:3])
+ ]]></programlisting>
+    <screen><![CDATA[
+--> %nan == %nan
+ ans  =
+  F
+
+--> intersect([1 -2 %nan 3 6], [%nan 1:3])
+ ans  =
+   1.   3.
+]]></screen>
+    <para/>
+    <para>
+        <literal>intersect()</literal> может также обрабатывать некоторые символы
+        или тексты. Поскольку Scilab превосходно работает с символами UTF, то здесь
+        пример с некоторым арабским содержимым, получающим символы, присутствующими
+        в обоих предложениях:
+    </para>
+        <programlisting role="example"><![CDATA[
+A = strsplit("هو برنامج علمي كبير ""Scilab""")'
+B = strsplit("فهو حر ومفتوح")'
+intersect(A,B)
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = strsplit("هو برنامج علمي كبير ""Scilab""")'
+ A  =
+!ه  و     ب  ر  ن  ا  م  ج     ع  ل  م  ي     ك  ب  ي  ر     "  S  c  i  l  a  b  "  !
+
+--> B = strsplit("فهو حر ومفتوح")'
+ B  =
+!ف  ه  و     ح  ر     و  م  ف  ت  و  ح  !
+
+--> intersect(A,B)
+ ans  =
+!   ر  م  ه  و  !
+]]></screen>
+    <para/>
+    <para>
+        Постолбцовая или построковая обработка двух матриц: здесь мы обрабатываем
+        2 матрицы знаковых 1-битных целых и получаем общие столбцы:
+    </para>
+    <programlisting role="example"><![CDATA[
+A = int8(grand(3,5,"uin",0,1))
+B = int8(grand(3,9,"uin",0,1))
+[M,ka,kb] = intersect(A, B, "c");
+M, ka, kb
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = int8(grand(3,5,"uin",0,1))
+ A  =
+  0  0  1  1  1
+  0  0  1  1  0
+  0  0  0  0  1
+
+--> B = int8(grand(3,9,"uin",0,1))
+ B  =
+  1  0  1  1  1  0  1  1  1
+  1  0  0  1  1  1  0  0  0
+  1  0  1  0  1  1  1  0  0
+
+--> [M,ka,kb] = intersect(A, B, "c");
+--> M, ka, kb
+ M  =
+  0  1  1
+  0  0  1
+  0  1  0
+
+ ka  =
+   1.   5.   3.
+
+ kb  =
+   2.   3.   4.
+]]></screen>
+    <para/>
+    <para>
+        <literal>intersect()</literal> для логических значений главным образом
+        полезны с опцией <literal>"r"</literal> или <literal>"c"</literal>. Здесь
+        пример с разрежённой матрицей логических значений:
+    </para>
+    <programlisting role="example"><![CDATA[
+[F, T] = (%f, %t);
+A = [F F T F T F ; T F F T T T ; T T F T F F]
+B = [F T F T F F ; T F F F T F ; F T F F T F]
+[M,ka,kb] = intersect(A, sparse(B), "c");
+issparse(M), full(M), ka, kb
+ ]]></programlisting>
+    <screen><![CDATA[
+--> A = [F F T F T F ; T F F T T T ; T T F T F F]
+ A  =
+  F F T F T F
+  T F F T T T
+  T T F T F F
+
+--> B = [F T F T F F ; T F F F T F ; F T F F T F]
+ B  =
+  F T F T F F
+  T F F F T F
+  F T F F T F
+
+--> [M,ka,kb] = intersect(A, sparse(B), "c");
+--> issparse(M), full(M), ka, kb
+ ans  =
+  T
+
+ ans  =
+  F F T
+  T T F
+  F T F
+
+ ka  =
+   6.   1.   3.
+
+ kb  =
+   1.   5.   4.
+]]></screen>
+    </refsection>
+    <refsection role="see also">
+        <title>Смотрите также</title>
+        <simplelist type="inline">
+            <member>
+                <link linkend="members">members</link>
+            </member>
+            <member>
+                <link linkend="unique">unique</link>
+            </member>
+            <member>
+                <link linkend="gsort">gsort</link>
+            </member>
+            <member>
+                <link linkend="union">union</link>
+            </member>
+        </simplelist>
+    </refsection>
+    <refsection role="history">
+        <title>История</title>
+        <revhistory>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    Теперь принимаются комплексные числа.
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    Теперь принимаются разрежённые матрицы (числовые или логические значения).
+                </revdescription>
+            </revision>
+        </revhistory>
+    </refsection>
+</refentry>
index 6ddb663..0354d5b 100644 (file)
 function [x_out, ka_out, kb_out] = intersect(a_in, b_in, orient)
     // returns the vector of common values of two vectors
 
-    [lhs, rhs] = argn();
-    x_out = []
-    ka_out = []
-    kb_out = []
+    [lhs, rhs] = argn()
+    [x_out, ka_out, kb_out] = ([], [], [])
 
     if rhs < 2 then
         msg = gettext("%s: Wrong number of input arguments: %d or %d expected.\n")
         error(msprintf(msg, "intersect", 2, 3))
     end
 
-    if a_in == [] | b_in == [] then
+    // Special empty cases
+    [esp, espb] = (sparse([]), sparse(%f)); espb(1) = []
+    if a_in == [] || b_in == [] | isequal(a_in, esp) || isequal(b_in, esp) | ..
+        isequal(a_in, espb) | isequal(b_in, espb)
         return
     end
-    aIsComplex = type(a_in)==1 && ~isreal(a_in);
-    bIsComplex = type(b_in)==1 && ~isreal(b_in);
+    //
+    aIsComplex = or(type(a_in)==[1 5]) && ~isreal(a_in);
+    bIsComplex = or(type(b_in)==[1 5]) && ~isreal(b_in);
 
     // Without orientation
     // -------------------
index 2c3e62f..89490d6 100644 (file)
@@ -24,10 +24,10 @@ A = [ 1 8 4 5 2 1];
 B = [ 9 7 4 2 1 4];
 
 [v,ka,kb] = intersect(A,B);
-if or(A(ka) <> B(kb)) then pause,end
-if or(A(ka) <> v) then pause,end
-if or(v<>intersect(A,B))  then pause,end
-if (or(v<>[1,2,4])) then pause,end
+assert_checkequal(A(ka), B(kb));
+assert_checkequal(A(ka), v);
+assert_checkequal(intersect(A,B), v);
+assert_checkequal(v, [1 2 4]);
 
 // With texts
 // ----------
@@ -43,44 +43,75 @@ if v <> [] then pause,end
 A = [ "elt1" "elt3" "elt4"];
 B = [ "elt5" "elt1" "elt3"];
 [v, ka, kb] = intersect(A,B);
-if or(A(ka) <> B(kb)) then pause,end
-if or(A(ka) <> v) then pause,end
-if or(v<>intersect(A,B))  then pause,end
-if (or(v<>["elt1","elt3"])) then pause,end
+assert_checkequal(A(ka), B(kb));
+assert_checkequal(A(ka), v);
+assert_checkequal(intersect(A,B), v);
+assert_checkequal(v, ["elt1","elt3"]);
+
 
 A = [ "elt1" "elt3" "elt4"];
 B = [ "elt5" "elt6" "elt2" "elt1" "elt3"];
 
 [v, ka, kb] = intersect(A,B);
-if or(A(ka) <> B(kb)) then pause,end
-if or(A(ka) <> v) then pause,end
-if or(v<>intersect(A,B))  then pause,end
-if (or(v<>["elt1","elt3"])) then pause,end
+assert_checkequal(A(ka), B(kb));
+assert_checkequal(A(ka), v);
+assert_checkequal(intersect(A,B), v);
+assert_checkequal(v, ["elt1","elt3"]);
 
 // UTF-8
 A = strsplit("هو برنامج علمي كبير ""Scilab""")'
 B = strsplit("فهو حر ومفتوح")'
 assert_checkequal(intersect(A,B),[" "  "ر"  "م"  "ه"  "و"]);
 
+// With booleans
+// -------------
+[T, F] = (%t, %f);
+assert_checkequal(intersect([F F],F), F);
+assert_checkequal(intersect([T T],T), T);
+assert_checkequal(intersect(T,F), []);
+assert_checkequal(intersect(F,T), []);
+A = [F F T F T F
+     T F F T T T
+     T T F T F F ];
+B = [F T F T F F
+     T F F F T F
+     F T F F T F ];
+ref = [F F T
+       T T F
+       F T F ];
+assert_checkequal(intersect(A,B), [F T]);
+assert_checkequal(intersect(A,B,"c"), ref);
+[v,ka,kb] = intersect(A,B,"c");
+assert_checkequal(v, ref);
+assert_checkequal(A(:,ka), v);
+assert_checkequal(A(:,ka), B(:,kb));
+
+assert_checkequal(intersect(A',B',"r"), ref');
+[v,ka,kb] = intersect(A',B',"r");
+assert_checkequal(v, ref');
+assert_checkequal(A(:,ka)', v);
+assert_checkequal(A(:,ka)', B(:,kb)');
+
+
 // with integers
 // ------------
-A = int16([ 1 8 4 5 2 1]);
-B = int16([ 9 7 4 2 1 4]);
+A = int16([1 8 4 5 2 1]);
+B = int16([9 7 4 2 1 4]);
 
 [v, ka, kb]=intersect(A,B);
-if or(A(ka) <> B(kb)) then pause,end
-if or(A(ka) <> v) then pause,end
-if or(v<>intersect(A,B))  then pause,end
-if (or(v<>int16([1,2,4]))) then pause,end
+assert_checkequal(A(ka), B(kb));
+assert_checkequal(A(ka), v);
+assert_checkequal(intersect(A,B), v);
+assert_checkequal(v, int16([1,2,4]));
 
-A = uint8([ 1 8 4 5 2 1]);
-B = uint8([ 9 7 4 2 1 4]);
+A = uint8([1 8 4 5 2 1]);
+B = uint8([9 7 4 2 1 4]);
 
 [v, ka, kb]=intersect(A,B);
-if or(A(ka) <> B(kb)) then pause,end
-if or(A(ka) <> v) then pause,end
-if or(v<>intersect(A,B))  then pause,end
-if (or(v<>uint8([1,2,4]))) then pause,end
+assert_checkequal(A(ka), B(kb));
+assert_checkequal(A(ka), v);
+assert_checkequal(intersect(A,B), v);
+assert_checkequal(v, uint8([1,2,4]));
 
 // With orientation: Common rows or columns
 // ----------------------------------------
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/intersect_sparse.tst b/scilab/modules/elementary_functions/tests/unit_tests/intersect_sparse.tst
new file mode 100644 (file)
index 0000000..82860c1
--- /dev/null
@@ -0,0 +1,139 @@
+// =============================================================================
+// 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 -->
+//
+// <-- Short Description -->
+// Unitary tests for intersect() with sparse boolean or numeric matrices
+
+// ===============
+// Sparse booleans
+// ===============
+[T, F] = (%t, %f);
+[esp, espb] = (sparse([]), sparse(F)); espb(1) = []
+
+// With an empty
+assert_checkequal(intersect(T, espb), []);
+[v, ka, kb] = intersect(T, espb);
+assert_checkequal(list(v, ka, kb), list([], [], []));
+
+assert_checkequal(intersect(espb, F), []);
+[v, ka, kb] = intersect(espb, F);
+assert_checkequal(list(v, ka, kb), list([], [], []));
+//
+A = [F F T F T F
+     T F F T T T
+     T T F T F F ];
+B = [F T F T F
+     T F F F T
+     F T F F T ];
+ref = [F F T
+       T T F
+       F T F ];
+[spA, spB, spref] = (sparse(A), sparse(B), sparse(ref));
+assert_checkequal(intersect(spA, B), sparse([F T]));
+assert_checkequal(intersect(A, spB), sparse([F T]));
+assert_checkequal(intersect(spA, spB), sparse([F T]));
+
+LA = list(spA, A, spA);
+LB = list(B, spB, spB);
+for i = 1:3
+    assert_checkequal(intersect(LA(i), LB(i), "c"), spref);
+    [v,ka,kb] = intersect(LA(i), LB(i), "c");
+    assert_checkequal(v, spref);
+    assert_checkequal(ka, [6 1 3]);
+    assert_checkequal(kb, [1 5 4]);
+    assert_checkequal(sparse(LA(i)(:,ka)), v);
+    assert_checkequal(sparse(LB(i)(:,kb)), v);
+
+    assert_checkequal(intersect(LA(i)', LB(i)', "r"), spref');
+    [v,ka,kb] = intersect(LA(i)', LB(i)', "r");
+    assert_checkequal(v, spref');
+    assert_checkequal(ka, [6 1 3]);
+    assert_checkequal(kb, [1 5 4]);
+    assert_checkequal(sparse(LA(i)(:,ka))', v);
+    assert_checkequal(sparse(LB(i)(:,kb))', v);
+end
+
+// ============
+// Sparse reals
+// ============
+A = sparse([-3 5 %nan 0 1e20 -%inf 123 1000]);
+B = sparse([1 %nan -3 123 4530 0 -%inf ]);
+assert_checkequal(intersect(A,B), sparse([-%inf -3 0 123]));
+[v, ka, kb] = intersect(A,B);
+assert_checkequal(v, sparse([-%inf -3 0 123]));
+assert_checkequal([ka ; kb], [6 1 4 7 ; 7 3 6 4]);
+//
+A = sparse([1  0  0  0  0  1  2  0  2  0
+            2  0  2  0  1  0  1  0  0  2
+            2  0  0  0  0  1  0  0  0  0 ]);
+B = sparse([2  1  1  0  1  0  0  2  2  0
+            2  0  1  1  0  0  1  1  0  0
+            0  2  0  0  1  1  1  2  0  0 ]);
+Ref = sparse([0  0  1  2
+              0  1  0  0
+              0  0  1  0 ]);
+kaRef  = [2  5  6  9];
+kbRef  = [10  4  5  9];
+
+assert_checkequal(intersect(A,B,"c"), Ref);
+[v, ka, kb] = intersect(A,B,"c");
+assert_checkequal(v, Ref);
+assert_checkequal(ka, kaRef);
+assert_checkequal(kb, kbRef);
+
+assert_checkequal(intersect(A',B',"r"), Ref');
+[v, ka, kb] = intersect(A',B',"r");
+assert_checkequal(v, Ref');
+assert_checkequal(ka, kaRef);
+assert_checkequal(kb, kbRef);
+
+
+// ==============
+// Sparse complex
+// ==============
+r = [-3  5   %nan 0   1e20 %inf 123  0];
+i = [1  %nan -3   123 4530 0    -%inf 1];
+A = sparse(complex(r,i))
+r = [-3  0  1e20 %nan 0    %inf 123 ];
+i = [0   1  1    -3   123  0   -%inf];
+B = sparse(complex(r,i))
+Ref = sparse(complex([0 0 123 %inf], [1 123 -%inf 0]));
+assert_checkequal(intersect(A,B), Ref);
+
+// "c" and "r" modes
+// -----------------
+r  = [0.   1.   0.   0.   0.   1.   0.   1.   0.   0.
+      1.   0.   1.   1.   1.   0.   1.   0.   1.   0. ];
+i  = [1.   0.   0.   1.   1.   0.   1.   0.   0.   0.
+      1.   1.   0.   0.   1.   0.   0.   0.   1.   0. ];
+A = sparse(complex(r,i));
+
+r  = [0.   1.   1.   1.   0.   1.   0.   0.   0.   0.
+      1.   1.   1.   1.   1.   0.   0.   1.   0.   1. ];
+i  = [0.   0.   1.   1.   1.   1.   1.   0.   1.   1.
+      0.   0.   0.   0.   1.   0.   0.   1.   1.   1. ];
+B = sparse(complex(r,i));
+
+Ref = sparse([0,  0   ,   %i ;
+              1,  1+%i, 1+%i]);
+kaRef  = [3 9 1];
+kbRef  = [1 8 5];
+
+assert_checkequal(intersect(A,B,"c"), Ref);
+[v, ka, kb] = intersect(A,B,"c");
+assert_checkequal(v, Ref);
+assert_checkequal(ka, kaRef);
+assert_checkequal(kb, kbRef);
+
+assert_checkequal(intersect(A',B',"r"), Ref');
+[v, ka, kb] = intersect(A',B',"r");
+assert_checkequal(v, Ref');
+assert_checkequal(ka, kaRef);
+assert_checkequal(kb, kbRef);