* Bugs 15838 15839 15842 16452 16454 fixed: gsort() for all sparse in all modes 84/21484/5
Samuel GOUGEON [Wed, 3 Jun 2020 01:23:54 +0000 (03:23 +0200)]
  http://bugzilla.scilab.org/15839 : gsort() for sparse: only vectors of
                          doubles could be sorted, and only in "g" mode,
                          and without multi-level sorting. Now,
     * Any 2D array of doubles can be sorted in "g" mode (not only vectors).
     * Any array of doubles can be sorted in any other r, c, lr, lc mode.
     * Any boolean array can be sorted in any g, r, c, lr, lc mode.

  http://bugzilla.scilab.org/15838 : [..,K]=gsort(): K missed indices of zeros.
  http://bugzilla.scilab.org/15842 : unique(sparseMatrix) yielded an error.
  http://bugzilla.scilab.org/16452 : setdiff(sparse([1 3 0 2]), sparse([3 7])) wrong
  http://bugzilla.scilab.org/15842 : gsort(Sparse) with NaN => error

--> test_run elementary_functions gsort*
   TMPDIR = C:\Users\I\AppData\Local\Temp\SCI_TMP_4540_1271

   001/007 - [elementary_functions] gsort_sparse................passed
   002/007 - [elementary_functions] gsort_multilevel_text.......passed
   003/007 - [elementary_functions] gsort_multilevel_polynomials passed
   004/007 - [elementary_functions] gsort_multilevel_numbers....passed
   005/007 - [elementary_functions] gsort_multilevel_complex....passed
   006/007 - [elementary_functions] gsort_boolean...............passed
   007/007 - [elementary_functions] gsort.......................passed
   --------------------------------------------------------------------------
 ans  =
  T

Change-Id: I0be52e6f9416ad7e7279ad9f7a8eb9db941d7ac0

scilab/CHANGES.md
scilab/modules/elementary_functions/help/en_US/searchandsort/gsort.xml
scilab/modules/elementary_functions/help/ru_RU/searchandsort/gsort.xml [new file with mode: 0644]
scilab/modules/elementary_functions/macros/%b_gsort.sci
scilab/modules/elementary_functions/macros/%sp_gsort.sci
scilab/modules/elementary_functions/macros/%spb_gsort.sci [new file with mode: 0644]
scilab/modules/elementary_functions/tests/nonreg_tests/bug_15842.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/nonreg_tests/bug_16452.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/nonreg_tests/bug_16454.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/gsort_boolean.tst
scilab/modules/elementary_functions/tests/unit_tests/gsort_sparse.tst

index 2850755..dd3dc99 100644 (file)
@@ -191,6 +191,10 @@ Feature changes and additions
 * `atomsGetInstalledPath` is no longer sensitive to the case or completeness of the modules names. Providing the modules versions is now optional.
 * `function` replaces `mc` as the new overloading code for functions in Scilab language.
 
+6.1.1
+* `gsort` is fully enabled for sparse vectors and 2D matrices, in all `g, r, c, lr, lc` methods. It was formerly limited to real or complex vectors and only to the `g` mode. All boolean, real or complex vector or 2D matrices can now be sorted with any method. Multi-level sorting is enabled for all types of sparse input.
+* `unique` is enabled for any 2D sparse arrays.
+
 Help pages:
 -----------
 
