* Bugs 7948 15825 fixed: gsort() multilevel sorting 23/20723/16
Samuel GOUGEON [Mon, 29 Oct 2018 02:33:26 +0000 (03:33 +0100)]
  http://bugzilla.scilab.org/7948
  http://bugzilla.scilab.org/15825
  Page (PDF): http://bugzilla.scilab.org/attachment.cgi?id=5059

  The tests and examples presently call directly the overloads
  on purpose, to be independent of the gateway. They can and will be
  changed into regular gsort() calls.

  This is the first step.
  The next one, afterward and in a separate commit will be for sparses
  (see 15839 below).

  This commit is noticeably required to process the following bugs:
    - http://bugzilla.scilab.org/15839 (sorting sparse and complex sparse)
    - http://bugzilla.scilab.org/15838 (sparse complex vector: wrong k)
    - http://bugzilla.scilab.org/15280 (hypermat of complex along dim>2)
    - http://bugzilla.scilab.org/15734 (intersect() with complex numbers)
    - http://bugzilla.scilab.org/15737 (setdiff() with complex numbers)

Change-Id: I7cd88246026ce14fa730d14d5c07064d84cbf73f

16 files changed:
scilab/CHANGES.md
scilab/modules/elementary_functions/help/en_US/searchandsort/gsort.xml
scilab/modules/elementary_functions/help/fr_FR/searchandsort/gsort.xml [deleted file]
scilab/modules/elementary_functions/help/ja_JP/searchandsort/gsort.xml [deleted file]
scilab/modules/elementary_functions/help/pt_BR/searchandsort/gsort.xml [deleted file]
scilab/modules/elementary_functions/help/ru_RU/searchandsort/gsort.xml [deleted file]
scilab/modules/elementary_functions/macros/%gsort_multilevel.sci [new file with mode: 0644]
scilab/modules/elementary_functions/macros/%hm_gsort.sci
scilab/modules/elementary_functions/macros/%s_gsort.sci [new file with mode: 0644]
scilab/modules/elementary_functions/sci_gateway/cpp/sci_gsort.cpp
scilab/modules/elementary_functions/tests/unit_tests/gsort.tst
scilab/modules/elementary_functions/tests/unit_tests/gsort_complex.tst [deleted file]
scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_complex.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_numbers.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_polynomials.tst [new file with mode: 0644]
scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_text.tst [new file with mode: 0644]

index 5a502bb..25c57e9 100644 (file)
@@ -140,6 +140,7 @@ Feature changes and additions
 * `nicholschart` is improved: more neutral default frame color; improved labels positionning; colors can now be specified by their predefined name or "#RRGGBB" hexa code; a structure of handles is now returned to easily postprocess both subframes and the set of labels.
 * `sciargs()` returns a column instead of formerly a row.
 * Booleans and encoded integers can now be concatenated together, as in `[%f int8(-5)]`.
+* `gsort` can now perform multilevel sorting. This noticeably allows to sort completely complex numbers.
 
 Help pages:
 -----------