@@ -268,6 +272,8 @@ Bug Fixes
 * [#8059](https://bugzilla.scilab.org/8059): A local `.wgetrc` config file could make troubles in `atomsDownload`.
 * [#9909](https://bugzilla.scilab.org/9909): In the help browser, add a way to open the online version of the current page.
 * [#12889](https://bugzilla.scilab.org/12889): In the help browser, add a menu allowing to select the language of help pages, regardless of the language of the session.
+* [#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. 
 * [#16106](https://bugzilla.scilab.org/16106): Xcos sciblk4 user-defined blocks did not handle opar and odstate/oz correctly.
 * [#16337](https://bugzilla.scilab.org/16337): The 3rd output of `[U,km,ku] = unique(..)` was not implemented.
 * [#16342](https://bugzilla.scilab.org/16342): `strcat()` was much slower in Scilab 6.0.2.
@@ -284,6 +290,8 @@ Bug Fixes
 * [#16406](https://bugzilla.scilab.org/16406): `edit_curv` yielded an error when reading data.
 * [#16408](https://bugzilla.scilab.org/16408): toJSON(var, indent, filename) is the right call sequence. Documentation has been udpated.
 * [#16445](https://bugzilla.scilab.org/16445): `colorbar(..)` ignored how to guess `umin` and `umax` for a Champ object (with .colored="on").
+* [#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.
 
 
 ### Bugs fixed in 6.1.0:
index 5051b33..632510e 100644 (file)
@@ -19,7 +19,7 @@
           xmlns:scilab="http://www.scilab.org" xml:id="gsort" xml:lang="en">
     <refnamediv>
         <refname>gsort</refname>
-        <refpurpose>sorting by quick sort algorithm</refpurpose>
+        <refpurpose>sorts boolean, numerical and text arrays</refpurpose>
     </refnamediv>
     <refsynopsisdiv>
         <title>Syntax</title>
@@ -37,8 +37,9 @@
             <varlistentry>
                 <term>A</term>
                 <listitem>
-                    Scalar, vector, matrix or hypermatrix of booleans, integers, real or complex
-                    numbers, or text, or a sparse vector of real numbers.
+                    Scalar, vector, matrix or hypermatrix of booleans, integers, real or
+                    complex numbers, or text. Sparse matrices of real numbers,
+                    of complex numbers, or of booleans can also be sorted.
                     <note>
                         Overloading for unhandled types is allowed.
                     </note>
             Extended UTF characters are supported.
         </para>
         <para>
+            Sorting boolean arrays is mostly useful with the "r", "c", "lr" or "lc" methods.
+        </para>
+        <para>
             <note>
                 Whatever is the chosen method, <emphasis role="bold">the algorithm preserves the
                 relative order of elements with equal values.
@@ -394,26 +398,31 @@ v = ['Scilab' '3.1'
 ]]></screen>
         </para>
         <para>
-            Lexicographic sorting of columns:
+            Lexicographic sorting of boolean columns:
         </para>
         <para>
         <programlisting role="example"><![CDATA[
-m  = [ 0.  1.  0.  1.  1.  1.  0.  1.
-       0.  0.  1.  1.  1.  1.  0.  0.
-       0.  0.  1.  1.  0.  0.  0.  0.
-     ];
-
-[s, k] = gsort(m, "lc", "i")  // sorting columns
+m  = [ 0 1 0 1 1 1 0 1
+       0 0 1 1 1 1 0 0
+       0 0 1 1 0 0 0 0 ]==1;
+m
+[s, k] = gsort(m, "lc")  // sorting columns in decreasing order
 ]]>     </programlisting>
-            <screen><![CDATA[
---> [s, k] = gsort(m, "lc", "i")
+        <screen><![CDATA[
+--> m
+ m  =
+  F T F T T T F T
+  F F T T T T F F
+  F F T T F F F F
+
+--> [s, k] = gsort(m, "lc")
  s  =
-   0.   0.   0.   1.   1.   1.   1.   1.
-   0.   0.   1.   0.   0.   1.   1.   1.
-   0.   0.   1.   0.   0.   0.   0.   1.
+  T T T T T F F F
+  T T T F F T F F
+  T F F F F T F F
 
  k  =
-   1.   7.   3.   2.   8.   5.   6.   4.
+   4.   5.   6.   2.   8.   3.   1.   7.
 ]]></screen>
         </para>
     <refsect3>
@@ -616,10 +625,21 @@ P = evstr(P)
                         </listitem>
                         <listitem>
                             Multilevel sorting added with the rankFuncs option.
+                            Complete sorting of complex numbers is now possible.
                         </listitem>
                     </itemizedlist>
                 </revremark>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revremark>
+                    gsort() was formerly limited to real or complex vectors,
+                    and only to the `g` method. It is now fully enabled for sparse
+                    vectors and 2D matrices of booleans, real or complex numbers,
+                    in all `g, r, c, lr, lc` methods. Multi-level sorting is
+                    enabled for all types of sparse input.
+                </revremark>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
diff --git a/scilab/modules/elementary_functions/help/ru_RU/searchandsort/gsort.xml b/scilab/modules/elementary_functions/help/ru_RU/searchandsort/gsort.xml
new file mode 100644 (file)
index 0000000..3ed304f
--- /dev/null
@@ -0,0 +1,658 @@
+<?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
+ * Copyright (C) 2020 - Stanislav KROTER
+ *
+ * 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="gsort" xml:lang="ru">
+    <refnamediv>
+        <refname>gsort</refname>
+        <refpurpose>сортировка по алгоритму быстрой сортировки</refpurpose>
+    </refnamediv>
+    <refsynopsisdiv>
+        <title>Синтаксис</title>
+        <synopsis>
+            B = gsort(A)
+            B = gsort(A, method)
+            B = gsort(A, method, direction)
+            B = gsort(A, method, directions, rankFuncs)
+            [B, k] = gsort(..)
+        </synopsis>
+    </refsynopsisdiv>
+    <refsection>
+        <title>Аргументы</title>
+        <variablelist>
+            <varlistentry>
+                <term>A</term>
+                <listitem>
+                    Скаляр, вектор, матрица или гиперматрица логических значений, целых,
+                    вещественных или комплексных чисел, или текстов. Sparse matrices of
+                    real numbers, of complex numbers, or of booleans can also be sorted.
+                    <note>
+                        Разрешена перегрузка необрабатываемых типов.
+                    </note>
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>method</term>
+                <listitem>
+                    Ключевое слово: метод сортировки:
+                    <informaltable>
+                        <tr valign="top">
+                            <th>'g'</th><td>:</td>
+                            <td>Общая сортировка: сортируются все элементы в <literal>A</literal>
+                                ( метод по умолчанию).
+                            </td>
+                        </tr>
+                        <tr valign="top">
+                            <th>'r'</th><td>:</td>
+                            <td>Сортируются строки в каждом столбце в <literal>A</literal>.</td>
+                        </tr>
+                        <tr valign="top">
+                            <th>'c'</th><td>:</td>
+                            <td>Сортируются столбцы в каждой строке в <literal>A</literal>.</td>
+                        </tr>
+                        <tr valign="top"><th>'lr'</th><td>:</td>
+                            <td>
+                                лексикографическая сортировка строк в <literal>A</literal>:
+                                Сортируются строки в соответствии со значениями в первом столбце.
+                                Если группа сортированных строк имеет то же значение, что и в
+                                столбце №1, то группа пересортировывается в соответствии со
+                                значениями в столбце №2, и так далее. Не применимо к гиперматрицам.
+                            </td>
+                        </tr>
+                        <tr valign="top"><th>'lc'</th><td>:</td>
+                            <td>
+                                лексикографическая сортировка столбцов в <literal>A</literal>
+                                (не для гиперматриц).
+                            </td>
+                        </tr>
+                    </informaltable>
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>direction</term>
+                <listitem>
+                    направление сортировки:
+                    "d": в порядке уменьшения (по умолчанию);
+                    "i": в порядке увеличения.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>directions</term>
+                <listitem>
+                    вектор символов "i" и "d", у которого столько же элементов, сколько
+                    элементов имеет <varname>rankFuncs</varname>.
+                    <literal>directions(k)</literal> используется для
+                    <varname>rankFuncs(k)</varname>.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>rankFuncs</term>
+                <listitem>
+                    список <literal>list()</literal>, элементы которого имеют следующие типы:
+                    <itemizedlist>
+                        <listitem>
+                            идентификатор <literal>fun</literal> функции на языке Scilab,
+                            либо встроенной функции.
+                        </listitem>
+                        <listitem>
+                            : двоеточие. Ставится для такой <literal>fun</literal>, для которой
+                            <literal>fun(A)</literal> возвращает <literal>A</literal>.
+                        </listitem>
+                        <listitem>
+                            список <literal>list(fun, param1, param2,..)</literal>, в котором
+                            <itemizedlist>
+                                <listitem>
+                                    <literal>fun</literal> - это идентификатор функции Scilab или
+                                    встроенной функции.
+                                </listitem>
+                                <listitem>
+                                    <literal>param1, param2,..</literal> - это параметры.
+                                </listitem>
+                            </itemizedlist>
+                            так что будет вызываться <literal>fun(A, param1, param2, ..)</literal>.
+                        </listitem>
+                    </itemizedlist>
+                    <para>
+                        Функции <literal>fun</literal> должны удовлетворять следующим условиям:
+                        <itemizedlist>
+                            <listitem>
+                                должны поддерживаться <literal>R=fun(A)</literal> или
+                                <literal>R=fun(A, param1, param2,..)</literal>.
+                            </listitem>
+                            <listitem>
+                                <literal>fun</literal> должна работать поэлементно, то есть:
+                                <literal>size(R)==size(A)</literal> и <literal>R(k)</literal>
+                                по сути равно <literal>A(k)</literal>
+                            </listitem>
+                            <listitem>
+                                <literal>R</literal> должен быть простым сортируемым типом:
+                                логические значения, целые числа, вещественные значения, текст.
+                            </listitem>
+                        </itemizedlist>
+                    </para>
+                    <para>
+                        <note>
+                            Если <literal>A</literal> содержит комплексные числа, то можно
+                            определить обычные функции <literal>real, imag, abs, atan</literal>.
+                            Тогда <literal>atan(imag(A),real(A))</literal> будет вызываться
+                            вместо <literal>atan(A)</literal>.
+                        </note>
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>B</term>
+                <listitem>
+                    Сортированный массив того же типа, кодирования и размера, что и <literal>A</literal>.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>k</term>
+                <listitem>
+                    Массив десятичных целых чисел размера <literal>size(A)</literal>:
+                    исходные индексы элементов <literal>B</literal> в <literal>A</literal>.
+                    Если <literal>A</literal> матрица, то в соответствии с выбранным методом
+                    <table>
+                    <tr>
+                        <th valign="top">"g"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> это матрица размером <literal>size(A)</literal>:
+                            <literal>k(i)</literal> - это линейный индекс элемента
+                            <literal>B(i)</literal> в <literal>A</literal> такой, что <literal>B(:) = A(k)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"r"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> это матрица размером <literal>size(A)</literal>:
+                            <literal>k(i,j)</literal> равна <literal>1 ≤ index ≤ size(A,1)</literal>
+                            элемента <literal>B(i,j)</literal> в столбце <literal>A(:,j)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"c"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> это матрица размером <literal>size(A)</literal>:
+                            <literal>k(i,j)</literal> равна <literal>1 ≤ index ≤ size(A,2)</literal>
+                            элемента <literal>B(i,j)</literal> в строке <literal>A(i,:)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"lr"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> - это столбец размером <literal>size(A,1)</literal>
+                            такой, что <literal>B = A(k,:)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"lc"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> - это строка размером <literal>size(A,2)</literal>
+                            такая, что <literal>B = A(:,k)</literal>.
+                        </td>
+                    </tr>
+                    </table>
+                    <para/>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsection>
+    <refsection>
+        <title>Описание</title>
+        <para>
+            Функция <literal>gsort</literal> выполняет "быструю сортировку" различных типов
+            данных. По умолчанию сортировка выполняется в порядке убывания.
+        </para>
+        <para>
+            Значения <literal>%nan</literal> считаются больше, чем <literal>%inf</literal>.
+        </para>
+        <para>
+            Комплексные числа по умолчанию сортируются только в соответствии с их модулями.
+            Полная сортировка может быть достигнута, используя многоуровневый режим, через
+            аргументы <varname>rankFuncs</varname> и <varname>directions</varname>.
+            Например:
+        </para>
+        <para>
+            <literal>M = gsort(C, "g", ["i" "d"], list(real, imag))</literal><para/>
+            отсортирует массив <literal>C</literal>, сначала в порядке возрастания вещественных
+            частей, и элементов у которых вещественные части равны, а затем в порядке убывания
+            мнимых частей. Многоуровневый режим детально описан в соответствующем подразделе ниже.
+        </para>
+        <para>
+            Тексты сортируются в алфавитном порядке, с учётом регистра.
+            Поддерживаются расширенные UTF-символы.
+        </para>
+        <para>
+            Сортировка массивов логических значений главным образом полезна с помощью методов
+            "r", "c", "lr" или "lc".
+        </para>
+        <para>
+            <note>
+                Какой бы метод ни выбрали, <emphasis role="bold">алгоритм сохраняет относительный порядок элементов с равными значениями</emphasis>.
+            </note>
+        </para>
+        <refsect3>
+            <title>Методы сортировки</title>
+            <para>
+                <emphasis role="bold">B = gsort(A,'g', ..)</emphasis> сортирует все элементы в
+                <varname>A</varname> и сохраняет сортированные элементы в первом столбце сверху
+                вниз, а затем во втором столбце и т.д.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'c', ..)</emphasis> сортирует каждую строку в
+                <varname>A</varname>. Каждый сортированный элемент находится в той же строке, что
+                и в <varname>A</varname>, но возможно в другом столбце в соответствии с его
+                рангом сортировки в строке.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'r', ..)</emphasis> сортирует каждый столбец в
+                <varname>A</varname>. Каждый сортированный элемент находится в том же столбце,
+                что и в <varname>A</varname>, но возможно в другой строке в соответствии с его
+                рангом сортировки в строке.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'lr', ..)</emphasis> сортирует строки в
+                <varname>A</varname> целиком в лексическом порядке. Две строки сравниваются и
+                сортируются следующим образом. Сравниваются элементы их первых столбцов. Если их
+                ранги не равны, то обе строки сортируются соответствующим образом. В противном
+                случае сравниваются элементы их вторых столбцов, и т.д. вплоть до последнего
+                столбца, если это потребуется.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'lc', ..)</emphasis> сортируются столбцы в
+                <varname>A</varname> целиком, в лексикографическом порядке (см. выше).
+            </para>
+        </refsect3>
+        <refsect3>
+            <title>Многоуровневая сортировка</title>
+            <para>
+                Как отмечено выше, когда два сравниваемых элемента имеют одинаковые ранги, их
+                исходный относительный порядок в <varname>A</varname> сохраняется в
+                результирующей <varname>B</varname>.
+            </para>
+            <para>
+                Однако, во многих случаях, выходящих за рамки, может быть полезна и затребована
+                многоуровневая сортировка:
+                после выполнения первой сортировки в соответствии с первым критерием и
+                направлением сортировки, можно указать второй критерий и направление сортировки и
+                применить их к одинаковым элементам 1-го ранга, собранным после первой
+                сортировки.
+            </para>
+            <para>
+                Если после двух первых сортировок некоторые элементы по-прежнему имеют одинаковый
+                ранг, то можно определить и использовать третий уровень сортировки и т.д.
+            </para>
+            <para>
+                <emphasis role="bold">Применимые примеры</emphasis> (смотрите также раздел
+                Примеры):
+                <orderedlist>
+                    <listitem>
+                        <emphasis>Сортировка матрицы <literal>C</literal> комплексных чисел,
+                            сначала в порядке увеличения модуля, затем в порядке увеличения
+                            фазы</emphasis>:
+                        <para/>
+                        <literal>gsort(C, "g", ["i" "i"], list(abs, atan))</literal>
+                        <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Сортировка столбцов матрицы <literal>T</literal> текстов,
+                        сначала в порядке увеличения длины, затем в обратном алфавитном
+                        порядке</emphasis>:
+                        <para/>
+                        <literal>gsort(T, "c", ["i" "d"], list(length, :))</literal>
+                        <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Сортировка матрицы <literal>P</literal> полиномов,
+                        сначала в порядке увеличения степени, затем в порядке уменьшения значения постоянного коэффициента 0-й степени</emphasis>:
+                        <screen>
+function c = get_coef(p, i)
+    // i: степень возвращаемого коэффициента
+    c = matrix(coeff(p(:))(:,i+1), size(p))
+endfunction
+
+gsort(P, "c", ["i" "d"], list(degree, list(get_coef,0)))
+</screen>
+                        В этом примере функция второго ранжирования позволяет определить степень
+                        <literal>i</literal> того коэффициента, который рассматривается в
+                        качестве значения вторичной сортировки.
+                    <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Сортировка матрицы <literal>D</literal> десятичных чисел,
+                        сначала в порядке возрастания целых частей, затем в порядке уменьшения дробных частей</emphasis>:
+                        <screen>
+function r = get_frac(numbers)
+    r = numbers - int(numbers)
+endfunction
+
+gsort(D, "g", ["i" "d"], list(int, get_frac))
+</screen>
+                    </listitem>
+                    <para/>
+                </orderedlist>
+            </para>
+        </refsect3>
+    </refsection>
+    <refsection>
+        <title>Примеры</title>
+        <para>
+            Сортировка элементов в строках:
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+m = [ 0.  2.  1.  2.  1.  0.
+      1.  1.  3.  1.  0.  3.
+      2.  3   3.  2.  1.  1. ];
+
+[s, k] = gsort(m, "c")
+]]>     </programlisting>
+        <screen><![CDATA[
+--> [s, k] = gsort(m, "c")
+ s  =
+   2.   2.   1.   1.   0.   0.
+   3.   3.   1.   1.   1.   0.
+   3.   3.   2.   2.   1.   1.
+
+ k  =
+   2.   4.   3.   5.   1.   6.
+   3.   6.   1.   2.   4.   5.
+   2.   3.   1.   4.   5.   6.
+]]></screen>
+        </para>
+        <para>
+            Лексикографическая сортировка строк:
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+v = ['Scilab' '3.1'
+     'xcos'   '4.0'
+     'xcos'   '3.1'
+     'Scilab' '2.7'
+     'xcos'   '2.7'
+     'Scilab' '4.0'];
+
+[s, k] = gsort(v,'lr','i'); s, k'
+]]>     </programlisting>
+            <screen><![CDATA[
+--> [s, k] = gsort(v,'lr','i'); s, k'
+ s  =
+  "Scilab"  "2.7"
+  "Scilab"  "3.1"
+  "Scilab"  "4.0"
+  "xcos"    "2.7"
+  "xcos"    "3.1"
+  "xcos"    "4.0"
+
+ ans  =
+   4.   1.   6.   5.   3.   2.
+]]></screen>
+        </para>
+        <para>
+            Лексикографическая сортировка логических столбцов:
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+m  = [ 0 1 0 1 1 1 0 1
+       0 0 1 1 1 1 0 0
+       0 0 1 1 0 0 0 0 ]==1;
+m
+[s, k] = gsort(m, "lc")  // сортировка столбцов в порядке убывания
+]]>     </programlisting>
+        <screen><![CDATA[
+--> m
+ m  =
+  F T F T T T F T
+  F F T T T T F F
+  F F T T F F F F
+
+--> [s, k] = gsort(m, "lc")
+ s  =
+  T T T T T F F F
+  T T T F F T F F
+  T F F F F T F F
+
+ k  =
+   4.   5.   6.   2.   8.   3.   1.   7.
+]]></screen>
+        </para>
+        <refsect3>
+        <title>Многоуровневая сортировка</title>
+        <para>
+            <emphasis role="bold">С некоторыми десятичными числами</emphasis>:
+            Сначала сортировка в порядке возрастания целых частей, а затем в порядке убывания
+            дробных частей.
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+// Функция получения дробных частей
+function r = get_frac(d)
+    r = d - int(d)
+endfunction
+
+// Несортированные данные
+d = [
+   2.1   0.1   1.3   1.2   0.1   1.2
+   0.3   1.2   2.3   0.3   1.2   2.1
+   0.1   1.2   1.1   1.2   2.2   1.1
+   2.3   1.3   0.1   2.3   0.1   0.1
+   0.1   2.2   2.1   0.2   1.1   0.3
+  ];
+// Сортировка
+[r, k] = gsort(d, "g", ["i" "d"], list(int, get_frac))
+]]>     </programlisting>
+        <screen><![CDATA[
+ r  =
+   0.3   0.1   0.1   1.2   1.1   2.2
+   0.3   0.1   1.3   1.2   1.1   2.2
+   0.3   0.1   1.3   1.2   2.3   2.1
+   0.2   0.1   1.2   1.2   2.3   2.1
+   0.1   0.1   1.2   1.1   2.3   2.1
+
+ k  =
+   2.    5.    29.   16.   25.   10.
+   17.   6.    9.    18.   28.   23.
+   30.   14.   11.   22.   4.    1.
+   20.   21.   7.    26.   12.   15.
+   3.    24.   8.    13.   19.   27.
+]]></screen>
+        </para>
+        <para>
+            <emphasis role="bold">С комплексными числами</emphasis>:
+            Сортировка сначала в порядке увеличения вещественных частей, затем в порядке
+            увеличения мнимых частей.
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+//c = [-1 1 ; -1 0; 0 2; 0 %nan; 0 -1; 0 %inf ; 0 1; 1 %nan ; 1 1; 1 -1 ; -1 %nan ; 1 -%inf]
+//c = matrix(squeeze(grand(1,"prm",complex(c(:,1), c(:,2)))), [3,4])
+s = "complex([0,0,-1,-1;0,-1,1,1;1,1,0,0]," + ..
+            "[%inf,2,%nan,1;-1,0,-1,%nan;1,-%inf,1,%nan])";
+c = evstr(s)
+[r, k] = gsort(c, "g", ["i" "i"], list(real, imag))
+]]>     </programlisting>
+    <screen><![CDATA[
+--> c = evstr(s)
+ c  =
+   0. + Infi   0. + 2.i   -1. + Nani  -1. + i
+   0. - i     -1. + 0.i    1. - i      1. + Nani
+   1. + i      1. - Infi   0. + i      0. + Nani
+
+ r  =
+  -1. + 0.i    0. - i     0. + Infi   1. - i
+  -1. + i      0. + i     0. + Nani   1. + i
+  -1. + Nani   0. + 2.i   1. - Infi   1. + Nani
+
+ k  =
+   5.    2.   1.    8.
+   10.   9.   12.   3.
+   7.    4.   6.    11.
+]]></screen>
+        </para>
+        <para>
+            <emphasis role="bold">С некоторыми текстами:</emphasis>
+            Сортировка строк в столбцах, сначала в порядке увеличения длины, затем в алфавитном
+            порядке.
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+t = [
+  "cc"    "ca"    "ab"    "bbca"  "b"     "ccbc"  "aab"   "bca"
+  "ac"    "bba"   "aba"   "bb"    "a"     "cac"   "b"     "b"
+  "aaaa"  "ac"    "b"     "bbca"  "bb"    "bc"    "aa"    "ca"
+  "c"     "ba"    "cbb"   "a"     "aab"   "abbb"  "ac"    "c"
+  "cbb"   "b"     "cabb"  "bccc"  "aba"   "acb"   "acb"   "b"
+  "cba"   "cc"    "a"     "abbb"  "ab"    "cc"    "bba"   "caaa"
+  ];
+
+[r, k] = gsort(t, "r", ["i" "i"], list(length, :))
+]]>     </programlisting>
+        <screen><![CDATA[
+--> [r, k] = gsort(t, "r", ["i" "i"], list(length, :))
+ r  =
+  "c"     "b"    "a"     "a"     "a"    "bc"    "b"    "b"
+  "ac"    "ac"   "b"     "bb"    "b"    "cc"    "aa"   "b"
+  "cc"    "ba"   "ab"    "abbb"  "ab"   "acb"   "ac"   "c"
+  "cba"   "ca"   "aba"   "bbca"  "bb"   "cac"   "aab"  "ca"
+  "cbb"   "cc"   "cbb"   "bbca"  "aab"  "abbb"  "acb"  "bca"
+  "aaaa"  "bba"  "cabb"  "bccc"  "aba"  "ccbc"  "bba"  "caaa"
+
+ k  =
+   4.   5.   6.   4.   2.   3.   2.   2.
+   2.   3.   3.   2.   1.   6.   3.   5.
+   1.   4.   1.   6.   6.   5.   4.   4.
+   6.   1.   2.   1.   3.   2.   1.   3.
+   5.   6.   4.   3.   4.   4.   5.   1.
+   3.   2.   5.   5.   5.   1.   6.   6.
+]]></screen>
+        </para>
+<!--  Display up to 6.0.2 (without extra blank lines)
+ r  =
+!c     b    a     a     a    bc    b    b     !
+!ac    ac   b     bb    b    cc    aa   b     !
+!cc    ba   ab    abbb  ab   acb   ac   c     !
+!cba   ca   aba   bbca  bb   cac   aab  ca    !
+!cbb   cc   cbb   bbca  aab  abbb  acb  bca   !
+!aaaa  bba  cabb  bccc  aba  ccbc  bba  caaa  !
+-->
+        <para>
+            <emphasis role="bold">С некоторыми полиномами:</emphasis>
+            Сортировка сначала в порядке уменьшения значений x^0, затем в порядке увеличения
+            степеней.
+        </para>
+        <para>
+        <programlisting role="example"><![CDATA[
+function c = get_coef(p, d)
+    // d : степени возвращаемых коэффициентов
+    c = matrix(coeff(p(:))(:,d+1), size(p))
+endfunction
+
+P = ["[-x,1-2*x,2+2*x,1-x,2,-1-x;"
+     "1-x,-1+x,-1,x,1+2*x,2*x;"
+     "-2+x,1,-2,2+x,-x,-1-x]"];
+
+x = varn(%s,"x");
+P = evstr(P)
+
+[r, k] = gsort(P, "g", ["d" "i"], list(list(get_coef, 0), degree))
+]]>     </programlisting>
+        <screen><![CDATA[
+--> P = evstr(P)
+ P  =
+  -x      1 -2x   2 +2x   1 -x   2      -1 -x
+   1 -x  -1 +x   -1       x      1 +2x   2x
+  -2 +x   1      -2       2 +x   -x     -1 -x
+
+--> [r, k] = gsort(P, "g", ["d" "i"], list(list(get_coef, 0), degree))
+ r  =
+  2      1      1 -x   x   -1     -1 -x
+  2 +2x  1 -x   1 +2x  -x  -1 +x  -2
+  2 +x   1 -2x  -x     2x  -1 -x  -2 +x
+
+ k  =
+   13.   6.   10.   11.   8.    18.
+   7.    2.   14.   15.   5.    9.
+   12.   4.   1.    17.   16.   3.
+]]></screen>
+        </para>
+    </refsect3>
+    </refsection>
+    <refsection role="see also">
+        <title>Смотрите также</title>
+        <simplelist type="inline">
+            <member>
+                <link linkend="comparison">сравнение</link>
+            </member>
+            <member>
+                <link linkend="strcmp">strcmp</link>
+            </member>
+            <member>
+                <link linkend="find">find</link>
+            </member>
+            <member>
+                <link linkend="overloading">перегрузка</link>
+            </member>
+        </simplelist>
+    </refsection>
+    <refsection>
+        <title>Литература</title>
+        <para>Quick sort algorithm from Bentley &amp; McIlroy's "Engineering a
+            Sort Function". Software---Practice and Experience,
+            23(11):1249-1265
+        </para>
+    </refsection>
+    <refsection>
+        <title>История</title>
+        <revhistory>
+            <revision>
+                <revnumber>5.4.0</revnumber>
+                <revremark>
+                    Теперь gsort() может быть перегружена для неуправляемых типов.
+                </revremark>
+            </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revremark>
+                    <itemizedlist>
+                        <listitem>
+                            Теперь можно сортировать логические значения.
+                        </listitem>
+                        <listitem>
+                            Многоуровневая сортировка, добавленная с помощью опции rankFuncs.
+                        </listitem>
+                    </itemizedlist>
+                </revremark>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revremark>
+                    gsort() ранее была ограничена вещественными или комплексными
+                    векторами и только методом 'g'. Теперь она полностью способна
+                    к работе с разрежёнными векторами и двумерными матрицами логических,
+                    вещественных или комплексных чисел, всеми методами 'g, r, c, lr, lc'.
+                    Многоуровневая сортировка возможна для всех типов разрежённых входных данных.
+                </revremark>
+            </revision>
+        </revhistory>
+    </refsection>
+</refentry>
index 30418fc..c089534 100644 (file)
@@ -11,6 +11,7 @@
 
 function varargout = %b_gsort(varargin)
     // Boolean hypermatrices are completely processed in %hm_gsort
+    // Sparse boolean matrices are sent to %spb_gsort
 
     b = iconvert(varargin(1), 1);
     if argn(1)==1 then
index c5ad712..5c9882d 100644 (file)
@@ -1,8 +1,8 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) DIGITEO - 2009 - Allan CORNET
 // Copyrifht (C) 2012 - Scilab Enterprises - Adeline CARNIS
-//
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2018 - 2020 - Samuel GOUGEON : complete rewritting
 //
 // 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.
 // For more information, see the COPYING file which you should have received
 // along with this program.
 
-function [A, k] = %sp_gsort(A, optsort, directionsort)
-    rhs = argn(2);
-    lhs = argn(1);
-    // arguments by default in gsort
-    select rhs
-    case 1
-        optsort = "g";
-        directionsort = "d";
-    case 2
-        // optsort can be: 'r', 'c', 'g', 'lr', 'lc'
-        pos_opts = find(optsort == ["r", "c", "g", "lr", "lc"]);
-        if pos_opts == [] then
-            error(msprintf(_("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"), "gsort", 2, "r", "c", "g", "lr", "lc"));
+function [A, k] = %sp_gsort(A, sortype, sortdir, criteria)
+    lhs = argn(1)
+    k = 0
+
+    // ===================
+    // CHECKING PARAMETERS
+    // ===================
+    if ~isdef("sortype", "l") then
+        sortype = "g"
+    else
+        sortype = convstr(sortype(1))
+        if ~or(sortype == ["g", "r", "c", "lr", "lc"]) then
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "gsort", 2, """g"",""r"",""c"",""lr"",""lc"""))
         end