@@ -206,6 +207,7 @@ Bug Fixes
 * [#7657](http://bugzilla.scilab.org/show_bug.cgi?id=7657): `lstsize` was a duplicate of `size` and should be removed.
 * [#7724](http://bugzilla.scilab.org/show_bug.cgi?id=7724): When a figure is created in .auto_resize="on" mode, its .axes_size sets its .figure_size accordingly, not the reverse. But this was not documented.
 * [#7765](http://bugzilla.scilab.org/show_bug.cgi?id=7765): `champ1()` is useless. `champ().colored` is available for a long time.
+* [#7948](http://bugzilla.scilab.org/show_bug.cgi?id=7948): `gsort()` could not perform multilevel sorting.
 * [#7967](http://bugzilla.scilab.org/show_bug.cgi?id=7967): The tricky size `[ny,nx]` of `meshgrid(x,y)` results and usages with graphics was not enough documented.
 * [#8307](http://bugzilla.scilab.org/show_bug.cgi?id=8307): `list2vec()` and `vec2list()` were located in the [optimization] module instead of in [data_structures], and were missing in the `See also` section of `list()`.
 * [#8418](http://bugzilla.scilab.org/show_bug.cgi?id=8418): `unique()` was not able to return the number of occurences of returned dictinct entities.
@@ -277,6 +279,7 @@ Bug Fixes
 * [#15745](http://bugzilla.scilab.org/show_bug.cgi?id=15745): `diophant(0,0,m)`, `diophant([p 0],q)`, `diophant([0 p],q)` with m<>0 and p>q were wrong. There was no flag for cases with an infinite number of solutions. When there is no solution, some values were returned anyway, instead of []. In this case, the documented definition of the err value was dubious. Decimal numbers and integers were accepted, but not encoded integers. Inf and NaN input coefficients were not rejected.
 * [#15812](http://bugzilla.scilab.org/show_bug.cgi?id=15812): On assigning variables the source variable may become become corrupted
 * [#15821](http://bugzilla.scilab.org/show_bug.cgi?id=15821): `fac3d()` and fac3d1()` were still in Scilab 6.0 despite they were tagged obsolete 14 years ago in Scilab 4.1
+* [#15825](http://bugzilla.scilab.org/show_bug.cgi?id=15825): `gsort()` could not sort completely dense matrices of complex numbers.
 * [#15840](http://bugzilla.scilab.org/show_bug.cgi?id=15840): `grand(1,"prm",m)` yielded an unsqueezed size([size(m) 1]) hypermatrix
 * [#15934](http://bugzilla.scilab.org/show_bug.cgi?id=15934): The `^ hat` page wrongly indicated that `^` applied to a rectangular matrix not being a vector is done element-wise.
 * [#15948](http://bugzilla.scilab.org/show_bug.cgi?id=15948): `xlabel`, `ylabel`, `zlabel` and `title` needed to be upgraded.
index 622064b..6f1352d 100644 (file)
@@ -2,8 +2,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.
  * 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="en">
+<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="en">
     <refnamediv>
         <refname>gsort</refname>
         <refpurpose>sorting by quick sort algorithm</refpurpose>
     </refnamediv>
     <refsynopsisdiv>
         <title>Syntax</title>
-        <synopsis>[B [,k]]=gsort(A)
-            [B [,k]]=gsort(A,option)
-            [B [,k]]=gsort(A,option,direction)
+        <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>
             <varlistentry>
                 <term>A</term>
                 <listitem>
-                    <para>
-                        scalar, vector, matrix or hypermatrix of booleans, integers, real numbers,
-                        or text, or a sparse vector of reals.
-                    </para>
+                    Scalar, vector, matrix or hypermatrix of booleans, integers, real or complex
+                    numbers, or text, or a sparse vector of real numbers.
+                    <note>
+                        Overloading for unhandled types is allowed.
+                    </note>
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>option</term>
+                <term>method</term>
                 <listitem>
-                    <para>a character string. It gives the type of sort to
-                        perform:
-                    </para>
+                    A keyword: The sorting method:
+                    <informaltable>
+                        <tr valign="top">
+                            <th>'g'</th><td>:</td>
+                            <td>General sorting: All elements of <literal>A</literal> are sorted
+                                (default method).
+                            </td>
+                        </tr>
+                        <tr valign="top">
+                            <th>'r'</th><td>:</td>
+                            <td>Rows of each column of <literal>A</literal> are sorted.</td>
+                        </tr>
+                        <tr valign="top">
+                            <th>'c'</th><td>:</td>
+                            <td>Columns of each row of <literal>A</literal> are sorted.</td>
+                        </tr>
+                        <tr valign="top"><th>'lr'</th><td>:</td>
+                            <td>lexicographic sort of the rows of <literal>A</literal>:
+                                Sorts rows according to values in the first column. If a group of
+                                sorted rows have the same value in column #1, resorts the group
+                                according to values in column #2. etc.
+                                Not applicable to hypermatrices.
+                            </td>
+                        </tr>
+                        <tr valign="top"><th>'lc'</th><td>:</td>
+                            <td>lexicographic sort of the columns of <literal>A</literal>
+                                (not for hypermatrices).
+                            </td>
+                        </tr>
+                    </informaltable>
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>direction</term>
+                <listitem>
+                    "d" for <emphasis role="bold">d</emphasis>ecreasing order (default), or
+                    "i" for <emphasis role="bold">i</emphasis>ncreasing one.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>directions</term>
+                <listitem>
+                    vector of "i" and "d" characters, with as many elements than
+                    <varname>rankFuncs</varname> has.
+                    <literal>directions(k)</literal> is used for <varname>rankFuncs(k)</varname>.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>rankFuncs</term>
+                <listitem>
+                    list() whose elements are among the following type:
                     <itemizedlist>
                         <listitem>
-                            <para>
-                                'r' : each column of <literal>A</literal> is sorted
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>
-                                'c': each row of <literal>A</literal> is sorted
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>
-                                'g': all elements of <literal>A</literal> are sorted. It
-                                is the default value.
-                            </para>
+                            identifier <literal>fun</literal> of a function in Scilab language
+                            or of a builtin function.
                         </listitem>
                         <listitem>
-                            <para>'lr': lexicographic sort of the rows of
-                                <literal>A</literal>
-                            </para>
+                            : colon. It stands for a <literal>fun</literal> such that
+                            <literal>fun(A)</literal> returns <literal>A</literal>.
                         </listitem>
                         <listitem>
-                            <para>'lc': lexicographic sort of the columns of
-                                <literal>A</literal>
-                            </para>
+                            a <literal>list(fun, param1, param2,..)</literal> where
+                            <itemizedlist>
+                                <listitem>
+                                    <literal>fun</literal> is the identifier of a Scilab or
+                                    builtin function.
+                                </listitem>
+                                <listitem>
+                                    <literal>param1, param2,..</literal> are parameters.
+                                </listitem>
+                            </itemizedlist>
+                            such that <literal>fun(A, param1, param2, ..)</literal> will be called.
                         </listitem>
                     </itemizedlist>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>direction</term>
-                <listitem>
-                    <para>a character string. It gives the ordering direction:
-                        <literal>'i'</literal> stand for increasing and
-                        <literal>'d'</literal> for decreasing order (default).
+                    <para>
+                        The functions <literal>fun</literal> must fullfill the following conditions:
+                        <itemizedlist>
+                            <listitem>
+                                <literal>R=fun(A)</literal> or <literal>R=fun(A, param1, param2,..)</literal>
+                                must be supported.
+                            </listitem>
+                            <listitem>
+                                <literal>fun</literal> must work in an element-wise way, meaning:
+                                <literal>size(R)==size(A)</literal>, and <literal>R(k)</literal>
+                                is about only <literal>A(k)</literal>
+                            </listitem>
+                            <listitem>
+                                <literal>R</literal> must be of simple sortable type: boolean,
+                                integer, real, text.
+                            </listitem>
+                        </itemizedlist>
+                    </para>
+                    <para>
+                        <note>
+                            When <literal>A</literal> are complex numbers, the usual functions
+                            <literal>real, imag, abs, atan</literal> can be specified. Then,
+                            <literal>atan(imag(A),real(A))</literal> will be called instead of
+                            <literal>atan(A)</literal>.
+                        </note>
                     </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>B</term>
                 <listitem>
-                    <para>an array with same type and dimensions as
-                        <literal>A</literal>.
-                    </para>
+                    The sorted array, with  <literal>A</literal>'s data type, encoding, and sizes.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>k</term>
                 <listitem>
-                    <para>a real array with integer values and same dimensions as
-                        <literal>A</literal>. Contains the origin indices.
-                    </para>
+                    Array of decimal integers, of size <literal>size(A)</literal>:
+                    Initial indices of <literal>B</literal> elements, in <literal>A</literal>.
+                    If <literal>A</literal> is a matrix, according to the chosen method,
+                    <table>
+                    <tr>
+                        <th valign="top">"g"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> is a matrix of size(A): <literal>k(i)</literal>
+                            is the linear index
+                            of <literal>B(i)</literal> in <literal>A</literal>, such that
+                            <literal>B(:) = A(k)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"r"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> is a matrix of size(A): <literal>k(i,j)</literal>
+                            is the <literal>1 ≤ index ≤ size(A,1)</literal>
+                            of <literal>B(i,j)</literal> in the column <literal>A(:,j)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"c"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> is a matrix of size(A): <literal>k(i,j)</literal>
+                            is the <literal>1 ≤ index ≤ size(A,2)</literal>
+                            of <literal>B(i,j)</literal> in the row <literal>A(i,:)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"lr"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> is a column of size(A,1), such that
+                            <literal>B = A(k,:)</literal>.
+                        </td>
+                    </tr>
+                    <tr>
+                        <th valign="top">"lc"</th><td>:</td>
+                        <td>
+                            <literal>k</literal> is a row of size(A,2), such that
+                            <literal>B = A(:,k)</literal>.
+                        </td>
+                    </tr>
+                    </table>
+                    <para/>
                 </listitem>
             </varlistentry>
         </variablelist>
     <refsection>
         <title>Description</title>
         <para>
-            <literal>gsort</literal> implements a "quick sort" algorithm for
-            various data types.
+            <literal>gsort</literal> performs a "quick sort" for various native data types.
+            By default, sorting is performed in decreasing order.
         </para>
-        <itemizedlist>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'g')</literal>,
-                    <literal>B=gsort(A,'g','d')</literal> and
-                    <literal>B=gsort(A)</literal> sort the elements of the array
-                    <literal>A</literal>, seen as <literal>A(:)</literal> in a decreasing
-                    order.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'g','i')</literal> sort the elements of the
-                    array <literal>A</literal> in the increasing order.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lr')</literal> sorts the rows of
-                    <literal>A</literal> in lexical decreasing order. <literal>B</literal>
-                    is obtained by a permutation of the rows of matrix
-                    <literal>A</literal> in such a way that the rows of
-                    <literal>B</literal> verify <literal>B(i,:)&gt;=B(j,:)</literal> if
-                    <literal>i&lt;j</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lr','i')</literal> works similarly for
-                    increasing lexical order.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lc')</literal> sorts the columns of
-                    <literal>A</literal> in lexical decreasing order. <literal>B</literal>
-                    is obtained by a permutation of the columns of matrix
-                    <literal>A</literal> in such a way that the columns of
-                    <literal>B</literal> verify <literal>B(:,i)&gt;=B(:,j)</literal> if
-                    <literal>i&lt;j</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lc','i')</literal> works similarly for
-                    increasing lexical order.
-                </para>
-            </listitem>
-        </itemizedlist>
         <para>
-            If required the second return argument <literal>k</literal> contains
-            the indices of the sorted values in <literal>A</literal>. If
-            <literal>[B,k]=gsort(A,'g')</literal> one has <literal>B==A(k)</literal>.
-            <emphasis role="bold">The algorithm preserve the relative order of
-                records with equal values.
-            </emphasis>
+            <literal>%nan</literal> values are considered greater than <literal>%inf</literal>.
         </para>
         <para>
-            When <literal>v</literal> is complex, the elements are sorted by
-            magnitude, i.e., abs(<literal>v</literal>) .
+            Complex numbers are by default sorted only according to their moduli.
+            Complete sorting can be achieved using the multilevel mode, through the
+            <varname>rankFuncs</varname> and <varname>directions</varname> arguments.
+            Example:
         </para>
         <para>
-            With complex numbers, <literal>gsort</literal> can be overloaded
-        </para>
-        <para>Create macro:
-            SCI/modules/elementary_functions/macros/%_gsort.sci
+            <literal>M = gsort(C, "g", ["i" "d"], list(real, imag))</literal><para/>
+            will sort the array C, first by increasing real parts, and for elements
+            of equal real parts, second by decreasing imaginary parts.
+            The multilevel mode is described with details in a dedicated subsection below.
         </para>
-        <para>Overloading for not managed type (others than a real, an integer or a character
-            string vector/matrix or a sparse vector.) is allowed.
+        <para>
+            Texts are sorted in alphabetical order, in a case-sensitive way.
+            Extended UTF characters are supported.
         </para>
         <para>
-            if <literal>v</literal> have <literal>%nan</literal> or
-            <literal>%inf</literal> as elements. gsort places these at the beginning
-            with <literal>'d'</literal> or at the end with <literal>'i'</literal>
-            argument.
+            <note>
+                Whatever is the chosen method, <emphasis role="bold">the algorithm preserves the
+                relative order of elements with equal values.
+            </emphasis>
+            </note>
         </para>
+        <refsect3>
+            <title>Sorting methods</title>
+            <para>
+                <emphasis role="bold">B = gsort(A,'g', ..)</emphasis> sorts all elements of
+                <varname>A</varname>, and stores sorted elements in the first column from top to
+                bottom, then in the second column, etc.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'c', ..)</emphasis> sorts each row of A.
+                Each sorted element is on the same row as in A, but possibly on another column
+                corresponding to its sorting rank on the row.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'r', ..)</emphasis> sorts each column of A.
+                Each sorted element is on the same column as in A, but possibly on another row
+                corresponding to its sorting rank.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'lr', ..)</emphasis> sorts rows of A, as a whole,
+                in a lexical way. Two rows are compared and sorted in the following way:
+                The elements of their first column are compared. If their ranks are not equal,
+                both rows are sorted accordingly. Otherwise, the elements of their second column
+                are compared. etc... up to the last column if it is required.
+            </para>
+            <para>
+                <emphasis role="bold">B = gsort(A,'lc', ..)</emphasis> sorts columns of A,
+                as a whole, in a lexical way (see above).
+            </para>
+        </refsect3>
+        <refsect3>
+            <title>Multilevel sorting</title>
+            <para>
+                As noted above, when two compared elements have equal ranks, their initial relative
+                order in <literal>A</literal> is preserved in the result <literal>B</literal> .
+            </para>
+            <para>
+                However, in many cases, going beyond through a multi-level sorting can be useful
+                and required:
+                After the first sort performed according to a first criterion and sorting
+                direction, it is possible to define a second criterion and sorting
+                direction and apply them to 1st-rank-equal elements gathered by the first sort.
+            </para>
+            <para>
+                If after the two first sorting some elements have still the same ranks, it is
+                possible to define and use a 3rd sorting level, etc.
+            </para>
+            <para>
+                <emphasis role="bold">Applied examples</emphasis> (see also the Examples section):
+                <orderedlist>
+                    <listitem>
+                        <emphasis>Sorting a matrix C of complex numbers,
+                        first: by increasing modulus, second: by increasing phase</emphasis>:
+                        <para/>
+                        <literal>gsort(C, "g", ["i" "i"], list(abs, atan))</literal>
+                        <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Sorting the columns of a matrix T of texts,
+                        first: by increasing length, second: in anti-alphabetical order</emphasis>:
+                        <para/>
+                        <literal>gsort(T, "c", ["i" "d"], list(length, :))</literal>
+                        <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Sorting a matrix P of polynomials,
+                        first: by increasing degree, second: by decreasing value of the constant
+                        0-degree coefficient</emphasis>:
+                        <screen>
+function c = get_coef(p, i)
+    // i: degree of the coeff to return
+    c = matrix(coeff(p(:))(:,i+1), size(p))
+endfunction
+
+gsort(P, "c", ["i" "d"], list(degree, list(get_coef,0)))
+</screen>
+                        In this example, the second ranking function allows to specify the degree i
+                        of the coefficient to be considered as secondary sorting value.
+                        <para/>
+                    </listitem>
+                    <listitem>
+                        <emphasis>Sorting a matrix D of decimal numbers,
+                        first: by increasing integer parts, second: by decreasing fractional parts</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>Examples</title>
-        <programlisting role="example">
-            alr=[1,2,2;
-            1,2,1;
-            1,1,2;
-            1,1,1];
-            [alr1,k]=gsort(alr,'lr','i')
-            [alr1,k]=gsort(alr,'lc','i')
-
-            v=int32(alr)
-
-            gsort(v)
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-
-            v=['Scilab' '2.6'
-            'Scilab' '2.7'
-            'xcos' '2.7'
-            'Scilab' '3.1'
-            'xcos' '3.1'
-            'xcos' '4.0'
-            'Scilab' '4.0']
-
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-        </programlisting>
+        <para>
+            Sorting elements in rows:
+        </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>
+            Lexicographic sorting of rows:
+        </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>
+            Lexicographic sorting of columns:
+        </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
+]]>     </programlisting>
+            <screen><![CDATA[
+--> [s, k] = gsort(m, "lc", "i")
+ 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.
+
+ k  =
+   1.   7.   3.   2.   8.   5.   6.   4.
+]]></screen>
+    <refsect3>
+        <title>Multilevel sorting</title>
+        <para>
+            <emphasis role="bold">With some decimal numbers</emphasis>:
+            Sorting first: by increasing integer parts,
+            second: by decreasing fractional parts.
+        </para>
+        <programlisting role="example"><![CDATA[
+// Function getting the fractional parts
+function r = get_frac(d)
+    r = d - int(d)
+endfunction
+
+// Unsorted data
+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
+  ];
+// Sorting
+[r, k] = %gsort_multilevel(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">With complex numbers</emphasis>:
+            Sorting, first: by increasing real parts, second: by increasing imaginary parts.
+        </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_multilevel(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">With some texts:</emphasis>
+            Sorting rows in columns, first by increasing lengths, second by alphabetical order
+        </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_multilevel(t, "r", ["i" "i"], list(length, :))
+]]>     </programlisting>
+        <screen><![CDATA[
+--> [r, k] = %gsort_multilevel(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>
+<!--  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/>
+        <para>
+            <emphasis role="bold">With some polynomials:</emphasis>
+            Sorting first: by decreasing values of x^0, second: by increasing degrees.
+        </para>
+        <programlisting role="example"><![CDATA[
+function c = get_coef(p, d)
+    // d : degree of the coeffs to return
+    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_multilevel(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_multilevel(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>
+    </refsect3>
     </refsection>
     <refsection role="see also">
         <title>See also</title>
         <simplelist type="inline">
             <member>
+                <link linkend="comparison">comparison</link>
+            </member>
+            <member>
+                <link linkend="strcmp">strcmp</link>
+            </member>
+            <member>
                 <link linkend="find">find</link>
             </member>
             <member>
         <revhistory>
             <revision>
                 <revnumber>5.4.0</revnumber>
-                <revremark>This function allows overloading for unmanaged type (others than a real, an integer or a character string vector/matrix or a sparse vector).</revremark>
+                <revremark>
+                    gsort() can now be overloaded for unmanaged types.
+                </revremark>
             </revision>
             <revision>
                 <revnumber>6.1.0</revnumber>
                 <revremark>
-                    Booleans can now be sorted.
+                    <itemizedlist>
+                        <listitem>
+                            Booleans can now be sorted.
+                        </listitem>
+                        <listitem>
+                            Multilevel sorting added with the rankFuncs option.
+                        </listitem>
+                    </itemizedlist>
                 </revremark>
             </revision>
         </revhistory>
diff --git a/scilab/modules/elementary_functions/help/fr_FR/searchandsort/gsort.xml b/scilab/modules/elementary_functions/help/fr_FR/searchandsort/gsort.xml
deleted file mode 100644 (file)
index 0b5762d..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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="fr">
-    <refnamediv>
-        <refname>gsort</refname>
-        <refpurpose>tri par l'algorithme "quick sort"</refpurpose>
-    </refnamediv>
-    <refsynopsisdiv>
-        <title>Séquence d'appel</title>
-        <synopsis>[B [,k]]=gsort(A )
-            [B [,k]]=gsort(A,option)
-            [B [,k]]=gsort(A,option,direction)
-        </synopsis>
-    </refsynopsisdiv>
-    <refsection>
-        <title>Paramètres</title>
-        <variablelist>
-            <varlistentry>
-                <term>A</term>
-                <listitem>
-                    <para>vecteur ou matrice de nombres réels, entiers ou de chaînes de
-                        caractères ou vecteur creux.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>option</term>
-                <listitem>
-                    <para>une chaîne de caractères, définissant le type de tri à
-                        réaliser:
-                    </para>
-                    <itemizedlist>
-                        <listitem>
-                            <para>'r' : trie chaque colonne de la matrice
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'c': trie chaque ligne de la matrice
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'g': trie tous les éléments de A(:). C'est la valeur par
-                                défaut.
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'lr': tri lexicographique des lignes de
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'lc': tri lexicographique des colonnes de
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                    </itemizedlist>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>direction</term>
-                <listitem>
-                    <para>Une chaîne de caractères définissant si le tri doit se faire
-                        dans l'ordre croissant <literal>('i')</literal> ou décroissant
-                        <literal>('d')</literal>. La valeur par défaut est
-                        <literal>('d')</literal>.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>B</term>
-                <listitem>
-                    <para>vecteur ou matrice de même type et même dimensions que
-                        <literal>A</literal>.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>k</term>
-                <listitem>
-                    <para>vecteur ou matrice de nombres entiers de même taille que
-                        <literal>A</literal> contenant les index d'origine.
-                    </para>
-                </listitem>
-            </varlistentry>
-        </variablelist>
-    </refsection>
-    <refsection>
-        <title>Description</title>
-        <para>
-            <literal>gsort</literal> est basé sur l'algorithme de tri rapide
-            "quick sort" modifié pour maintenir l'ordre relatif des éléments ayant des
-            valeurs égales lorsque l'index de tri est demandé.
-        </para>
-        <itemizedlist>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'g')</literal> et
-                    <literal>B=gsort(A,'g','d')</literal> produisent le même résultat que
-                    <literal>B=gsort(A)</literal>. Ces instructions produisent un tri de
-                    la matrice <literal>A</literal>, vue comme le vecteur
-                    <literal>A(:)</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'g','i')</literal> fonctionne de la même
-                    manière pour l'ordre croissant.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lr')</literal> trie les lignes de la matrice
-                    <literal>A</literal> dans l'ordre lexical décroissant.
-                    <literal>B</literal> est obtenue par une permutation des lignes de la
-                    matrice <literal>A</literal> de telle manière que les lignes de
-                    <literal>B</literal> vérifient <literal>B(i,:)&gt;=B(j,:)</literal> si
-                    <literal>i&lt;j</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lr','i')</literal> fonctionne de la même
-                    manière pour l'ordre lexical croissant.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lc')</literal> trie les colonnes de la
-                    matrice <literal>A</literal> dans l'ordre lexical décroissant.
-                    <literal>B</literal> est obtenue par une permutation des colonnes de
-                    la matrice <literal>A</literal> de telle manière que les colonnes de
-                    <literal>B</literal> vérifient <literal>B(:,i)&gt;=B(:,j)</literal> si
-                    <literal>i&lt;j</literal>. <literal/>
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lc','i')</literal> fonctionne de la même
-                    manière pour l'ordre lexical croissant.
-                </para>
-            </listitem>
-        </itemizedlist>
-        <para>Si le second argument de retour k est demandé, il contient les
-            indices des valeurs triées dans le tableau d'origine. Si
-            <literal>[B,k]=gsort(A,'g')</literal> on a <literal>B==A(k)</literal>.
-            <emphasis role="bold">L'algorithme préserve l'ordre relatif des éléments
-                ayant des valeurs égales.
-            </emphasis>
-        </para>
-        <para>Les matrices ou vecteurs complexes sont triés par rapport au module
-            complexe. Seule l'option <literal>'g'</literal> est accessible avec des
-            nombres complexes.
-        </para>
-        <para>
-            Pour les nombres complexes, <literal>gsort</literal> peut être
-            surchargé.
-        </para>
-        <para>voir la macro:
-            SCI/modules/elementary_functions/macros/%_gsort.sci
-        </para>
-        <para>La surcharge pour les types autres que vecteur ou matrice de nombres réels,
-            entiers ou de chaînes de caractères ou vecteur creux est possible.
-        </para>
-        <para>
-            Si <literal>A</literal> contient des <literal>%nan</literal> ou des
-            <literal>%inf</literal> ceux ci seront placés en début avec l'argument
-            <literal>'d'</literal> ou à la fin avec l'argument
-            <literal>'i'</literal>.
-        </para>
-    </refsection>
-    <refsection>
-        <title>Exemples</title>
-        <programlisting role="example">
-            alr=[1,2,2;
-            1,2,1;
-            1,1,2;
-            1,1,1];
-            [alr1,k]=gsort(alr,'lr','i')
-            [alr1,k]=gsort(alr,'lc','i')
-
-            A=int32(alr)
-
-            gsort(A)
-            gsort(A,'lr','i')
-            gsort(A,'lc','i')
-
-            A=['Scilab' '2.6'
-            'Scilab' '2.7'
-            'xcos' '2.7'
-            'Scilab' '3.1'
-            'xcos' '3.1'
-            'xcos' '4.0'
-            'Scilab' '4.0']
-
-            gsort(A,'lr','i')
-            gsort(A,'lc','i')
-        </programlisting>
-    </refsection>
-    <refsection role="see also">
-        <title>Voir aussi</title>
-        <simplelist type="inline">
-            <member>
-                <link linkend="find">find</link>
-            </member>
-            <member>
-                <link linkend="overloading">overloading</link>
-            </member>
-        </simplelist>
-    </refsection>
-    <refsection>
-        <title>Bibliographie</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>Historique</title>
-        <revhistory>
-            <revision>
-                <revnumber>5.4.0</revnumber>
-                <revremark>Cette fonction peut être étendue aux types non gérés (autres que vecteur ou matrice de nombres réels, entiers ou de chaînes de caractères ou vecteur creux).</revremark>
-            </revision>
-        </revhistory>
-    </refsection>
-</refentry>
diff --git a/scilab/modules/elementary_functions/help/ja_JP/searchandsort/gsort.xml b/scilab/modules/elementary_functions/help/ja_JP/searchandsort/gsort.xml
deleted file mode 100644 (file)
index 826e3c7..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-<?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
- *
- * 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="ja">
-
-    <refnamediv>
-
-        <refname>gsort</refname>
-
-        <refpurpose>クイックソートアルゴリズムによるソート</refpurpose>
-
-    </refnamediv>
-
-    <refsynopsisdiv>
-
-        <title>呼び出し手順</title>
-
-        <synopsis>[B [,k]]=gsort(A)
-
-            [B [,k]]=gsort(A,option)
-
-            [B [,k]]=gsort(A,option,direction)
-
-        </synopsis>
-
-    </refsynopsisdiv>
-
-    <refsection>
-
-        <title>引数</title>
-
-        <variablelist>
-
-            <varlistentry>
-
-                <term>A</term>
-
-                <listitem>
-
-                    <para>実数,整数または文字列のベクトル/行列または疎ベクトル.</para>
-
-                </listitem>
-
-            </varlistentry>
-
-            <varlistentry>
-
-                <term>option</term>
-
-                <listitem>
-
-                    <para>文字列. ソートの種類(下記)を指定します:</para>
-
-                    <itemizedlist>
-
-                        <listitem>
-
-                            <para>
-
-                                'r' : <literal>A</literal> の各列がソートされます
-
-                            </para>
-
-                        </listitem>
-
-                        <listitem>
-
-                            <para>
-
-                                'c': <literal>A</literal> の各行がソートされます
-
-                            </para>
-
-                        </listitem>
-
-                        <listitem>
-
-                            <para>
-
-                                'g': <literal>A</literal> の全要素がソートされます.
-
-                                デフォルト値です.
-
-                            </para>
-
-                        </listitem>
-
-                        <listitem>
-
-                            <para>
-
-                                'lr': <literal>A</literal>の列の辞書式ソート
-
-                            </para>
-
-                        </listitem>
-
-                        <listitem>
-
-                            <para>
-
-                                'lc': <literal>A</literal>のの行の辞書式ソート
-
-                            </para>
-
-                        </listitem>
-
-                    </itemizedlist>
-
-                </listitem>
-
-            </varlistentry>
-
-            <varlistentry>
-
-                <term>direction</term>
-
-                <listitem>
-
-                    <para>文字列. ソートの方向を指定します:
-
-                        <literal>'i'</literal> は昇順,
-
-                        <literal>'d'</literal> は降順 (デフォルト)を意味します.
-
-                    </para>
-
-                </listitem>
-
-            </varlistentry>
-
-            <varlistentry>
-
-                <term>B</term>
-
-                <listitem>
-
-                    <para>
-
-                        <literal>A</literal>と同じ型と次元の配列.
-
-                    </para>
-
-                </listitem>
-
-            </varlistentry>
-
-            <varlistentry>
-
-                <term>k</term>
-
-                <listitem>
-
-                    <para>
-
-                        整数値を有し,<literal>A</literal>と同じ次元の実数配列.
-
-                        元の添え字を有します.
-
-                    </para>
-
-                </listitem>
-
-            </varlistentry>
-
-        </variablelist>
-
-    </refsection>
-
-    <refsection>
-
-        <title>説明</title>
-
-        <para>
-
-            <literal>gsort</literal> は種々のデータ型に関する
-
-            "クイックソート" アルゴリズムです.
-
-        </para>
-
-        <itemizedlist>
-
-            <listitem>
-
-                <para>
-
-                    <literal>B=gsort(A,'g')</literal>,
-
-                    <literal>B=gsort(A,'g','d')</literal> および
-
-                    <literal>B=gsort(A)</literal> は
-
-                    配列  <literal>A</literal>の要素を<literal>A(:)</literal>として
-
-                    降順にソートします.
-
-                </para>
-
-                <para>
-
-                    <literal>B=gsort(A,'g','i')</literal> は
-
-                    <literal>A</literal>の要素を昇順にソートします.
-
-                </para>
-
-            </listitem>
-
-            <listitem>
-
-                <para>
-
-                    <literal>B=gsort(A,'lr')</literal> は<literal>A</literal>
-
-                    の行を辞書的に降順にソートします.
-
-                    <literal>B</literal>は,
-
-                    <literal>B</literal>の各行が<literal>B(i,:)&gt;=B(j,:)</literal>
-
-                    (ただし,<literal>i&lt;j</literal>)となるように,
-
-                    行列<literal>A</literal>の行を並び替えることにより
-
-                    得られます.
-
-                </para>
-
-                <para>
-
-                    <literal>B=gsort(A,'lr','i')</literal> は
-
-                    昇順の辞書的ソートについても同様に動作します.
-
-                </para>
-
-            </listitem>
-
-            <listitem>
-
-                <para>
-
-                    <literal>B=gsort(A,'lc')</literal>
-
-                    の列を辞書的に降順にソートします.
-
-                    <literal>B</literal>は,
-
-                    <literal>B</literal>の各列が<literal>B(:,i)&gt;=B(:,j)</literal>
-
-                    (ただし,<literal>i&lt;j</literal>となるように,
-
-                    行列<literal>A</literal>の列を並び替えることにより
-
-                    得られます.
-
-                </para>
-
-                <para>
-
-                    <literal>B=gsort(A,'lc','i')</literal> は
-
-                    昇順の辞書的ソートについても同様に動作します.
-
-                </para>
-
-            </listitem>
-
-        </itemizedlist>
-
-        <para>二番目の戻り値引数が指定された場合,
-
-            <literal>k</literal>に<literal>A</literal>のソートされた値の添え字が
-
-            代入されます.
-
-            <literal>[B,k]=gsort(A,'g')</literal>の場合,
-
-            <literal>B==A(k)</literal>となります.
-
-            <emphasis role="bold">このアルゴリズムは,等しい値を有する
-
-                レコードの相対的な順序を保持します.
-
-            </emphasis>
-
-        </para>
-
-        <para>
-
-            <literal>v</literal> が複素数の場合, その要素は
-
-            大きさ,すなわち, abs(<literal>v</literal>) によりソートされます,
-
-            2番目の引数としては<literal>'g'</literal>のみが複素数で使用可能です.
-
-        </para>
-
-        <para>
-
-            複素数の場合, <literal>gsort</literal> はオーバーロードできます.
-
-        </para>
-
-        <para>マクロを参照:
-
-            SCI/modules/elementary_functions/macros/%_gsort.sci
-
-        </para>
-
-        <para>
-
-            (実数,整数または文字列ベクトル/行列または疎ベクトル以外の)
-
-            管理されない型のオーバーロードが可能です.
-
-        </para>
-
-        <para>
-
-            <literal>v</literal> が <literal>%nan</literal> または
-
-            <literal>%inf</literal> を要素として有する場合, gsort は
-
-            これらを <literal>'d'</literal> の場合は先頭,
-
-            <literal>'i'</literal>の場合は末尾に置きます.
-
-        </para>
-
-    </refsection>
-
-    <refsection>
-
-        <title>例</title>
-
-        <programlisting role="example">
-
-            alr=[1,2,2;
-
-            1,2,1;
-
-            1,1,2;
-
-            1,1,1];
-
-            [alr1,k]=gsort(alr,'lr','i')
-
-            [alr1,k]=gsort(alr,'lc','i')
-
-            v=int32(alr)
-
-            gsort(v)
-
-            gsort(v,'lr','i')
-
-            gsort(v,'lc','i')
-
-            v=['Scilab' '2.6'
-
-            'Scilab' '2.7'
-
-            'xcos' '2.7'
-
-            'Scilab' '3.1'
-
-            'xcos' '3.1'
-
-            'xcos' '4.0'
-
-            'Scilab' '4.0']
-
-            gsort(v,'lr','i')
-
-            gsort(v,'lc','i')
-
-        </programlisting>
-
-    </refsection>
-
-    <refsection role="see also">
-
-        <title>参照</title>
-
-        <simplelist type="inline">
-
-            <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>
-
-                    この関数は(実数, 整数または文字列ベクトル/行列または疎ベクトル以外の)
-
-                    管理されない型についてオーバーロードできるようになりました.
-
-                </revremark>
-
-            </revision>
-
-        </revhistory>
-
-    </refsection>
-
-</refentry>
-
diff --git a/scilab/modules/elementary_functions/help/pt_BR/searchandsort/gsort.xml b/scilab/modules/elementary_functions/help/pt_BR/searchandsort/gsort.xml
deleted file mode 100644 (file)
index 6005a85..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-<?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
- *
- * 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="pt">
-    <refnamediv>
-        <refname>gsort</refname>
-        <refpurpose>ordenação decrescente</refpurpose>
-    </refnamediv>
-    <refsynopsisdiv>
-        <title>Seqüência de Chamamento</title>
-        <synopsis>[s, [k]]=gsort(v )
-            [s, [k]]=gsort(v,flag1)
-            [s, [k]]=gsort(v,flag1,flag2)
-        </synopsis>
-    </refsynopsisdiv>
-    <refsection>
-        <title>Parâmetros</title>
-        <variablelist>
-            <varlistentry>
-                <term>v,s</term>
-                <listitem>
-                    <para>vetor ou matriz de reais, inteiros ou strings ou sparse
-                        vector
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>flag1</term>
-                <listitem>
-                    <para>
-                        um string <literal>'r'</literal>,
-                        <literal>'c'</literal>,<literal>'g'</literal>,<literal>'lr'</literal>
-                        ou <literal>'lc'</literal>.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>flag2</term>
-                <listitem>
-                    <para>
-                        um string <literal>'i'</literal> para ordem crescente ou
-                        <literal>'d'</literal> para ordem decrescente. k : vetor ou matriz
-                        de inteiros
-                    </para>
-                </listitem>
-            </varlistentry>
-        </variablelist>
-    </refsection>
-    <refsection>
-        <title>Descrição</title>
-        <para>
-            <literal>gsort</literal> é semelhante a <literal>sort</literal> com
-            propriedades adicionais. O terceiro argumento pode ser usado para escolher
-            ordem crescente ou decrescente. O segundo argumento podem ser usado para
-            ordens léxicas.
-        </para>
-        <para>
-            <literal>[s,k]=gsort(a,'g')</literal> e
-            <literal>[s,k]=gsort(a,'g','d')</literal> são o mesmo que
-            <literal>[s,k]=gsort(a)</literal>. Eles realizam uma ordenação das
-            entradas da matriz <literal>a</literal>, <literal>a</literal> sendo vista
-            como vetor de pilhas <literal>a(:)</literal> (coluna a coluna).
-            <literal>[s,k]=gsort(a,'g','i')</literal> realiza a mesma operação, mas em
-            ordem crescente.
-        </para>
-        <para>
-            <literal>[s,k]=gsort(a,'lr')</literal> ordena as linhas da matriz
-            <literal>a</literal> em ordem léxica decrescente. <literal>s</literal> é
-            obtida por uma permutação das linhas da matriz <literal>a</literal> dada
-            pelo vetor coluna <literal>k</literal>) de tal modo que as linhas de
-            <literal>s</literal> verificam <literal>s(i,:) &gt; s(j,:)</literal> se
-            <literal>i&lt;j</literal>. <literal>[s,k]=gsort(a,'lr','i')</literal>
-            realiza a mesma operação, mas em ordem léxica crescente.
-        </para>
-        <para>
-            <literal>[s,k]=gsort(a,'lc')</literal> ordena as colunas da matriz
-            <literal>a</literal> em ordem léxica decrescente. <literal>s</literal> é
-            obtida por uma permutação das colunas da matriz <literal>int(a)</literal>
-            (ou <literal>a</literal>) dada pelo vetor linha <literal>k</literal>) ide
-            tal modo que as colunas de <literal>s</literal> verificam <literal>s(:,i)
-                &gt; s(:,j)
-            </literal>
-            se <literal>i&lt;j</literal>.
-            <literal>[s,k]=gsort(a,'lc','i')</literal> realiza a mesma operação, mas
-            em ordem léxica crescente.
-        </para>
-        <para>
-            Quando <literal>v</literal> é complexo, os elementos são ordenados
-            pela magnitude, i.e., abs(<literal>v</literal>) . Apenas 'g' como segundo
-            argumento funciona com complexos.
-        </para>
-        <para>
-            Se <literal>v</literal> tem elementos <literal>%nan</literal> ou
-            <literal>%inf</literal> . gsort coloca esses elementos no início com o
-            argumento <literal>'d'</literal> ou ao fim com o argumento
-            <literal>'i'</literal>.
-        </para>
-    </refsection>
-    <refsection>
-        <title>Exemplos</title>
-        <programlisting role="example">
-            alr=[1,2,2;
-            1,2,1;
-            1,1,2;
-            1,1,1];
-            [alr1,k]=gsort(alr,'lr','i')
-            [alr1,k]=gsort(alr,'lc','i')
-
-            v=int32(alr)
-
-            gsort(v)
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-
-            v=['Scilab' '2.6'
-            'Scilab' '2.7'
-            'Scicos' '2.7'
-            'Scilab' '3.1'
-            'Scicos' '3.1'
-            'Scicos' '4.0'
-            'Scilab' '4.0']
-
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-        </programlisting>
-    </refsection>
-    <refsection>
-        <title>Ver Também</title>
-        <simplelist type="inline">
-            <member>
-                <link linkend="find">find</link>
-            </member>
-            <member>
-                <link linkend="overloading">overloading</link>
-            </member>
-        </simplelist>
-    </refsection>
-    <refsection>
-        <title>Bibliografia</title>
-        <para>Algoritmo Quicksort.</para>
-    </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
deleted file mode 100644 (file)
index ab3bc36..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-<?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
- *
- * 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 [,k]]=gsort(A)
-            [B [,k]]=gsort(A,option)
-            [B [,k]]=gsort(A,option,direction)
-        </synopsis>
-    </refsynopsisdiv>
-    <refsection>
-        <title>Аргументы</title>
-        <variablelist>
-            <varlistentry>
-                <term>A</term>
-                <listitem>
-                    <para>
-                        scalar, vector, matrix or hypermatrix of booleans, integers, real numbers,
-                        or text, or a sparse vector of reals.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>option</term>
-                <listitem>
-                    <para>символьная строка. Она задаёт тип требуемой сортировки:
-                    </para>
-                    <itemizedlist>
-                        <listitem>
-                            <para>
-                                'r' : сортируется каждый столбец <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>
-                                'c': сортируется каждая строка <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>
-                                'g': сортируются все элементы <literal>A</literal>. Это значение по умолчанию.
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'lr': лексикографическая сортировка строк
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                        <listitem>
-                            <para>'lc': лексикографическая сортировка столбцов
-                                <literal>A</literal>
-                            </para>
-                        </listitem>
-                    </itemizedlist>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>direction</term>
-                <listitem>
-                    <para>символьная строка. Она задаёт направление сортировки:
-                        <literal>'i'</literal> устанавливает порядок возрастания, а
-                        <literal>'d'</literal> устанавливает порядок убывания (по умолчанию).
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>B</term>
-                <listitem>
-                    <para>
-                        массив того же типа и размеров, что и <literal>A</literal>.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>k</term>
-                <listitem>
-                    <para>вещественный массив целочисленных значений тех же размеров, что и
-                        <literal>A</literal>. Содержит исходные индексы.
-                    </para>
-                </listitem>
-            </varlistentry>
-        </variablelist>
-    </refsection>
-    <refsection>
-        <title>Описание</title>
-        <para>
-            <literal>gsort</literal> использует алгоритм "быстрой сортировки" для различных типов данных.
-        </para>
-        <itemizedlist>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'g')</literal>,
-                    <literal>B=gsort(A,'g','d')</literal> и
-                    <literal>B=gsort(A)</literal> сортируют элементы массива
-                    <literal>A</literal>, который рассматривается как <literal>A(:)</literal> в порядке убывания.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'g','i')</literal> сортирует элементы массива <literal>A</literal> в порядке возрастания.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lr')</literal> сортирует строки
-                    <literal>A</literal> в лексическом порядке убывания. <literal>B</literal>
-                    получается перестановкой строк матрицы <literal>A</literal> таким образом, чтобы строки <literal>B</literal> удовлетворяли <literal>B(i,:)&gt;=B(j,:)</literal>, если <literal>i&lt;j</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lr','i')</literal> работает аналогично для лексического порядка возрастания.
-                </para>
-            </listitem>
-            <listitem>
-                <para>
-                    <literal>B=gsort(A,'lc')</literal> сортирует столбцы <literal>A</literal> в лексическом порядке убывания. <literal>B</literal> получается перестановкой столбцов матрицы <literal>A</literal> таким образом, чтобы столбцы           <literal>B</literal> удовлетворяли <literal>B(:,i)&gt;=B(:,j)</literal>, если
-                    <literal>i&lt;j</literal>.
-                </para>
-                <para>
-                    <literal>B=gsort(A,'lc','i')</literal> работает аналогично для лексического порядка возрастания.
-                </para>
-            </listitem>
-        </itemizedlist>
-        <para>
-            Если требуется, то второй возвращаемый аргумент <literal>k</literal> содержит индексы отсортированных значений в <literal>A</literal>. Если <literal>[B,k]=gsort(A,'g')</literal>, то  <literal>B==A(k)</literal>.
-            <emphasis role="bold">
-                Алгоритм сохраняет относительный порядок записей с одинаковыми значениями.
-            </emphasis>
-        </para>
-        <para>
-            Когда <literal>v</literal> является комплексным, элементы сортируются по амплитуде, т. е. abs(<literal>v</literal>). Только <literal>'g'</literal> в качестве второго аргумента работает с комплексными значениями.
-        </para>
-        <para>
-            С комплексными числами <literal>gsort</literal> может быть перегружена
-        </para>
-        <para>смотрите макрос:
-            SCI/modules/elementary_functions/macros/%_gsort.sci
-        </para>
-        <para>
-            Можно делать перегрузку для типов, которые не управляются (отличные от матриц/векторов вещественных, целочисленных или символьных значений, либо разрежённого вектора).
-        </para>
-        <para>
-            Если <literal>v</literal> содержит элементы <literal>%nan</literal> или
-            <literal>%inf</literal>, то <literal>gsort</literal> помещает их в начало с аргументом <literal>'d'</literal>, либо в конец с аргументом <literal>'i'</literal>.
-        </para>
-    </refsection>
-    <refsection>
-        <title>Примеры</title>
-        <programlisting role="example">
-            alr=[1,2,2;
-            1,2,1;
-            1,1,2;
-            1,1,1];
-            [alr1,k]=gsort(alr,'lr','i')
-            [alr1,k]=gsort(alr,'lc','i')
-
-            v=int32(alr)
-
-            gsort(v)
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-
-            v=['Scilab' '2.6'
-            'Scilab' '2.7'
-            'xcos' '2.7'
-            'Scilab' '3.1'
-            'xcos' '3.1'
-            'xcos' '4.0'
-            'Scilab' '4.0']
-
-            gsort(v,'lr','i')
-            gsort(v,'lc','i')
-        </programlisting>
-    </refsection>
-    <refsection role="see also">
-        <title>Смотрите также</title>
-        <simplelist type="inline">
-            <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>
-                    Эта функция позволяет делать перегрузку для типов, которые не управляются (отличные от матриц/векторов вещественных, целочисленных или символьных значений, либо разрежённого вектора).
-                </revremark>
-            </revision>
-            <revision>
-                <revnumber>6.1.0</revnumber>
-                <revremark>
-                    Booleans can now be sorted.
-                </revremark>
-            </revision>
-        </revhistory>
-    </refsection>
-</refentry>
diff --git a/scilab/modules/elementary_functions/macros/%gsort_multilevel.sci b/scilab/modules/elementary_functions/macros/%gsort_multilevel.sci
new file mode 100644 (file)
index 0000000..13c9d36
--- /dev/null
@@ -0,0 +1,187 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 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 [sorted, K] = %gsort_multilevel(array, sortype, sortdir, criteria)
+    // This internal overload sorts only dense matrices.
+    // For hypermatrices, %hm_gsort() is called upstream
+    //   - to reformat the input as a matrix
+    //   - to call %_gsort() with the equivalent input matrix
+    //   - to reformat the output as expected
+    //   There is nothing specific to complex numbers with hypermatrices
+    // For sparse matrices, %sp_gsort() is called upstream.
+    //
+    // array   : vector or matrix to be sorted.
+    //           Hypermatrices are pre- and post-processed by %hm_gsort()
+    // sortype : "g" "r" "c" "lr" "lc". Default "g"
+    // sortdir: [], or vector of "i" or "d". Default = "d"
+    // criteria: list of Scilab functions or primitives handles, or :.
+    //           When a function fun requires some additional parameters
+    //           a, b, c, ... list(fun, a, b, c,..) must be provided
+    //           instead of only fun.
+
+    sa = size(array)
+
+    // CHECKING INPUT PARAMETERS
+    // -------------------------
+    // array:
+    // This overload is called only when array is defined and are complex numbers
+
+    // sortype:
+    if ~isdef("sortype", "l") || sortype==[] || (type(sortype)==10 && sortype(1)=="")
+        sortype = "g"
+    elseif type(sortype)~=10
+        msg = _("%s: Argument #%d: Text(s) expected.\n")
+        error(msprintf(msg, "gsort", 2))
+    else
+        sortype = convstr(sortype(1))
+        if ~or(sortype==["g" "r" "c" "lr" "lc"])
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "gsort", 2, "''g'',''r'',''c'',''lc'',''lr''"))
+        end
+    end
+
+    // sortdir:
+    if ~isdef("sortdir", "l") || sortdir==[]
+        sortdir = "d"           // for back-compatibility
+    elseif type(sortdir)~=10
+        msg = _("%s: Argument #%d: Text(s) expected.\n")
+        error(msprintf(msg, "gsort", 3))
+    else
+        sortdir = convstr(sortdir)
+        k = find(sortdir <> "i" & sortdir <> "d")
+        if k <> []
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "gsort", 3, "''i'',''d''"))
+        end
+    end
+
+    // criteria:
+    if type(criteria) <> 15 then
+        msg = _("%s: Argument #%d: List expected.\n")
+        error(msprintf(msg, "gsort", 4))
+    end
+    if size(criteria) <> size(sortdir,"*") then
+        msg = _("%s: Arguments #%d and #%d: Same numbers of elements expected.\n")
+        error(msprintf(msg, "gsort", 3, 4))
+    end
+    for c = criteria
+        t = type(c)==13 || typeof(c)=="fptr" || ..
+           (typeof(c)=="implicitlist" && (1:1:$)==c)
+        if ~t & type(c)==15
+            if length(c) > 0
+                t = type(c(1))==13 || typeof(c(1))=="fptr" || ..
+                   (typeof(c(1))=="implicitlist" && (1:1:$)==c(1))
+            end
+        end
+        if ~t
+            msg = _("%s: Argument #%d: List of functions identifiers expected.\n")
+            error(msprintf(msg, "gsort", 4))
+        end
+    end
+
+    // ONLY ONE LEVEL => SIMPLE DIRECT PROCESSING
+    // ------------------------------------------
+    if size(criteria)==1 then
+        fun = criteria(1)
+        if typeof(fun)=="implicitlist" & fun==(1:1:$)
+            [sorted, K] = gsort(array, sortype, sortdir)
+        else
+            v = %gsort_eval(array, fun)
+            [sorted, K] = gsort(v, sortype, sortdir)
+            select sortype
+            case "g"
+                sorted = matrix(array(K), size(array))
+            case "r"
+                C = ones(sa(1),1) * (1:sa(2))
+                sorted = matrix(array(K+(C-1)*sa(1)), sa)
+            case "c"
+                R = (1:sa(1))' * ones(1,sa(2))
+                sorted = matrix(array(R+(K-1)*sa(1)), sa)
+            case "lr"
+                sorted = array(K, :)
+            case "lc"
+                sorted = array(:, K)
+            end
+        end
+        return
+    end
+
+    // OTHERWISE:
+    // BUILDING THE MATRIX OF SEPARATE RANKS
+    // -------------------------------------
+    nbcrit = length(criteria)
+    a = array(:)
+    kk = []
+    for i = 1:nbcrit
+        fun = criteria(i)
+        v = %gsort_eval(a, fun)
+        [vs, k0] = gsort(v(:), "g", sortdir(i))
+        [?, k2] = gsort(k0,"g","i")
+        // The k(i) of equal elements following the first one must be
+        //  set to the heading index:
+        b = [%T ; vs(2:$) <> vs(1:$-1)];
+        k = cumsum(b);  // Done!
+        kk = [kk k(k2)];
+    end
+
+    // SORTING
+    // -------
+    if sortype=="g" then
+        [?, K] = gsort(kk, "lr", "i");
+        K = matrix(K, sa)
+        sorted = matrix(array(K), sa)
+
+    elseif or(sortype==["c" "r"]) then
+        [?, K] = gsort(kk, "lr", "i");
+        K = matrix(K, sa)
+        z = zeros(sa(1),sa(2))
+        z(K) = 1:prod(sa)
+        [?, K] = gsort(z, sortype, "i")
+        if sortype=="c" then
+            R = (1:sa(1))' * ones(1,sa(2))
+            sorted = matrix(array(R+(K-1)*sa(1)), sa)
+        else // "r"
+            C = ones(sa(1),1) * (1:sa(2))
+            sorted = matrix(array(K+(C-1)*sa(1)), sa)
+        end
+
+    elseif sortype=="lr" then
+        tmp = ones(nbcrit,1)*(1:sa(2))+(0:nbcrit-1)'*ones(1,sa(2))*sa(2)
+        tmp = matrix(kk, sa(1), -1)(:,tmp)
+        [?, K] = gsort(tmp, "lr", "i");
+        sorted = array(K, :)
+
+    else // sortype=="lc"
+        tmp = matrix(kk',nbcrit*sa(1), -1)'
+        [?, K] = gsort(tmp, "lr", "i");
+        K = K'
+        sorted = array(:,K)
+    end
+
+endfunction
+// ------------------------------------------------------
+function v = %gsort_eval(a, fun)
+    if type(fun)==15
+        params = fun
+        params(1) = null()
+        fun = fun(1)
+        if typeof(fun)=="fptr" & fun==atan & type(a)==1 & ~isreal(a)
+            v = fun(imag(a), real(a)) + params(1)
+        else
+            v = fun(a, params(:))
+        end
+    elseif typeof(fun)=="fptr" & fun==atan & type(a)==1 & ~isreal(a)
+        v = atan(imag(a), real(a))
+    elseif typeof(fun)=="implicitlist" & (1:1:$)==fun
+        v = a
+    else
+        v = fun(a)
+    end
+endfunction
index 8b24fc2..d7c5e7a 100644 (file)
@@ -1,7 +1,7 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyrifht (C) 2012 - Scilab Enterprises - Cedric Delamarre
-//
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2016 - 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.
 // For more information, see the COPYING file which you should have received
 // along with this program.
 
-function [S, k] = %hm_gsort(A, optsort, directionsort)
-    rhs = argn(2);
-    lhs = argn(1);
+function [S, k] = %hm_gsort(A, method, varargin)
+    // method can be: 'g', 'r', 'c', 'lr', 'lc'
+    // sortdir = varargin(1): "i", "d", or vector of "i" and "d"
+    // criteria = varargin(2): list() of functions or builtin handles or :
+    //
+    // Called for all generic types: booleans, integers,
+    //  decimal or complex numbers, polynomials, texts
+
+    // INITIALIZATIONS
+    lhs = argn(1)
+    sizes = size(A)
+    L = prod(sizes(3:$))
     AisBool = typeof(A)=="boolean"
     if AisBool
         A = iconvert(A,1) // int8
     end
 
-    // 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"));
-        end
-        directionsort = "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"));
-        end
-        if pos_direction == [] then
-            error(msprintf(_("%s: Wrong value for input argument #%d: ''%s'' or ''%s'' expected.\n"), "gsort", 3, "d", "i"));
-        end
+    // CHECKING PARAMETERS
+    // method: checked in the gateway
+    if ~isdef("method","l")
+        method = "g"
     end
+    // sortdir, criteria: checked in each overload, since these ones
+    //      can also be called directly by the gateway
 
-    if(lhs == 1) // without output indices, gsort is faster.
-        if optsort == "g"
-            S = gsort(A(:), optsort, directionsort);
-            S = matrix(S, size(A));
+    // ONLY THE SORTED ARRAY IS EXPECTED (gsort is then faster)
+    if(lhs == 1)
+        if method == "g"
+            S = gsort(A(:), method, varargin(:))
+            S = matrix(S, size(A))
         else // 'r' 'c' 'lr' 'lc'
-            sizes = size(A);
-
             // transform input hypermatrix to a hypermatrix of 3 dimensions
-            l = prod(sizes(3:$));
-            mat = matrix(A,sizes(1), sizes(2), l);
+            mat = matrix(A,sizes(1), sizes(2), -1)
 
             // init output variables
-            S = zeros(sizes(1), sizes(2), l);
+            S = zeros(sizes(1), sizes(2), L)
 
-            // perform a 2D sort for each dimensions > 2
-            for i = 1:l
-                S(:,:,i) = gsort(mat(:,:,i), optsort, directionsort);
+            // perform a 2D sort for each sheet
+            for i = 1:L
+                S(:,:,i) = gsort(mat(:,:,i), method, varargin(:))
             end
-
-            // return the result with the good dimensions
-            S = matrix(S, sizes);
         end
+
+    // INDICES ARE ALSO EXPECTED
     else
-        if optsort == "g"
-            [S, k] = gsort(A(:), optsort, directionsort);
-            S = matrix(S, size(A));
-            k = matrix(k, size(A));
+        if method == "g"
+            [S, k] = gsort(A(:), method, varargin(:))
+            S = matrix(S, size(A))
+            k = matrix(k, size(A))
         else // 'r' 'c' 'lr' 'lc'
-            sizes = size(A);
-            sizesInd = size(A);
+            sizesInd = size(A)
 
             // transform input hypermatrix to a hypermatrix of 3 dimensions
-            l = prod(sizes(3:$));
-            mat = matrix(A,sizes(1), sizes(2), l);
+            mat = matrix(A,sizes(1), sizes(2), -1)
 
             // init output variables
-            S = zeros(sizes(1), sizes(2), l);
-            if optsort == "lc"
-                sizesInd(1) = 1;
-            elseif optsort == "lr"
-                sizesInd(2) = 1;
+            S = zeros(sizes(1), sizes(2), L)
+            if method == "lc"
+                sizesInd(1) = 1
+            elseif method == "lr"
+                sizesInd(2) = 1
             end
-            k = zeros(sizesInd(1), sizesInd(2), l);
+            k = zeros(sizesInd(1), sizesInd(2), L)
 
-            // perform a 2D sort for each dimensions > 2
-            for i = 1:l
-                [S(:,:,i), k(:,:,i)] = gsort(mat(:,:,i), optsort, directionsort);
+            // perform a 2D sort for each sheet
+            for i = 1:L
+                [S(:,:,i), k(:,:,i)] = gsort(mat(:,:,i), method, varargin(:))
             end
 
             // return the result with the good dimensions
-            S = matrix(S, sizes);
-            k = matrix(k, sizesInd);
+            k = matrix(k, sizesInd)
         end
     end
+    S = matrix(S, sizes)
     if AisBool then
         S = S==int8(1)
     end
diff --git a/scilab/modules/elementary_functions/macros/%s_gsort.sci b/scilab/modules/elementary_functions/macros/%s_gsort.sci
new file mode 100644 (file)
index 0000000..bbb0379
--- /dev/null
@@ -0,0 +1,64 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 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 [sorted, indin] = %s_gsort(array, method, sortdir, criteria)
+    // Sorting complex numbers.
+    // This overload sorts only dense matrices.
+    // For hypermatrices, %hm_gsort() is called upstream
+    // For sparse matrices, %sp_gsort() is called upstream.
+    //
+    // method  : "g" "r" "c" "lr" "lc"
+    // sortdir : [], or 1 or 2 elements in ["i" "d"]. Default = "d"
+    // criteria: list() of functions handles: real, imag, abs, atan
+
+    // DEMO
+    // ----
+    if argn(2)==0
+        i = grand(10,3,"uin",-1,1);
+        r = grand(10,3,"uin",-1,1);
+        c = r+i*%i
+        [cs, k] = %s_gsort(c, "g", ["d" "i"], list(abs, atan));
+        a = atand(imag(cs),real(cs));
+        disp(cs, abs(cs) + a*%i)
+        sorted = []
+        indin = []
+        return
+    end
+
+    // CHECKING INPUT PARAMETERS
+    // -------------------------
+    // array:
+    // This overload is called only when array is defined and are complex numbers
+
+    // DEFAULT VALUES
+    // method: checked in the gateway (and initialized when default)
+    if ~isdef("method", "l") | method==[] | (type(method)==10 & method(1)=="")
+        method = "g"
+    end
+
+    // sortdir: checked in %gsort_multilevel. Only setting the default:
+    if ~isdef("sortdir", "l") | sortdir==[] | (type(sortdir)==10 & sortdir(1)=="")
+        sortdir = "d"           // for back-compatibility
+    end
+    //criteria:  checked in %gsort_multilevel. Only setting the default:
+    if ~isdef("criteria", "l") | (type(criteria)==1 & criteria==[])
+        if size(sortdir,"*")==2
+            criteria = list(abs, atan)
+        else
+            criteria = list(abs)
+        end
+    end
+
+    // PROCESSING
+    // ----------
+    // Indices are computed anyway.
+   [sorted, indin] = %gsort_multilevel(array, method, sortdir, criteria)
+
+endfunction
index e4ced15..5bd874a 100644 (file)
@@ -17,6 +17,7 @@
 #include "function.hxx"
 #include "double.hxx"
 #include "string.hxx"
+#include "polynom.hxx"
 #include "overload.hxx"
 #include "gsort.hxx"
 #include "context.hxx"
@@ -36,18 +37,54 @@ types::Function::ReturnValue sci_gsort(types::typed_list &in, int _iRetCount, ty
         Scierror(77, _("%s: Wrong number of input argument(s): At least %d expected.\n"), "gsort", 1);
         return types::Function::Error;
     }
-    // The maximal number of input args may depend on the input data type, due to specific options
 
     //
-    // Special cases
-    //
+    // Custom typeof
+    // -------------
     if (in[0]->isGenericType() == false)
     {
         // custom types
         std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_gsort";
         return Overload::call(wstFuncName, in, _iRetCount, out);
     }
+    // Otherwise: max numbers of inputs / outputs
+    if (in.size() > 4 )
+    {
+        Scierror(77, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "gsort", 1, 4);
+        return types::Function::Error;
+    }
+    if (_iRetCount > 2)
+    {
+        Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "gsort", 1, 2);
+        return types::Function::Error;
+    }
+
+    // Get the sorting method, always as argin#2 for all generic types
+    // ----------------------
+    std::wstring wstrProcess = L"g";
+    if (in.size() >= 2)
+    {
+        if (in[1]->isString() == false)
+        {
+            Scierror(999, _("%s: Wrong type for input argument #%d : string expected.\n"), "gsort", 2);
+            return types::Function::Error;
+        }
+
+        wstrProcess = in[1]->getAs<types::String>()->get(0);
+
+        if ( wstrProcess != L"c"  &&
+                wstrProcess != L"r"  &&
+                wstrProcess != L"g"  &&
+                wstrProcess != L"lc" &&
+                wstrProcess != L"lr")
+        {
+            Scierror(999, _("%s: Argument #%d: Must be in the set {%s}.\n"), "gsort", 2, "'g','r','c','lc','lr'");
+            return types::Function::Error;
+        }
+    }
+
     types::GenericType* pGTIn = in[0]->getAs<types::GenericType>();
+       
     if (pGTIn->getDims() > 2)
     {
         // hypermatrix
@@ -59,29 +96,25 @@ types::Function::ReturnValue sci_gsort(types::typed_list &in, int _iRetCount, ty
         std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_gsort";
         return Overload::call(wstFuncName, in, _iRetCount, out);
     }
-    if (pGTIn->isComplex() && symbol::Context::getInstance()->getFunction(symbol::Symbol(L"%_gsort")))
+    if (pGTIn->isDouble() && pGTIn->isComplex())
     {
-        // complex is documented as being managed through overloading
-        std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_gsort";
-        return Overload::call(wstFuncName, in, _iRetCount, out);
+        // complex numbers
+        return Overload::call(L"%s_gsort", in, _iRetCount, out);
     }
-
-    //
-    // Common case
-    //
-
-    if (in.size() > 3)
+    if (in.size() == 4)
     {
-        Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "gsort", 1, 3);
-        return types::Function::Error;
+        // Direct multilevel sorting
+        return Overload::call(L"%gsort_multilevel", in, _iRetCount, out);
     }
-
-    if (_iRetCount > 2)
+    if (pGTIn->isPoly())
     {
-        Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "gsort", 1, 2);
-        return types::Function::Error;
+        // real or complex polynomials
+        return Overload::call(L"%p_gsort", in, _iRetCount, out);
     }
 