-        directionsort = "d";
+    end
+    if ~isdef("sortdir", "l")
+        sortdir = "d"
     else
-        // optsort can be: 'r', 'c', 'g', 'lr', 'lc'
-        pos_opts = find(optsort == ["r", "c", "g", "lr", "lc"]);
-        // directionsort can be: 'd' or 'i'
-        pos_direction = find(directionsort == ["d", "i"]);
-        if pos_opts == [] then
-            error(msprintf(_("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"), "gsort", 2, "r", "c", "g", "lr", "lc"));
+        sortdir = convstr(sortdir)
+        if and(sortdir <> "d" & sortdir <> "i") then
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "gsort", 3, """i"",""d"""))
         end
-        if pos_direction == [] then
-            error(msprintf(_("%s: Wrong value for input argument #%d: ''%s'' or ''%s'' expected.\n"), "gsort", 3, "d", "i"));
+        if ~isdef("criteria","l")
+            sortdir = sortdir(1)
         end
     end
 
-    [ij, v, mn] = spget(A);
-    if mn(1) <> 1 & mn(2) <> 1 then
-        error(msprintf(_("%s: Wrong size for input argument #%d: sparse vectors expected.\n"), "gsort", 1));
+    // ==========
+    // PROCESSING
+    // ==========
+    if sortype=="c"
+        A = A.'
     end
+    // Gets non zero values by increasing linearized indices:
+    [ij, v, mn] = spget(A.');
+    ij = ij(:,[2 1]);
+    mn = mn([2 1]);
 
-    if mn(1) == 1 then
-        // if A is a row vector and optsort = 'r', the result is the
-        // first input argument
-        if strcmp(optsort, "r") == 0 |strcmp(optsort, "lr") == 0 | v == [] then
-            A = A;
-            if lhs == 2 then
-                if strcmp(optsort, "lr") == 0 | ij == [] then
-                    k = 1;
-                else
-                    k = ij(:,1);
-                    k = k';
-                end
+    s = prod(mn)
+
+    // ------------------------
+    // "g" general sorting mode
+    // ------------------------
+    if sortype=="g" then
+        v($+1) = 0        // To get the position of all sorted implicit zeros
+        ij($+1,:) = [mn(1)+1 1]  // (the value does not matter)
+
+        // Sorting non zero values:
+        if lhs == 1 then
+            if ~isdef("criteria", "l")
+                v = gsort(v, "g", sortdir)
+            else
+                v = gsort(v, "g", sortdir, criteria)
             end
         else
-            dif = mn(2) - length(v);
-            if lhs == 1 then
-                v = gsort(v', optsort, directionsort);
+            if ~isdef("criteria", "l")
+                [v, ks] = gsort(v, "g", sortdir)
             else
-                [v, k] = gsort(v', optsort, directionsort);
-                k=ij(k,2)';
+                [v, ks] = gsort(v, "g", sortdir, criteria)
             end
+        end
 
-            //Obtain the indices corresponding to positive values of v
-            // and negative value of v
-            // If A is complex, the elements are sorted by magnitude
-            if isreal(A) then
-                last = find(v<0);
-                first = find(v>0);
-            else
-                s = abs(v);
-                last = find(s<0);
-                first = find(s>0);
-            end
+        kz = find(v==0)  // Here is the position of zeros
+        v(kz) = []       // Cleaning
+        K = [ 1:kz-1  s-length(v)+kz:s]  // We build K
+        Ain = A
+        A = sparse(ind2sub(mn,K), v, mn) // We build the sorted sparse
+        // Building the dense matrix of initial indices of sorted elements
+        // A new "sparse_k" option could be implemented later to return a sparse k
+        if lhs==2
+            ks(kz) = []
+            k = zeros(A);
+            k(K) = sub2ind(mn, ij(ks,:));
+            k(k==0) = find(Ain(:)==0)
+            k = matrix(k, size(A))
+        end
+        return
+    end
 
-            // Sort the indices
-            if last == [] & first <> [] then
-                if strcmp(directionsort, "i")== 0 then
-                    ij(:,2) = first(:) + dif;
-                else
-                    ij(:,2) = first(:);
-                end
-            elseif first == [] & last <> [] then
-                if strcmp(directionsort, "i")== 0 then
-                    ij(:,1) = last(:);
+    // -------------------------------------
+    // Sorting inside rows or inside columns
+    // -------------------------------------
+    if or(sortype==["r" "c"]) then   // "r" sorts rows of each column
+        a = 2;                       // "c" sorts columns of each row
+        uc = unique(ij(:,a))
+        V = []
+        K = []
+        Kin = (1:mn(1))'*ones(1,mn(2))
+        for n = uc'
+            vec = A(:, n)
+            if lhs==1
+                if ~isdef("criteria", "l")
+                    v = gsort(vec, "g", sortdir)
                 else
-                    ij(:,1) = last(:) + dif;
+                    v = gsort(vec, "g", sortdir, criteria)
                 end
             else
-                if strcmp(directionsort, "i")== 0 then
-                    ij(:,2) = [last(:); first(:) + dif];
+                if ~isdef("criteria", "l")
+                    [v, k] = gsort(vec, "g", sortdir)
                 else
-                    ij(:,2) = [first(:); last(:) + dif];
+                    [v, k] = gsort(vec, "g", sortdir, criteria)
                 end
             end
-            A = sparse(ij,v,mn);
+            [tmp, v] = spget(v);
+            tmp(:, a) = n
+            K = [K ; tmp]
+            V = [V ; v]
+            if lhs>1
+                Kin(:,n) = k(:)
+            end
+        end
+        A = sparse(K, V, mn);
+        if lhs>1
+            k = matrix(Kin, mn);
         end
+        if sortype=="c"
+            A = A.'
+            k = k.'
+        end
+        return
     end
 
-    if mn(2) == 1 then
-        // if A is a column vector and optsort = 'c', the result is the
-        // first input argument
-        if strcmp(optsort, "c") == 0 | strcmp(optsort, "lc") == 0 | v == [] then
-            A = A;
-            if lhs == 2 then
-                if strcmp(optsort, "lc") == 0 | ij == [] then
-                    k = 1;
-                else
-                    k = ij(:,2);
-                    k = k;
-                end
-            end
-        else
-
-            dif = mn(1) - length(v);
-            if lhs == 1 then
-                v = gsort(v, optsort, directionsort);
-            else
-                [v, k] = gsort(v, optsort, directionsort);
-                k=ij(k,1);
-            end
-
-            //Obtain the indices corresponding to positive values of v
-            // and negative value of v
-            // If A is complex, the elements are sorted by magnitude
-            if isreal(A) then
-                last = find(v<0);
-                first = find(v>0);
-            else
-                s = abs(v);
-                last = find(s<0);
-                first = find(s>0);
-            end
+    // ---------------------
+    // Lexicographic sorting
+    // ---------------------
+    msg = _("%s: Argument #%d: Complex sparse not yet supported in ""%s"" mode.\n")
 
-            // sort the indices in terms of directionsort = 'i' or 'd'
-            // if directionsort='i' and v>0, the elements are sorted in the
-            // increasing order, ie [0,..,v] and, conversely, in the decreasing
-            // order the elements are sorted : [v,..,0]
-            // if v<0, the elements are sorted in the increasing order,
-            // ie [v,..,0] and, conversely, in the decreasing order the
-            // elements are sorted : [0,..,v]
-            // And else, if v contains positive and neqative values, the
-            // elements are sorted in the increasing order,ie [v_neg,0,v_pos],
-            // and conversely for the decreasing order.
-            if last == [] & first <> [] then
-                if strcmp(directionsort, "i") == 0 then
-                    ij(:,1) = first(:) + dif;
-                else
-                    ij(:,1) = first(:);
-                end
-            elseif first == [] & last <> [] then
-                if strcmp(directionsort, "i") == 0 then
-                    ij(:,1) = last(:);
+    // Vector = special simple case
+    // ----------------------------
+    if isvector(A) then
+        isRow = isrow(A)
+        if (isRow & sortype=="lr") | (iscolumn(A) & sortype=="lc")
+            k = 1
+        else
+            if lhs==1
+                if ~isdef("criteria", "l")
+                    A = gsort(A(:), "g", sortdir)
                 else
-                    ij(:,1) = last(:) + dif;
+                    A = gsort(A(:), "g", sortdir, criteria)
                 end
             else
-                if strcmp(directionsort, "i") == 0 then
-                    ij(:,1) = [last(:); first(:) + dif];
+                if ~isdef("criteria", "l")
+                    [A, k] = gsort(A(:), "g", sortdir)
                 else
-                    ij(:,1) = [first(:); last(:) + dif];
+                    [A, k] = gsort(A(:), "g", sortdir, criteria)
                 end
             end
-            A = sparse(ij, v, mn);
+            if isRow
+                A = matrix(A, 1, -1)
+                k = matrix(k, 1, -1)
+            end
+        end
+        return
+    end
+
+    // "lr" case
+    // ---------
+    if sortype=="lc" then
+        A = A.'
+    end
+    if ~isdef("criteria", "l")
+        [A, k] = %sp_gsort_lr(A, sortdir);
+    else
+        [A, k] = %sp_gsort_lr(A, sortdir, criteria);
+    end
+    if sortype == "lc" then
+        A = A.'
+        k = matrix(k, 1, -1)
+    end
+endfunction
+
+// ===================================================================
+
+function [S, K] = %sp_gsort_lr(S, order, criteria)
+    [nr,nc] = size(S)
+    K = (1:nr)'
+    crit = isdef("criteria","l")
+
+    // List of column according to which sorting must be done
+    J = 1:nc
+        // We ignore columns that are uniform. Sorting them is useless
+    Std = sum(S.^2,"r")/nr - (sum(S,"r")/nr).^2
+    J(Std==0) = []
+
+    // Processing (bulky. A more clever algo required (but hard))
+    for j = J($:-1:1)
+        if crit
+            [?, k] = gsort(S(K, j), "g", order, criteria)
+        else
+            [?, k] = gsort(S(K, j), "g", order)
         end
+        K = K(k,1)
     end
+    S = S(K,:)
 endfunction
diff --git a/scilab/modules/elementary_functions/macros/%spb_gsort.sci b/scilab/modules/elementary_functions/macros/%spb_gsort.sci
new file mode 100644 (file)
index 0000000..685487d
--- /dev/null
@@ -0,0 +1,20 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+//
+// 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.
+
+function [A, k] = %spb_gsort(A, varargin)
+    lhs = argn(1)
+    if lhs > 1 then
+        [A, k] = gsort(A*1, varargin(:))
+    else
+        A = gsort(A*1, varargin(:))
+    end
+    A = (A==1)
+endfunction
diff --git a/scilab/modules/elementary_functions/tests/nonreg_tests/bug_15842.tst b/scilab/modules/elementary_functions/tests/nonreg_tests/bug_15842.tst
new file mode 100644 (file)
index 0000000..533ba93
--- /dev/null
@@ -0,0 +1,32 @@
+// =============================================================================
+// 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 15842 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/15842
+//
+// <-- Short Description -->
+// unique() yielded an error for 2D sparse matrices
+
+s = int(sprand(10,20,0.05)*10);
+assert_checkequal(unique(s), sparse(unique(full(s))));
+
+r = unique(s, "keepOrder");
+ref = sparse(unique(full(s), "keepOrder"));
+assert_checkequal(r, ref);
+
+r = unique(s, "uniqueNan");
+ref = sparse(unique(full(s), "uniqueNan"));
+assert_checkequal(r, ref);
+
+r = unique(s, "keepOrder", "uniqueNan");
+ref = sparse(unique(full(s), "keepOrder", "uniqueNan"));
+assert_checkequal(r, ref);
diff --git a/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16452.tst b/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16452.tst
new file mode 100644 (file)
index 0000000..25e2844
--- /dev/null
@@ -0,0 +1,20 @@
+// =============================================================================
+// 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 16452 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/16452
+//
+// <-- Short Description -->
+// setdiff(sparse([1 3 0 2]), sparse([3 7])) missed 0 and listed 3
+
+r = setdiff(sparse([1 3 0 2]), sparse([3 7]));
+assert_checkequal(r, sparse([0 1 2]));
diff --git a/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16454.tst b/scilab/modules/elementary_functions/tests/nonreg_tests/bug_16454.tst
new file mode 100644 (file)
index 0000000..df5e6ed
--- /dev/null
@@ -0,0 +1,26 @@
+// =============================================================================
+// 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 16454 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/16454
+//
+// <-- Short Description -->
+// Sorting a sparse vector including some NaN yielded an error
+
+s = sprand(20,30,0.5);
+s([30 100 150 437]) = %nan;
+objects = list(s(:)', s(:), s);
+for o = objects
+    for m = ["g" "r" "c" "lr" "lc"]
+        assert_checktrue(execstr("gsort(o,m,""i"")", "errcatch")==0);
+    end
+end
index d018c73..49be521 100644 (file)
@@ -10,7 +10,9 @@
 // For more information, see the COPYING file which you should have received
 // along with this program.
 // =============================================================================
-
+//
+// NOTE: gsort() is tested for sparse booleans in gsort_sparse.tst
+//
 // <-- CLI SHELL MODE -->
 // <-- NO CHECK REF -->
 
index bd51b1b..0d3e8c4 100644 (file)
-// =============================================================================
+// ===================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) ????-2008 - INRIA
 // Copyright (C) ????-2008 - ENPC
 // Copyright (C) 2008 - DIGITEO - Allan CORNET
 // Copyright (C) 2012 - Scilab Enterprises - Adeline CARNIS
-// Copyright (C) 2018 - Samuel GOUGEON
+// Copyright (C) 2018 - 2020 - Samuel GOUGEON
 //
 //  This file is distributed under the same license as the Scilab package.
-// =============================================================================
-
+// ===================================================================
+//
+// Included gsort() tests:
+//  * sparse reals (all sizes)
+//  * sparse complex (all sizes), including multi-level sorting
+//  * sparse boolean
+//
 // <-- CLI SHELL MODE -->
 // <-- NO CHECK REF -->
 
-//================================ sparse vectors ==============================
-
-sp = sparse([1,2,4,5,3,10]);
-ref = sparse([10,5,4,3,2,1]);
-A = gsort(sp);
-assert_checkequal(ref, A);
-
-sp = sparse([1,2;4,5;3,10]);
-assert_checkfalse(execstr("A = gsort(sp)", "errcatch") == 0);
-refMsg = msprintf(_("%s: Wrong size for input argument #%d: sparse vectors expected.\n"), "gsort", 1);
-assert_checkerror("A = gsort(sp)", refMsg);
+// ========================= sparse reals ============================
 
-//=============== testing gsort with Sparse (macro: %sp_gsort) =================
+b = [5 1 3 2 4 ; 6 1 2 4 1];
+c = full(sprand(10,8,0.1));
+objects = list(b(:)', b(:), b, c(:)', c(:), c);
+for method = ["g" "lr" "lc" "r" "c" ] //  
+    mprintf("\n%s : ", method);
+    for o = objects
+        O = sparse(o);
+        for order = ["i" "d"]
+            mprintf("%s ",order)
+            [s,k] = gsort(o, method, order);
+            [S,K] = gsort(O, method, order);
+            assert_checktrue(issparse(S));
+            assert_checkequal(full(S), s);
+            assert_checkequal(K, k);
+        end
+    end
+end
 
-// with real sparses :
-b = [5 1 3 2 4;6 1 2 4 1]; b = b(:);
-B = sparse(b);
-for smode = ["g" "r" "c" "lr" "lc"]
-    for sdir = ["d" "i"]
-        [s, k] = gsort(b, smode, sdir);
-        [s1, k1] = gsort(B, smode, sdir);
-        assert_checkequal(full(s1),s);
-        assert_checkequal(k1,k);
-        [s, k] = gsort(b', smode, sdir);
-        [s1, k1] = gsort(B', smode, sdir);
-        assert_checkequal(full(s1),s);
-        assert_checkequal(k1,k);
+// Uniform row, column or matrix of zeros or of ones
+objects = list(spzeros(1,10), spzeros(10,1), spzeros(6,8))
+for a = [0 1]
+    for o = objects
+        sz = size(o);
+        z = o + a;
+        [s, k]= gsort(z, "g");
+        assert_checkequal(s, z);
+        assert_checkequal(k, matrix(1:prod(sz),sz(1),-1));
+        [s, k]= gsort(z, "r");
+        assert_checkequal(k, (1:sz(1))'*ones(1,sz(2)));
+        [s, k]= gsort(z, "c");
+        assert_checkequal(k, ones(sz(1),1)*(1:sz(2)));
+        [s, k]= gsort(z, "lr");
+        assert_checkequal(k, (1:sz(1))');
+        [s, k]= gsort(z, "lc");
+        assert_checkequal(k, 1:sz(2));
     end
 end
 
-// with complex sparses :
-A = [1 -%i; %i 0]; A = A(:);
+// ========================== sparse complex =========================
+
+// Sparse column of complex numbers (< 2018)
+// -----------------------------------------
+A = [1 -%i;%i 0];
 A1 = sparse(A);
-B = [1 1+%i 4; -2*%i 3 3-%i]; B = B(:);
+B = [1 1+%i 4; -2*%i 3 3-%i];
 B1 = sparse(B);
-C = [-%i 3*%i; 4 9; -2*%i 7]; C = C(:);
+C = [-%i 3*%i;4 9;-2*%i 7];
 C1 = sparse(C);
-for smode = ["g" "r" "c"]
-    for sdir = ["d" "i"]
-        c = gsort(A, smode, sdir);
-        d = full(gsort(A1, smode, sdir));
-        assert_checkequal(c,d);
-        c = gsort(B, smode, sdir);
-        d = full(gsort(B1, smode, sdir));
-        assert_checkequal(c,d);
-        [s, k] = gsort(C, smode, sdir);
-        [s1, k1] = gsort(C1, smode, sdir);
-        assert_checkequal(full(s1),s);
-        assert_checkequal(k1,k);
+mprintf("\nSparse real:\n");
+for order = ["i" "d"]
+    for method = ["g" "r" "c" "lr" "lc"]
+        c = gsort(A(:), method, order);
+        d = full(gsort(A1(:), method, order));
+        assert_checkequal(c, d);
+
+        c = gsort(B(:), method, order);
+        d = full(gsort(B1(:), method, order));
+        assert_checkequal(c, d);
+
+        [s,k] = gsort(C(:), method, order);
+        [s1,k1] = gsort(C1(:), method, order);
+        assert_checkequal(full(s1), s);
+        assert_checkequal(k1, k);
     end
 end
+
+// Sparse matrix of complex numbers
+// --------------------------------
+c0 = sprand(50,10,0.2) + imult(sprand(50,10,0.2));
+objects = list(c0(:).', c0(:), c0);
+Crit = list(list(abs, atan), list(real, imag));
+Orders = ["i" "i" ; "i" "d"];
+mprintf("\nSparse complex:\n");
+for method = ["g" "r" "c" "lr" "lc"]
+    mprintf("\n%s : ", method);
+    for O = objects
+        for j = 1:2
+            order = Orders(j,:);
+            crit = Crit(j);
+            mprintf("%s ", strcat(order));
+            S = gsort(O, method, order, crit);
+            s = gsort(full(O), method, order, crit);
+            assert_checktrue(issparse(S));
+            assert_checkequal(s, full(S));
+
+            [S, K] = gsort(O, method, order, crit);
+            [s, k] = gsort(full(O), method, order, crit);
+            assert_checktrue(issparse(S));
+            assert_checkequal(K, k);
+            assert_checkequal(s, full(S));
+        end
+    end
+end
+
+// ========================= sparse boolean =========================
+
+b = sprand(10,500,0.1) > 0;
+objects = list(b(:)', b(:), b);
+mprintf("\nSparse booleans:\n");
+for method = ["g" "r" "c" "lr" "lc"]
+    mprintf("\n%s : ", method);
+    for O = objects
+        for order = ["i" "d"]
+            mprintf("%s ", order);
+            [S, K] = gsort(O, method, order);
+            [s, k] = gsort(full(O), method, order);
+            assert_checktrue(issparse(S));
+            assert_checkequal(K, k);
+            assert_checkequal(full(S), s);
+
+            S = gsort(O, method, order);
+            assert_checktrue(issparse(S));
+            assert_checkequal(full(S), s);
+        end
+    end
+end
+