+    //
+    // Common case
+    //
     // Get the sorting order
     std::wstring wstrWay = L"d";
     if (in.size() > 2)
@@ -100,29 +133,6 @@ types::Function::ReturnValue sci_gsort(types::typed_list &in, int _iRetCount, ty
         }
     }
 
-    // Get the sorting method
-    std::wstring wstrProcess = L"g";
-    if (in.size() >= 2)
-    {
-        if (in[1]->isString() == false)
-        {
-            Scierror(999, _("%s: Wrong type for input argument #%d : string expected.\n"), "gsort", 2);
-            return types::Function::Error;
-        }
-
-        wstrProcess = in[1]->getAs<types::String>()->get(0);
-
-        if ( wstrProcess != L"c"  &&
-                wstrProcess != L"r"  &&
-                wstrProcess != L"g"  &&
-                wstrProcess != L"lc" &&
-                wstrProcess != L"lr")
-        {
-            Scierror(999, _("%s: Wrong value for input argument #%d: ['g' 'r' 'c' 'lc' 'lr'] expected.\n"), "gsort", 2);
-            return types::Function::Error;
-        }
-    }
-
     // Get data and perform operation for each types::
     types::Double* pDblInd = NULL;
     if (_iRetCount == 2)
index fd97aea..fd1a5d5 100644 (file)
@@ -342,19 +342,19 @@ Nrand = 100;
 vmax = 4;
 for itype = [1 2 4 8 11 12 14 18]
     a = iconvert(matrix(grand(1,"prm",(1:N*P)'),N,P), itype);
-
+    
     //-----Global sort --------------------------------
     [a1,ind] = gsort(a,"g");
     assert_checkequal(a1, iconvert(matrix(N * P:-1:1,N,P), itype));
     assert_checkequal(a1, matrix(a(ind),N,P));
-
+    
     for i = 1:Nrand
         b = iconvert(10 * rand(N,P,"u"), itype);
         [b1,ind] = gsort(b,"g");
         assert_checkequal(b1, matrix(b(ind),N,P));
         assert_checktrue(or(b1(1:$-1) - b1(2:$) >= 0));
     end
-
+    
     //increasing values
     [a1,ind] = gsort(a,"g","i");
     assert_checkequal(a1, iconvert(matrix(1:N*P,N,P), itype));
@@ -366,7 +366,7 @@ for itype = [1 2 4 8 11 12 14 18]
         assert_checkequal(b1, matrix(b(ind),N,P));
         assert_checktrue(or(b1(1:$-1) - b1(2:$) <= 0));
     end
-
+    
     //----sort each column of a ('r' means that the row indice is used for sorting)
     [a1,ind] = gsort(a,"r");
     nc = size(a,"c");
@@ -375,13 +375,13 @@ for itype = [1 2 4 8 11 12 14 18]
         test = [test, matrix(a(ind(:,i),i),N,1)];
     end
     assert_checkequal(a1, test);
-
+    
     test = [];
     for i =1:nc
         test = [test, gsort(a(:,i),"g")];
     end
     assert_checkequal(a1, test);
-
+    
     if itype < 10
         for i = 1:Nrand
             b = iconvert(10*rand(N,P,"u"), itype);
@@ -424,7 +424,7 @@ for itype = [1 2 4 8 11 12 14 18]
         test = [test; gsort(a(i,:),"g")];
     end
     assert_checkequal(a1, test);
-
+    
     if itype < 10
         for i = 1:Nrand
             b = iconvert(10 * rand(N,P,"u"), itype);
@@ -451,7 +451,7 @@ for itype = [1 2 4 8 11 12 14 18]
         test = [test; gsort(a(i,:),"g","i")];
     end
     assert_checkequal(a1, test);
-
+    
     //----sort the rows of a in lexicographic order
     //    i.e a(k,:) < a(l,:) if there's a number j
     //    such that a(k,j) < a(l,j) or a(k,p)=a(l,p) for p in [1,j-1];
@@ -464,12 +464,12 @@ for itype = [1 2 4 8 11 12 14 18]
     // a random permutation
     [ax,perm] = gsort(rand(1,N1,"u"));
     a = iconvert(alr(perm,:), itype);
-
+    
     [a1,ind] = gsort(a,"lr");
-
+    
     assert_checkequal(a1, iconvert(alr, itype));
     assert_checkequal(a1, matrix(a(ind,:),N1,P1));
-
+    
     [a2,ind2] = gsort(a*[100;10;1],"g");
     assert_checkequal(ind2, ind);
     ///////////////////////
@@ -480,15 +480,15 @@ for itype = [1 2 4 8 11 12 14 18]
         v = double(b1)*((vmax+1)^[P-1:-1:0])';
         assert_checktrue(or(v(2:$) - v(1:$-1) <= 0));
     end
-
+    
     // increasing
     [a1,ind] = gsort(a,"lr","i");
     assert_checkequal(a1, iconvert(alr(N1:-1:1,:), itype));
     assert_checkequal(a1, matrix(a(ind,:),N1,P1));
-
+    
     [a2,ind2] = gsort(a*[100;10;1],"g","i");
     assert_checkequal(ind2, ind);
-
+    
     for i = 1:Nrand
         b = int(vmax * rand(N,P,"u"));
         [b1,ind] = gsort(b,"lr","i");
@@ -496,21 +496,21 @@ for itype = [1 2 4 8 11 12 14 18]
         v = double(b1)*((vmax+1)^[P-1:-1:0])';
         assert_checktrue(or(v(2:$) - v(1:$-1) >= 0));
     end
-
+    
     //----sort the columns of a in lexicographic order
     N1 = 3; P1 = 4;
     alr = alr';
     // a random permutation
     [ax,perm] = gsort(rand(1,P1,"u"));
     a = iconvert(alr(:,perm), itype);
-
+    
     [a1,ind] = gsort(a,"lc");
     assert_checkequal(a1, iconvert(alr, itype));
     assert_checkequal(a1, matrix(a(:,ind),N1,P1));
-
+    
     [a2,ind2] = gsort([100,10,1]*a,"g");
     assert_checkequal(ind2, ind);
-
+    
     for i = 1:Nrand
         b = int(vmax*rand(N1,P1,"u"));
         [b1,ind] = gsort(b,"lc");
@@ -523,10 +523,10 @@ for itype = [1 2 4 8 11 12 14 18]
     [a1,ind] = gsort(a,"lc","i");
     assert_checkequal(a1, iconvert(alr(:,P1:-1:1), itype));
     assert_checkequal(a1, matrix(a(:,ind),N1,P1));
-
+    
     [a2,ind2] = gsort([100,10,1] * a,"g","i");
     assert_checkequal(ind2, ind);
-
+    
     for i = 1:Nrand
         b = int(vmax*rand(N,P,"u"));
         [b1,ind] = gsort(b,"lc","i");
@@ -534,7 +534,7 @@ for itype = [1 2 4 8 11 12 14 18]
         v = ((vmax+1)^[N-1:-1:0])*b1;
         assert_checktrue(or(v(2:$) - v(1:$-1) >= 0));
     end
-
+    
     a = iconvert([1,1,1,1,2,2,3,3,2,2,3,3,4,4,4,4,4,4,4,4,5,5,5,6,6,6,7,7,7,7,..
     8,8,8,8,9,9,9,9,9,9,9,7,9,10,10,10,10,11,11,11,12,13,13,13,13,14,14,12,12,..
     14,14,14,14,14,14,15,15,15,15,16,17,18;
@@ -549,7 +549,7 @@ for itype = [1 2 4 8 11 12 14 18]
     assert_checktrue(or(t(:,1) >= 0));      // int8: <= 0
     assert_checktrue(or(t(find(t(:,1)==0),2) >= 0));
     assert_checkequal(a(ind,:), b);
-
+    
     for k = 1:30
         p = grand(1,"prm",(1:size(a,1))');
         [b,ind] = gsort(a(p,:),"lr","i");
@@ -558,13 +558,13 @@ for itype = [1 2 4 8 11 12 14 18]
         assert_checktrue(or(t(find(t(:,1)==0),2) >= 0));
         assert_checkequal(a(p(ind),:), b);
     end
-
+    
     [b,ind] = gsort(a,"lr","d");
     t = b(1:$-1,:) - b(2:$,:);
     assert_checktrue(or(t(:,1) >= 0));      // int8: <= 0
     assert_checktrue(or(t(find(t(:,1)==0),2) >= 0));
     assert_checkequal(a(ind,:), b);
-
+    
     for k = 1:30
         p = grand(1,"prm",(1:size(a,1))');
         [b,ind] = gsort(a(p,:),"lr","d");
@@ -573,7 +573,7 @@ for itype = [1 2 4 8 11 12 14 18]
         assert_checktrue(or(t(find(t(:,1)==0),2) >= 0));
         assert_checkequal(a(p(ind),:), b);
     end
-
+    
     a = b;
     a([10 60],:) = a([60 10],:);
     [b,ind] = gsort(a,"lr","i");
@@ -581,7 +581,7 @@ for itype = [1 2 4 8 11 12 14 18]
     assert_checktrue(or(t(:,1) >= 0));      // int8: <= 0
     assert_checktrue(or(t(find(t(:,1)==0),2) >= 0));
     assert_checkequal(a(ind,:), b);
-
+    
     [b,ind] = gsort(a,"lr","d");
     t = b(1:$-1,:) - b(2:$,:);
     assert_checktrue(or(t(:,1) >= 0));      // int8: <= 0
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/gsort_complex.tst b/scilab/modules/elementary_functions/tests/unit_tests/gsort_complex.tst
deleted file mode 100644 (file)
index da01f40..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// =============================================================================
-// 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
-//
-//  This file is distributed under the same license as the Scilab package.
-// =============================================================================
-
-// <-- CLI SHELL MODE -->
-// <-- NO CHECK REF -->
-
-//================================ sparse complex ==============================
-
-// Tests in gsort_sparse.tst
-
-//================================ complex matrix ==============================
-x = [3  1  5 ; 2 9 8];
-y = [2  4  1 ; 4 1 3];
-c = x + y * %i;
-
-ref_ind = [    4.    5.    3.  ;    6.    2.    1.  ];
-ref_values = [     9. + %i      5. + %i      1. + 4.*%i  ;    8. + 3.*%i    2. + 4.*%i    3. + 2.*%i ];
-[v,ind] = gsort(c);
-assert_checkequal(ref_ind, ind);
-assert_checkequal(ref_values, v);
-
-[v1,ind1] = gsort(abs(c));
-[v2,ind2] = gsort(c);
-assert_checkequal(ind1, ind2);
-
-A = [18 21 10 7 5];
-B = [1  3  22 8 4];
-y = complex(A,B);
-[a,b] = gsort(y);
-assert_checkequal(b, [3 2 1 4 5]);
-assert_checkequal(y(b), a);
-
-assert_checkfalse(execstr("[a,b] = gsort(y,''l'')", "errcatch") == 0);
-refMsg = msprintf(_("%s: Wrong value for input argument #%d: [''g'' ''r'' ''c'' ''lc'' ''lr''] expected.\n"), "gsort", 2);
-assert_checkerror("[a,b] = gsort(y,''l'')", refMsg);
-
-ierr = execstr("[a,b] = gsort(y,''g'');","errcatch");
-assert_checkequal(ierr, 0);
-
-ierr = execstr("[a,b] = gsort(y,''r'');","errcatch");
-assert_checkequal(ierr, 0);
-
-ierr = execstr("[a,b] = gsort(y,''c'');","errcatch");
-assert_checkequal(ierr, 0);
-
-ierr = execstr("[a,b] = gsort(y,''lc'');","errcatch");
-assert_checkequal(ierr, 0);
-
-ierr = execstr("[a,b] = gsort(y,''lr'');","errcatch");
-assert_checkequal(ierr, 0);
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_complex.tst b/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_complex.tst
new file mode 100644 (file)
index 0000000..a5f5591
--- /dev/null
@@ -0,0 +1,286 @@
+// ===================================================================
+// 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-2020 - Samuel GOUGEON
+//
+//  This file is distributed under the same license as the Scilab package.
+// ===================================================================
+
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+
+//================================ sparse complex ====================
+//  Tests in gsort_sparse.tst
+//
+//================================ complex matrix ====================
+/*
+i = %i;
+c  = [
+i         -1. - i    -i         -i       
+1. - i    -1.         1.         1. + i  
+-1. + i     1.         0.         0.      
+i         -1. + i     1.         1. - i  
+0.         1. - i     1. + i     0.      
+1.        -1. - i    -1.        -1. + i  
+i         -1. + i    -1. + i    -i       
+1. - i    -1.         1.         1. + i  
+-1. + i    -i         -1.        -i       
+];
+*/
+
+x = [3  1  5 ; 2 9 8];
+y = [2  4  1 ; 4 1 3];
+c = x + y * %i;
+
+ref_ind = [  4.    5.    3.  ;    6.    2.    1.  ];
+ref_values = [ 9 +   %i, 5 +   %i,  1 + 4*%i
+8 + 3*%i, 2 + 4*%i,  3 + 2*%i ];
+[v,ind] = gsort(c);
+assert_checkequal(ref_ind, ind);
+assert_checkequal(ref_values, v);
+
+[v1,ind1] = gsort(abs(c));
+[v2,ind2] = gsort(c);
+assert_checkequal(ind1, ind2);
+
+A = [18 21 10 7 5];
+B = [1  3  22 8 4];
+y = complex(A,B);
+[a,b] = gsort(y);
+assert_checkequal(b, [3 2 1 4 5]);
+assert_checkequal(y(b), a);
+
+refMsg = msprintf(_("%s: Argument #%d: Must be in the set {%s}.\n"), "gsort", 2, "''g'',''r'',''c'',''lc'',''lr''");
+assert_checkerror("[a,b] = %s_gsort(y,''l'')", refMsg);
+
+ierr = execstr("[a,b] = %s_gsort(y,''g'');","errcatch");
+assert_checkequal(ierr, 0);
+
+ierr = execstr("[a,b] = %s_gsort(y,''r'');","errcatch");
+assert_checkequal(ierr, 0);
+
+ierr = execstr("[a,b] = %s_gsort(y,''c'');","errcatch");
+assert_checkequal(ierr, 0);
+
+ierr = execstr("[a,b] = %s_gsort(y,''lc'');","errcatch");
+assert_checkequal(ierr, 0);
+
+ierr = execstr("[a,b] = %s_gsort(y,''lr'');","errcatch");
+assert_checkequal(ierr, 0);
+
+// -------------------------------------------------------------------
+// Error messages
+// -------------------------------------------------------------------
+msg = msprintf(_("%s: Argument #%d: Must be in the set {%s}.\n"), "gsort", 2, "''g'',''r'',''c'',''lc'',''lr''");
+assert_checkerror("%s_gsort(%i,''q'')", msg);
+msg = msprintf(_("%s: Argument #%d: Text(s) expected.\n"), "gsort", 3);
+assert_checkerror("%s_gsort(%i,''g'',1)", msg);
+
+msg = msprintf(_("%s: Argument #%d: Must be in the set {%s}.\n"), "gsort", 3, "''i'',''d''");
+assert_checkerror("%s_gsort(%i,''g'',''a'')", msg);
+msg = "gsort: Argument #4: List expected.";
+assert_checkerror("%s_gsort(%i,''g'',''i'', 1)", msg);
+msg = "gsort: Arguments #3 and #4: Same numbers of elements expected.";
+assert_checkerror("%s_gsort(%i,''g'',''i'', list())", msg);
+assert_checkerror("%s_gsort(%i,''g'',''i'', list(real, imag))", msg);
+msg = "gsort: Arguments #3 and #4: Same numbers of elements expected.";
+assert_checkerror("%s_gsort(%i,''g'',''i'', list())", msg);
+msg = "gsort: Argument #4: List of functions identifiers expected.";
+assert_checkerror("%s_gsort(%i,''g'',''i'', list(1))", msg);
+
+// ===================================================================
+//              Other tests with DENSE matrices of COMPLEX numbers
+// ===================================================================
+function r = getBuiltinName(b)
+    select b
+    case real
+        r = "real"
+    case imag
+        r = "imag"
+    case abs
+        r = "abs"
+    case atan
+        r = "atan"
+    else
+        r = "unknown"
+    end
+endfunction
+
+function r = getDecimalData(C, crit)
+    if crit==atan
+        r = atan(imag(C), real(C))
+    else
+        r = crit(C)
+    end
+endfunction
+function checkComplexOrderVec(Vs1, Vs2, Vks, ord2)
+    for j = 2:length(Vs1)
+        mprintf("%d ",j);
+        if Vs1(j)==Vs1(j-1)
+            if ord2=="i"
+                assert_checktrue(Vs2(j)>=Vs2(j-1));
+            else
+                assert_checktrue(Vs2(j)<=Vs2(j-1));
+            end
+            if Vs2(j)==Vs2(j-1) // => check initial order preserved
+                assert_checktrue(Vks(j)>Vks(j-1));
+            end
+        end
+    end
+endfunction
+// -------------------------------------------------------------------
+function checkComplexOrder(C, Cs, ks, method, order, crits)
+    ord1 = order(1);
+    Cs1 = getDecimalData(Cs, crits(1));
+    // Checking the order according to the first criteria:
+    //   If the Cs order is correct, its first criteria part should have the
+    //   same order than the sorted C (necessary but not sufficient condition).
+    //   This should be true for all methods, but only for values: Indices of
+    //   equal first part values can be changed by the second criteria
+    // FIRST CRITERION
+    // ---------------
+    C1 = getDecimalData(C, crits(1));
+    [C1ref, k1] = gsort(C1, method, ord1);
+    if and(method~=["lr" "lc"]) | (size(order,"*")==1 | size(crits)<2) then
+        assert_checkalmostequal(Cs1, C1ref);
+    end
+    // SINGLE CRITERIA
+    // ---------------
+    if size(order,"*")==1 | size(crits)<2
+        // then we can compare directly k1 and ks: they must be equal
+        assert_checkequal(ks, k1);
+        // We assume that gsort() works correctly with reals.
+        // So we do not check here the actual order of Cs1 values and the
+        // correctness of ks indices.
+        // These checking should be done by tests with reals.
+        mprintf("\n");
+        return
+    end
+    // SECOND CRITERIA
+    // ---------------
+    ord2 = order(2);
+    if or(method==["g" "r" "c"]) then
+        Cs2 = getDecimalData(Cs, crits(2));
+        if method=="g"
+            checkComplexOrderVec(Cs1, Cs2, ks, ord2);
+        elseif method=="r"
+            for col = 1:size(C,2)
+                checkComplexOrderVec(Cs1(:,col), Cs2(:,col), ks(:,col), ord2);
+            end
+        elseif method=="c"
+            for row = 1:size(C,1)
+                checkComplexOrderVec(Cs1(row,:), Cs2(row,:), ks(row,:), ord2);
+            end
+        end
+        mprintf("\n");
+    else // lr, lc
+        mprintf("  %s: values unchecked\n", method);
+    end
+endfunction
+
+clc
+[nr, nc] = (6,6);
+r = grand(nr, nc, "uin", -1, 1);
+i = grand(nr, nc, "uin", -1, 1);
+C = r + i*%i;
+sizeC = size(C);
+colNan = ones(C(:,1))*%nan;
+crits = list(real, imag, abs, atan);
+
+// ================
+// SINGLE CRITERION
+// ================
+methods = ["g" "r" "c" "lr" "lc"];
+for m = methods
+    for  sdir = ["i" "d"]
+        for c = crits
+            mprintf("%s  %s  %s", m, sdir, getBuiltinName(c));
+            [sC, k]  = %s_gsort(C, m, sdir, list(c));
+            checkComplexOrder(C, sC, k, m, sdir, list(c));
+        end
+    end
+end
+// -------------------------------------------------------------------
+// ============
+// TWO CRITERIA
+// ============
+[nr, nc] = (10,3);
+r = grand(nr, nc, "uin",-1,1);
+i = grand(nr, nc, "uin",-1,1);
+C = r+i*%i;
+sizeC = size(C);
+colNan = ones(C(:,1))*%nan;
+
+methods = ["g" "c" "r" "lr" "lc"];
+crits = list(real, imag, abs, atan);
+for m = methods
+    for sdir = ["i" "i" ; "i" "d" ; "d" "i" ; "d" "d"]'
+        for c1 = crits
+            for c2 = crits
+                if c1 == c2
+                    continue
+                end
+                crit = list(c1, c2);
+                mprintf("%s  %s  %s  %s : ", m, strcat(sdir), ..
+                getBuiltinName(c1), getBuiltinName(c2));
+                [sC, k]  = %s_gsort(C, m, sdir, crit);
+                // Check values
+                checkComplexOrder(C, sC, k, m, sdir, crit);
+                // Check indices:
+                if m=="g"
+                    assert_checkequal(sC, matrix(C(k),sizeC));
+                elseif m=="c"
+                    // get linearized indices:
+                    ak = (1:nr)'*ones(1,nc)+(k-1)*nr;
+                    assert_checkequal(sC, matrix(C(ak),sizeC));
+                elseif m=="r"
+                    // get linearized indices:
+                    ak = ones(nr,1)*(0:nc-1)*10 + k;
+                    assert_checkequal(sC, matrix(C(ak),sizeC));
+                elseif m=="lc"
+                    assert_checktrue(isrow(k));
+                    assert_checkequal(sC, C(:,k));
+                else // m=="lr"
+                    assert_checktrue(iscolumn(k));
+                    assert_checkequal(sC, C(k,:));
+                end
+            end
+        end
+    end
+end
+
+// -------------------------------------------------------------------
+// Incomplete sorting
+// -------------------------------------------------------------------
+m = complex([7  6  9  2  8  1  0  4  3  2], 0);
+assert_checkequal(%s_gsort(m, "g", "i", list(atan)), m);
+assert_checkequal(%s_gsort(m, "g", "i", list(imag)), m);
+assert_checkequal(%s_gsort(m, "g", ["i" "i"], list(imag, atan)), m);
+assert_checkequal(%s_gsort(m+%i, "g", "d", list(imag)), m+%i);
+
+// -------------------------------------------------------------------
+// Double sorting criteria with Nan values in the secondary criterion
+// -------------------------------------------------------------------
+c = [-1 1 ; -1 0; 0 2; 0 %nan; 0 -1; 0 %inf ; 0 1; 1 %nan ; 1 1; 1 -1];
+c = complex(c(:,1), c(:,2))
+// 1   -1. +    i
+// 2   -1.
+// 3          2.i
+// 4         Nani
+// 5           -i
+// 6         Infi
+// 7            i
+// 8    1. + Nani
+// 9    1. +    i
+// 10   1. -    i
+[v, k] = %s_gsort(c, "g", "i");
+assert_checkequal(k, [2  5  7  1  9  10  3  6  4  8]');
+[v, k] = %s_gsort(c, "g", ["i" "i"], list(real, imag));
+assert_checkequal(k, [2  1  5  7  3  6  4  10  9  8]');
+[v, k] = %s_gsort(c,"g", ["i" "d"], list(real, imag));
+assert_checkequal(k, [1  2  4  6  3  7  5  8  9  10]');
+[v, k] = %s_gsort(c,"g", ["d" "i"], list(real, imag));
+assert_checkequal(k, [10  9  8  5  7  3  6  4  2  1]');
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_numbers.tst b/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_numbers.tst
new file mode 100644 (file)
index 0000000..e472edc
--- /dev/null
@@ -0,0 +1,133 @@
+// ===================================================================
+// 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 -->
+// <-- ENGLISH IMPOSED -->
+//
+//====================================================================
+//         Tests of multilevel gsort() for decimal numbers
+//====================================================================
+/*
+We sort numbers,
+ - first: by integer part, with int()
+ - second: by fractional part, with a custom function.
+*/
+function r = get_frac(d)
+    r = d - int(d)
+endfunction
+crit = list(int, get_frac);
+
+// Initial data
+// ------------
+d = [
+   2.3   1.5   1.7   2.1   2.3   2.6   1.9   2.6
+   0.    2.8   2.1   0.8   1.8   2.9   1.6   1. 
+   1.9   1.5   0.3   0.4   2.3   2.7   0.    0.8
+   2.6   1.8   2.3   0.2   0.8   1.    1.6   2.9
+   2.5   1.8   2.3   0.5   1.4   1.9   2.3   1.3
+   1.5   1.5   2.1   2.9   0.4   2.7   1.    0.2
+  ];
+
+// "g" multilevel sorting
+// ----------------------
+[r, k] = %gsort_multilevel(d, "g", ["i" "d"], crit);
+ref = [
+   0.8   0.3   1.9   1.6   1.4   2.9   2.6   2.3
+   0.8   0.2   1.9   1.6   1.3   2.9   2.6   2.3
+   0.8   0.2   1.8   1.5   1.    2.8   2.5   2.3
+   0.5   0.    1.8   1.5   1.    2.7   2.3   2.1
+   0.4   0.    1.8   1.5   1.    2.7   2.3   2.1
+   0.4   1.9   1.7   1.5   2.9   2.6   2.3   2.1
+  ];
+kref = [
+  20  15  35  38  29  32  31  25
+  28  22  37  40  47  46  43  27
+  45  48  10   6  34   8   5  41
+  23   2  11   7  42  33   1  14
+  21  39  26   9  44  36  16  18
+  30   3  13  12  24   4  17  19
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// "r" and "c" multilevel sorting
+// ------------------------------
+[r, k] = %gsort_multilevel(d, "c", ["i" "d"], crit);
+ref = [
+   1.9   1.7   1.5   2.6   2.6   2.3   2.3   2.1
+   0.8   0.    1.8   1.6   1.    2.9   2.8   2.1
+   0.8   0.4   0.3   0.    1.9   1.5   2.7   2.3
+   0.8   0.2   1.8   1.6   1.    2.9   2.6   2.3
+   0.5   1.9   1.8   1.4   1.3   2.5   2.3   2.3
+   0.4   0.2   1.5   1.5   1.    2.9   2.7   2.1
+  ];
+kref = [
+  7  3  2  6  8  1  5  4
+  4  1  5  7  8  6  2  3
+  8  4  3  7  1  2  6  5
+  5  4  2  7  6  8  1  3
+  4  6  2  5  8  1  3  7
+  5  8  1  2  7  4  6  3
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(d, "r", ["d" "i"], crit);
+ref = [
+   2.3   2.8   2.1   2.1   2.3   2.6   2.3   2.6
+   2.5   1.5   2.1   2.9   2.3   2.7   1.    2.9
+   2.6   1.5   2.3   0.2   1.4   2.7   1.6   1. 
+   1.5   1.5   2.3   0.4   1.8   2.9   1.6   1.3
+   1.9   1.8   1.7   0.5   0.4   1.    1.9   0.2
+   0.    1.8   0.3   0.8   0.8   1.9   0.    0.8
+  ];
+kref = [
+  1  2  2  1  1  1  5  1
+  5  1  6  6  3  3  6  4
+  4  3  4  4  5  6  2  2
+  6  6  5  3  2  2  4  5
+  3  4  1  5  6  4  1  6
+  2  5  3  2  4  5  3  3
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// Lexicographic multilevel sorting
+// --------------------------------
+d = [
+   0.1   0.1   1.1   0.1   0.1   1.    0.1   0. 
+   1.    1.    1.1   0.    1.    1.1   0.    1. 
+   0.1   0.1   0.1   0.    1.1   0.1   0.    0. 
+   0.    0.    0.1   1.    1.    1.    1.    0.1
+   1.1   1.    1.1   0.1   1.    1.1   0.1   0.1
+   1.1   0.1   0.1   0.1   1.    0.1   0.    0. 
+    ];
+[r, k] = %gsort_multilevel(d, "lr", ["i" "d"], crit);
+ref = [
+   0.1   0.1   0.1   0.    1.1   0.1   0.    0. 
+   0.1   0.1   1.1   0.1   0.1   1.    0.1   0. 
+   0.    0.    0.1   1.    1.    1.    1.    0.1
+   1.1   0.1   0.1   0.1   1.    0.1   0.    0. 
+   1.1   1.    1.1   0.1   1.    1.1   0.1   0.1
+   1.    1.    1.1   0.    1.    1.1   0.    1. 
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k', [3  1  4  6  5  2]);
+
+//
+[r, k] = %gsort_multilevel(d, "lc", ["d" "i"], crit);
+ref = [
+   1.    1.1   0.    0.1   0.1   0.1   0.1   0.1
+   1.1   1.1   1.    1.    1.    1.    0.    0. 
+   0.1   0.1   0.    1.1   0.1   0.1   0.    0. 
+   1.    0.1   0.1   1.    0.    0.    1.    1. 
+   1.1   1.1   0.1   1.    1.    1.1   0.1   0.1
+   0.1   0.1   0.    1.    0.1   1.1   0.    0.1
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, [6  3  8  5  2  1  7  4]);
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_polynomials.tst b/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_polynomials.tst
new file mode 100644 (file)
index 0000000..b334391
--- /dev/null
@@ -0,0 +1,343 @@
+// ===================================================================
+// 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 -->
+// <-- ENGLISH IMPOSED -->
+//
+//====================================================================
+//          Tests of multilevel gsort() for polynomials
+//====================================================================
+/*
+We sort polynomials,
+ - first: by degree, with degree()
+ - second: by highest coefficient, by a custom function.
+*/
+function c = get_degreeI(p,i)
+    tmp = coeff(p(:))
+    [nl,nc] = size(tmp)
+    if i <> %inf then
+        tmp = tmp(:,i+1)
+    else
+        tmp = tmp'((0:nl-1)'*nc + max(0,degree(p(:)))+1) // highest coeff
+    end
+    c = matrix(tmp, size(p))
+endfunction
+crit = list(degree, list(get_degreeI, %inf));
+
+// Initial array
+// -------------
+x = poly(0,"x");
+p = [
+  "[2*x,1+2*x+x^2,1+2*x+2*x^2,2+x,2*x+x^2,0*x;"
+  "2+x^2,2*x+x^2,0,2*x^2,1+x+2*x^2,2*x+2*x^2;"
+  "1+2*x^2,x+x^2,2*x^2,1+2*x,2+2*x,2+2*x+x^2;"
+  "2*x+x^2,x,1+x+x^2,2*x,x+x^2,x+2*x^2;"
+  "1+2*x+x^2,2+x+x^2,1+2*x+x^2,2*x+2*x^2,2,2+x+2*x^2;"
+  "x,2*x,2+2*x+x^2,2+2*x+x^2,1,2+x];"
+ ];
+p = evstr(p);
+/*
+  2x         1 +2x +x²  1 +2x +2x²  2 +x       2x +x²     0
+  2 +x²      2x +x²     0           2x²        1 +x +2x²  2x +2x²
+  1 +2x²     x +x²      2x²         1 +2x      2 +2x      2 +2x +x²
+  2x +x²     x          1 +x +x²    2x         x +x²      x +2x²
+  1 +2x +x²  2 +x +x²   1 +2x +x²   2x +2x²    2          2 +x +2x²
+  x          2x         2 +2x +x²   2 +2x +x²  1          2 +x
+*/
+
+// "g" multilevel sorting
+// ----------------------
+[r, k] = %gsort_multilevel(p, "g", ["i" "i"], crit);
+ref = [
+  "[0*x,2+x,2+2*x,x+x^2,2*x+x^2,2*x^2;"
+  "0*x,2+x,2+x^2,2+x+x^2,x+x^2,2*x+2*x^2;"
+  "1,2*x,2*x+x^2,1+x+x^2,2+2*x+x^2,1+x+2*x^2;"
+  "2,2*x,1+2*x+x^2,1+2*x+x^2,1+2*x^2,2*x+2*x^2;"
+  "x,1+2*x,1+2*x+x^2,2+2*x+x^2,1+2*x+2*x^2,x+2*x^2;"
+  "x,2*x,2*x+x^2,2+2*x+x^2,2*x^2,2+x+2*x^2]"
+  ];
+ref = evstr(ref);
+/*
+  0  2 +x   2 +2x      x +x²      2x +x²      2x²
+  0  2 +x   2 +x²      2 +x +x²   x +x²       2x +2x²
+  1  2x     2x +x²     1 +x +x²   2 +2x +x²   1 +x +2x²
+  2  2x     1 +2x +x²  1 +2x +x²  1 +2x²      2x +2x²
+  x  1 +2x  1 +2x +x²  2 +2x +x²  1 +2x +2x²  x +2x²
+  x  2x     2x +x²     2 +2x +x²  2x²         2 +x +2x²
+*/
+kref = [
+  14  19  27   9  25  20
+  31  36   2  11  28  23
+  30   1   4  16  33  26
+  29  12   5  17   3  32
+   6  21   7  18  13  34
+  10  22   8  24  15  35
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(p, "g", ["i" "d"], crit);
+ref = [
+  "[0*x,1+2*x,2+x,1+x+2*x^2,1+2*x+x^2,1+2*x+x^2;"
+  "0*x,2*x,1+2*x^2,2*x+2*x^2,1+2*x+x^2,2+2*x+x^2;"
+  "2,2+2*x,1+2*x+2*x^2,x+2*x^2,2*x+x^2,2+2*x+x^2;"
+  "1,x,2*x^2,2+x+2*x^2,x+x^2,2*x+x^2;"
+  "2*x,x,2*x^2,2+x^2,2+x+x^2,x+x^2;"
+  "2*x,2+x,2*x+2*x^2,2*x+x^2,1+x+x^2,2+2*x+x^2]"
+  ];
+ref = evstr(ref);
+/*
+  0   1 +2x  2 +x        1 +x +2x²  1 +2x +x²  1 +2x +x²
+  0   2x     1 +2x²      2x +2x²    1 +2x +x²  2 +2x +x²
+  2   2 +2x  1 +2x +2x²  x +2x²     2x +x²     2 +2x +x²
+  1   x      2x²         2 +x +2x²  x +x²      2x +x²
+  2x  x      2x²         2 +x²      2 +x +x²   x +x²
+  2x  2 +x   2x +2x²     2x +x²     1 +x +x²   2 +2x +x²
+*/
+kref = [
+  14  21  36  26   5  17
+  31  22   3  32   7  18
+  29  27  13  34   8  24
+  30   6  15  35   9  25
+   1  10  20   2  11  28
+  12  19  23   4  16  33
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// "r" and "c" multilevel sorting
+// ------------------------------
+[r, k] = %gsort_multilevel(p, "c", ["i" "i"], crit);
+ref = [
+  "[0*x,2+x,2*x,1+2*x+x^2,2*x+x^2,1+2*x+2*x^2;"
+  "0*x,2+x^2,2*x+x^2,2*x^2,1+x+2*x^2,2*x+2*x^2;"
+  "1+2*x,2+2*x,x+x^2,2+2*x+x^2,1+2*x^2,2*x^2;"
+  "x,2*x,2*x+x^2,1+x+x^2,x+x^2,x+2*x^2;"
+  "2,1+2*x+x^2,2+x+x^2,1+2*x+x^2,2*x+2*x^2,2+x+2*x^2;"
+  "1,x,2+x,2*x,2+2*x+x^2,2+2*x+x^2]"
+  ];
+ref = evstr(ref);
+/*
+  0      2 +x       2x        1 +2x +x²  2x +x²     1 +2x +2x²
+  0      2 +x²      2x +x²    2x²        1 +x +2x²  2x +2x²
+  1 +2x  2 +2x      x +x²     2 +2x +x²  1 +2x²     2x²
+  x      2x         2x +x²    1 +x +x²   x +x²      x +2x²
+  2      1 +2x +x²  2 +x +x²  1 +2x +x²  2x +2x²    2 +x +2x²
+  1      x          2 +x      2x         2 +2x +x²  2 +2x +x²
+*/
+kref = [
+  6  4  1  2  5  3
+  3  1  2  4  5  6
+  4  5  2  6  1  3
+  2  4  1  3  5  6
+  5  1  2  3  4  6
+  5  1  6  2  3  4
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(p, "c", ["d" "i"], crit);
+ref = [
+  "[1+2*x+x^2,2*x+x^2,1+2*x+2*x^2,2+x,2*x,0*x;"
+  "2+x^2,2*x+x^2,2*x^2,1+x+2*x^2,2*x+2*x^2,0*x;"
+  "x+x^2,2+2*x+x^2,1+2*x^2,2*x^2,1+2*x,2+2*x;"
+  "2*x+x^2,1+x+x^2,x+x^2,x+2*x^2,x,2*x;"
+  "1+2*x+x^2,2+x+x^2,1+2*x+x^2,2*x+2*x^2,2+x+2*x^2,2;"
+  "2+2*x+x^2,2+2*x+x^2,x,2+x,2*x,1]"
+  ];
+ref = evstr(ref);
+/*
+  1 +2x +x²  2x +x²     1 +2x +2x²  2 +x       2x         0
+  2 +x²      2x +x²     2x²         1 +x +2x²  2x +2x²    0
+  x +x²      2 +2x +x²  1 +2x²      2x²        1 +2x      2 +2x
+  2x +x²     1 +x +x²   x +x²       x +2x²     x          2x
+  1 +2x +x²  2 +x +x²   1 +2x +x²   2x +2x²    2 +x +2x²  2
+  2 +2x +x²  2 +2x +x²  x           2 +x       2x         1
+*/
+kref = [
+  2  5  3  4  1  6
+  1  2  4  5  6  3
+  2  6  1  3  4  5
+  1  3  5  6  2  4
+  1  2  3  4  6  5
+  3  4  1  6  2  5
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(p, "r", ["i" "i"], crit);
+ref = [
+  "[x,x,0*x,2+x,1,0*x;"
+  "2*x,2*x,1+x+x^2,1+2*x,2,2+x;"
+  "2+x^2,1+2*x+x^2,1+2*x+x^2,2*x,2+2*x,2+2*x+x^2;"
+  "2*x+x^2,2*x+x^2,2+2*x+x^2,2+2*x+x^2,2*x+x^2,2*x+2*x^2;"
+  "1+2*x+x^2,x+x^2,1+2*x+2*x^2,2*x^2,x+x^2,x+2*x^2;"
+  "1+2*x^2,2+x+x^2,2*x^2,2*x+2*x^2,1+x+2*x^2,2+x+2*x^2]"
+  ];
+ref = evstr(ref);
+/*
+  x          x          0           2 +x       1          0
+  2x         2x         1 +x +x²    1 +2x      2          2 +x
+  2 +x²      1 +2x +x²  1 +2x +x²   2x         2 +2x      2 +2x +x²
+  2x +x²     2x +x²     2 +2x +x²   2 +2x +x²  2x +x²     2x +2x²
+  1 +2x +x²  x +x²      1 +2x +2x²  2x²        x +x²      x +2x²
+  1 +2x²     2 +x +x²   2x²         2x +2x²    1 +x +2x²  2 +x +2x²
+*/
+kref = [
+  6  4  2  1  6  1
+  1  6  4  3  5  6
+  2  1  5  4  3  3
+  4  2  6  6  1  2
+  5  3  1  2  4  4
+  3  5  3  5  2  5
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(p, "r", ["d" "i"], crit);
+ref = [
+  "[2+x^2,1+2*x+x^2,1+x+x^2,2+2*x+x^2,2*x+x^2,2+2*x+x^2;"
+  "2*x+x^2,2*x+x^2,1+2*x+x^2,2*x^2,x+x^2,2*x+2*x^2;"
+  "1+2*x+x^2,x+x^2,2+2*x+x^2,2*x+2*x^2,1+x+2*x^2,x+2*x^2;"
+  "1+2*x^2,2+x+x^2,1+2*x+2*x^2,2+x,2+2*x,2+x+2*x^2;"
+  "x,x,2*x^2,1+2*x,1,2+x;"
+  "2*x,2*x,0*x,2*x,2,0*x]"
+  ];
+ref = evstr(ref);
+/*
+  2 +x²      1 +2x +x²  1 +x +x²    2 +2x +x²  2x +x²     2 +2x +x²
+  2x +x²     2x +x²     1 +2x +x²   2x²        x +x²      2x +2x²
+  1 +2x +x²  x +x²      2 +2x +x²   2x +2x²    1 +x +2x²  x +2x²
+  1 +2x²     2 +x +x²   1 +2x +2x²  2 +x       2 +2x      2 +x +2x²
+  x          x          2x²         1 +2x      1          2 +x
+  2x         2x         0           2x         2          0
+*/
+kref = [
+  2  1  4  6  1  3
+  4  2  5  2  4  2
+  5  3  6  5  2  4
+  3  5  1  1  3  5
+  6  4  3  3  6  6
+  1  6  2  4  5  1
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// Lexicographic multilevel sorting
+// --------------------------------
+p = [
+  "[2+2*x,2+2*x,2+x,1+x,1+2*x,1+2*x;"
+  "0*x,x,2*x,2,2+x,1+x;"
+  "2+2*x,1+2*x,x,1,0*x,2+x;"
+  "2,1+2*x,1+2*x,x,x,1+2*x;"
+  "1,2,1+x,2,1,0*x;"
+  "1+x,2*x,1,1,2+2*x,x;"
+  "2+x,0*x,2+x,0*x,2*x,x]"
+  ];
+p = evstr(p);
+/*
+  2 +2x  2 +2x  2 +x   1 +x  1 +2x  1 +2x
+  0      x      2x     2     2 +x   1 +x
+  2 +2x  1 +2x  x      1     0      2 +x
+  2      1 +2x  1 +2x  x     x      1 +2x
+  1      2      1 +x   2     1      0
+  1 +x   2x     1      1     2 +2x  x
+  2 +x   0      2 +x   0     2x     x
+*/
+[r, k] = %gsort_multilevel(p, "lr", ["i" "i"], crit);
+ref = [
+  "[0*x,x,2*x,2,2+x,1+x;"
+  "1,2,1+x,2,1,0*x;"
+  "2,1+2*x,1+2*x,x,x,1+2*x;"
+  "2+x,0*x,2+x,0*x,2*x,x;"
+  "1+x,2*x,1,1,2+2*x,x;"
+  "2+2*x,1+2*x,x,1,0*x,2+x;"
+  "2+2*x,2+2*x,2+x,1+x,1+2*x,1+2*x]"
+  ];
+ref = evstr(ref);
+/*
+  0      x      2x     2     2 +x   1 +x
+  1      2      1 +x   2     1      0
+  2      1 +2x  1 +2x  x     x      1 +2x
+  2 +x   0      2 +x   0     2x     x
+  1 +x   2x     1      1     2 +2x  x
+  2 +2x  1 +2x  x      1     0      2 +x
+  2 +2x  2 +2x  2 +x   1 +x  1 +2x  1 +2x
+*/
+assert_checkequal(r, ref);
+assert_checkequal(k', [2  5  4  7  6  3  1]);
+
+//
+[r, k] = %gsort_multilevel(p, "lr", ["d" "i"], crit);
+ref = [
+  "[1+x,2*x,1,1,2+2*x,x;"
+  "2+x,0*x,2+x,0*x,2*x,x;"
+  "2+2*x,2+2*x,2+x,1+x,1+2*x,1+2*x;"
+  "2+2*x,1+2*x,x,1,0*x,2+x;"
+  "1,2,1+x,2,1,0*x;"
+  "2,1+2*x,1+2*x,x,x,1+2*x;"
+  "0*x,x,2*x,2,2+x,1+x]"
+  ];
+ref = evstr(ref);
+/*
+  1 +x   2x     1      1     2 +2x  x
+  2 +x   0      2 +x   0     2x     x
+  2 +2x  2 +2x  2 +x   1 +x  1 +2x  1 +2x
+  2 +2x  1 +2x  x      1     0      2 +x
+  1      2      1 +x   2     1      0
+  2      1 +2x  1 +2x  x     x      1 +2x
+  0      x      2x     2     2 +x   1 +x
+*/
+assert_checkequal(r, ref);
+assert_checkequal(k', [6  7  1  3  5  4  2]);
+//
+[r, k] = %gsort_multilevel(p, "lc", ["i" "i"], crit);
+ref = [
+  "[1+x,2+x,2+2*x,1+2*x,1+2*x,2+2*x;"
+  "2,2*x,0*x,2+x,1+x,x;"
+  "1,x,2+2*x,0*x,2+x,1+2*x;"
+  "x,1+2*x,2,x,1+2*x,1+2*x;"
+  "2,1+x,1,1,0*x,2;"
+  "1,1,1+x,2+2*x,x,2*x;"
+  "0*x,2+x,2+x,2*x,x,0*x]"
+  ];
+ref = evstr(ref);
+/*
+  1 +x  2 +x   2 +2x  1 +2x  1 +2x  2 +2x
+  2     2x     0      2 +x   1 +x   x
+  1     x      2 +2x  0      2 +x   1 +2x
+  x     1 +2x  2      x      1 +2x  1 +2x
+  2     1 +x   1      1      0      2
+  1     1      1 +x   2 +2x  x      2x
+  0     2 +x   2 +x   2x     x      0
+*/
+assert_checkequal(r, ref);
+assert_checkequal(k, [4  3  1  5  6  2]);
+//
+[r, k] = %gsort_multilevel(p, "lc", ["d" "i"], crit);
+ref = [
+  "[2+x,1+x,1+2*x,2+2*x,1+2*x,2+2*x;"
+  "2*x,2,1+x,x,2+x,0*x;"
+  "x,1,2+x,1+2*x,0*x,2+2*x;"
+  "1+2*x,x,1+2*x,1+2*x,x,2;"
+  "1+x,2,0*x,2,1,1;"
+  "1,1,x,2*x,2+2*x,1+x;"
+  "2+x,0*x,x,0*x,2*x,2+x]"
+  ];
+ref = evstr(ref);
+/*
+  2 +x   1 +x  1 +2x  2 +2x  1 +2x  2 +2x
+  2x     2     1 +x   x      2 +x   0
+  x      1     2 +x   1 +2x  0      2 +2x
+  1 +2x  x     1 +2x  1 +2x  x      2
+  1 +x   2     0      2      1      1
+  1      1     x      2x     2 +2x  1 +x
+  2 +x   0     x      0      2x     2 +x
+*/
+assert_checkequal(r, ref);
+assert_checkequal(k, [3  4  6  2  5  1]);
diff --git a/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_text.tst b/scilab/modules/elementary_functions/tests/unit_tests/gsort_multilevel_text.tst
new file mode 100644 (file)
index 0000000..d233a64
--- /dev/null
@@ -0,0 +1,216 @@
+// ===================================================================
+// 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 -->
+// <-- ENGLISH IMPOSED -->
+//
+//====================================================================
+//             Tests of multilevel gsort() for texts
+//====================================================================
+
+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"
+  ];
+
+// "g" multilevel sorting
+// ----------------------
+[r, k] = %gsort_multilevel(t, "g", ["i" "i"], list(length,:));
+ref = [
+  "a"  "b"   "ab"  "bb"  "cc"   "acb"  "cba"   "bbca"
+  "a"  "b"   "ab"  "bb"  "cc"   "acb"  "cbb"   "bbca"
+  "a"  "b"   "ac"  "bc"  "aab"  "bba"  "cbb"   "bccc"
+  "b"  "c"   "ac"  "ca"  "aab"  "bba"  "aaaa"  "caaa"
+  "b"  "c"   "ac"  "ca"  "aba"  "bca"  "abbb"  "cabb"
+  "b"  "aa"  "ba"  "cc"  "aba"  "cac"  "abbb"  "ccbc"
+  ];
+kref = [
+  18  38  13  20  12  35   6  19
+  22  44  30  27  36  41   5  21
+  26  47   2  33  28   8  16  23
+  11   4   9   7  37  42   3  48
+  15  46  40  45  14  43  24  17
+  25  39  10   1  29  32  34  31
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(t, "g", ["i" "d"], list(length,:));
+ref = [
+  "c"  "b"   "cc"  "bb"  "ab"   "bca"  "aba"   "bccc"
+  "c"  "b"   "cc"  "ba"  "aa"   "bba"  "aab"   "bbca"
+  "b"  "a"   "ca"  "ac"  "cbb"  "bba"  "aab"   "bbca"
+  "b"  "a"   "ca"  "ac"  "cbb"  "acb"  "ccbc"  "abbb"
+  "b"  "a"   "bc"  "ac"  "cba"  "acb"  "cabb"  "abbb"
+  "b"  "cc"  "bb"  "ab"  "cac"  "aba"  "caaa"  "aaaa"
+  ];
+kref = [
+   4  44  12  27  30  43  29  23
+  46  47  36  10  39   8  28  19
+  11  18   7   2   5  42  37  21
+  15  22  45   9  16  35  31  24
+  25  26  33  40   6  41  17  34
+  38   1  20  13  32  14  48   3
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// "r" and "c" multilevel sorting
+// ------------------------------
+[r, k] = %gsort_multilevel(t, "c", ["i" "i"], list(length,:));
+ref = [
+  "b"  "ab"  "ca"   "cc"   "aab"  "bca"  "bbca"  "ccbc"
+  "a"  "b"   "b"    "ac"   "bb"   "aba"  "bba"   "cac" 
+  "b"  "aa"  "ac"   "bb"   "bc"   "ca"   "aaaa"  "bbca"
+  "a"  "c"   "c"    "ac"   "ba"   "aab"  "cbb"   "abbb"
+  "b"  "b"   "aba"  "acb"  "acb"  "cbb"  "bccc"  "cabb"
+  "a"  "ab"  "cc"   "cc"   "bba"  "cba"  "abbb"  "caaa"
+  ];
+kref = [
+  5  3  2  1  7  8  4  6
+  5  7  8  1  4  3  2  6
+  3  7  2  5  6  8  1  4
+  4  1  8  7  2  5  3  6
+  2  8  5  6  7  1  4  3
+  3  5  2  6  7  1  4  8
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(t, "c", ["d" "i"], list(length,:));
+ref = [
+  "bbca"  "ccbc"  "aab"  "bca"  "ab"   "ca"   "cc"  "b"
+  "aba"   "bba"   "cac"  "ac"   "bb"   "a"    "b"   "b"
+  "aaaa"  "bbca"  "aa"   "ac"   "bb"   "bc"   "ca"  "b"
+  "abbb"  "aab"   "cbb"  "ac"   "ba"   "a"    "c"   "c"
+  "bccc"  "cabb"  "aba"  "acb"  "acb"  "cbb"  "b"   "b"
+  "abbb"  "caaa"  "bba"  "cba"  "ab"   "cc"   "cc"  "a"
+  ];
+kref = [
+  4  6  7  8  3  2  1  5
+  3  2  6  1  4  5  7  8
+  1  4  7  2  5  6  8  3
+  6  5  3  7  2  4  1  8
+  4  3  5  6  7  1  2  8
+  4  8  7  1  5  2  6  3
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(t, "r", ["i" "i"], list(length,:));
+ref = [
+  "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"
+  ];
+kref = [
+  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
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+//
+[r, k] = %gsort_multilevel(t, "r", ["d" "i"], list(length,:));
+ref = [
+  "aaaa"  "bba"  "cabb"  "abbb"  "aab"  "abbb"  "aab"  "caaa"
+  "cba"   "ac"   "aba"   "bbca"  "aba"  "ccbc"  "acb"  "bca" 
+  "cbb"   "ba"   "cbb"   "bbca"  "ab"   "acb"   "bba"  "ca"  
+  "ac"    "ca"   "ab"    "bccc"  "bb"   "cac"   "aa"   "b"   
+  "cc"    "cc"   "a"     "bb"    "a"    "bc"    "ac"   "b"   
+  "c"     "b"    "b"     "a"     "b"    "cc"    "b"    "c"   
+  ];
+kref = [
+  3  2  5  6  4  4  1  6
+  6  3  2  1  5  1  5  1
+  5  4  4  3  6  5  6  3
+  2  1  1  5  3  2  3  2
+  1  6  6  2  2  3  4  5
+  4  5  3  4  1  6  2  4
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, kref);
+
+// Lexicographic multilevel sorting
+// --------------------------------
+t = [
+  "aa"  "bb"  "b"   "aa"  "b"   "b"   "bb"  "bb"
+  "b"   "b"   "b"   "aa"  "a"   "a"   "ab"  "a" 
+  "bb"  "b"   "bb"  "b"   "a"   "b"   "ba"  "b" 
+  "b"   "b"   "ba"  "a"   "b"   "b"   "ba"  "bb"
+  "ba"  "aa"  "ba"  "ba"  "ba"  "ab"  "a"   "aa"
+  "b"   "a"   "bb"  "a"   "aa"  "b"   "ab"  "b" 
+  "b"   "ab"  "aa"  "ba"  "ab"  "b"   "a"   "ba"
+  "b"   "aa"  "bb"  "aa"  "bb"  "a"   "bb"  "a" 
+    ];
+[r, k] = %gsort_multilevel(t, "lr", ["i" "i"], list(length,:));
+ref = [
+  "b"   "a"   "bb"  "a"   "aa"  "b"   "ab"  "b" 
+  "b"   "b"   "b"   "aa"  "a"   "a"   "ab"  "a" 
+  "b"   "b"   "ba"  "a"   "b"   "b"   "ba"  "bb"
+  "b"   "aa"  "bb"  "aa"  "bb"  "a"   "bb"  "a" 
+  "b"   "ab"  "aa"  "ba"  "ab"  "b"   "a"   "ba"
+  "aa"  "bb"  "b"   "aa"  "b"   "b"   "bb"  "bb"
+  "ba"  "aa"  "ba"  "ba"  "ba"  "ab"  "a"   "aa"
+  "bb"  "b"   "bb"  "b"   "a"   "b"   "ba"  "b" 
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k', [6  2  4  8  7  1  5  3]);
+
+//
+[r, k] = %gsort_multilevel(t, "lr", ["d" "i"], list(length,:));
+ref = [
+  "aa"  "bb"  "b"   "aa"  "b"   "b"   "bb"  "bb"
+  "ba"  "aa"  "ba"  "ba"  "ba"  "ab"  "a"   "aa"
+  "bb"  "b"   "bb"  "b"   "a"   "b"   "ba"  "b" 
+  "b"   "aa"  "bb"  "aa"  "bb"  "a"   "bb"  "a" 
+  "b"   "ab"  "aa"  "ba"  "ab"  "b"   "a"   "ba"
+  "b"   "a"   "bb"  "a"   "aa"  "b"   "ab"  "b" 
+  "b"   "b"   "ba"  "a"   "b"   "b"   "ba"  "bb"
+  "b"   "b"   "b"   "aa"  "a"   "a"   "ab"  "a" 
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k', [1  5  3  8  7  6  4  2]);
+//
+[r, k] = %gsort_multilevel(t, "lc", ["i" "i"], list(length,:));
+ref = [
+  "b"   "b"   "b"   "aa"  "aa"  "bb"  "bb"  "bb"
+  "a"   "a"   "b"   "b"   "aa"  "a"   "b"   "ab"
+  "a"   "b"   "bb"  "bb"  "b"   "b"   "b"   "ba"
+  "b"   "b"   "ba"  "b"   "a"   "bb"  "b"   "ba"
+  "ba"  "ab"  "ba"  "ba"  "ba"  "aa"  "aa"  "a" 
+  "aa"  "b"   "bb"  "b"   "a"   "b"   "a"   "ab"
+  "ab"  "b"   "aa"  "b"   "ba"  "ba"  "ab"  "a" 
+  "bb"  "a"   "bb"  "b"   "aa"  "a"   "aa"  "bb"
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, [5  6  3  1  4  8  2  7]);
+//
+[r, k] = %gsort_multilevel(t, "lc", ["d" "i"], list(length,:));
+ref = [
+  "aa"  "aa"  "bb"  "bb"  "bb"  "b"   "b"   "b" 
+  "aa"  "b"   "ab"  "a"   "b"   "a"   "a"   "b" 
+  "b"   "bb"  "ba"  "b"   "b"   "a"   "b"   "bb"
+  "a"   "b"   "ba"  "bb"  "b"   "b"   "b"   "ba"
+  "ba"  "ba"  "a"   "aa"  "aa"  "ba"  "ab"  "ba"
+  "a"   "b"   "ab"  "b"   "a"   "aa"  "b"   "bb"
+  "ba"  "b"   "a"   "ba"  "ab"  "ab"  "b"   "aa"
+  "aa"  "b"   "bb"  "a"   "aa"  "bb"  "a"   "bb"
+  ];
+assert_checkequal(r, ref);
+assert_checkequal(k, [4  1  7  8  2  5  6  3]);