* Bugs 16337 16455 fixed: [..,..,ku] = unique(..) implemented 74/21474/5
Samuel GOUGEON [Sat, 30 May 2020 01:25:05 +0000 (03:25 +0200)]
  http://bugzilla.scilab.org/16455 (NR included in unit tests)
  http://bugzilla.scilab.org/16337

  Help page updated (PDF): http://bugzilla.scilab.org/attachment.cgi?id=5149

  This commit supersedes https://codereview.scilab.org/21422

Change-Id: I19a215a45c6b65b715fc2a775548d48a02cf0339

scilab/CHANGES.md
scilab/modules/elementary_functions/help/en_US/setoperations/unique.xml
scilab/modules/elementary_functions/help/fr_FR/setoperations/unique.xml
scilab/modules/elementary_functions/help/ja_JP/setoperations/unique.xml
scilab/modules/elementary_functions/help/pt_BR/setoperations/unique.xml
scilab/modules/elementary_functions/help/ru_RU/setoperations/unique.xml
scilab/modules/elementary_functions/macros/unique.sci
scilab/modules/elementary_functions/tests/unit_tests/unique.tst

index 040adfc..ff36a56 100644 (file)
@@ -269,6 +269,7 @@ Bug Fixes
 * [#9909](https://bugzilla.scilab.org/9909): In the help browser, add a way to open the online version of the current page.
 * [#12889](https://bugzilla.scilab.org/12889): In the help browser, add a menu allowing to select the language of help pages, regardless of the language of the session.
 * [#16106](https://bugzilla.scilab.org/16106): Xcos sciblk4 user-defined blocks did not handle opar and odstate/oz correctly.
+* [#16337](https://bugzilla.scilab.org/16337): The 3rd output of `[U,km,ku] = unique(..)` was not implemented.
 * [#16342](https://bugzilla.scilab.org/16342): `strcat()` was much slower in Scilab 6.0.2.
 * [#16350](https://bugzilla.scilab.org/16350): in if/while conditions, the empty sparse boolean was considered as TRUE.
 * [#16365](https://bugzilla.scilab.org/16365): `median(m,"r")` and `median(m,"c")` yielded wrong results (6.1.0 regression)
index 22c16b7..d6ac46f 100644 (file)
     <refsynopsisdiv>
         <title>Syntax</title>
         <synopsis>
-            [N, km, kn, nb] = unique(M)
-            [N, km, kn, nb] = unique(M, orient)
-            [N, km, kn, nb] = unique(.., "keepOrder")
-            [N, km, kn, nb] = unique(.., "uniqueNan")
+            [U, km, ku, nb] = unique(M)
+            [U, km, ku, nb] = unique(M, orient)
+            [U, km, ku, nb] = unique(.., "keepOrder")
+            [U, km, ku, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -36,7 +36,7 @@
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    vector, matrix, or hypermatrix of numbers or of strings.
+                    vector, matrix, or hypermatrix of booleans, numbers, or text.
                     <para/>
                 </listitem>
             </varlistentry>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>N</term>
+                <term>U</term>
                 <listitem>
                   <itemizedlist>
                     <listitem>
                         If <varname>orient</varname> is not used: Vector of extracted
                         <varname>M</varname> components sorted in ascending order.
-                        If <varname>M</varname> is a row vector, <varname>N</varname> is
+                        If <varname>M</varname> is a row vector, <varname>U</varname> is
                         also a row vector. In all other <varname>M</varname> cases,
-                        <varname>N</varname> is a matrix or a column vector.
+                        <varname>U</varname> is a column vector.
                         <para/>
                     </listitem>
                     <listitem>
@@ -72,8 +72,8 @@
                 <term>km</term>
                 <listitem>
                     Vector of indices of first encountered occurrences, such that
-                    <literal>N(i) = M(km(i))</literal> or <literal>N(i,:) = M(km(i),:)</literal>
-                    or <literal>N(:,i) = M(:,km(i))</literal>.
+                    <literal>U = M(km)</literal> or <literal>U = M(km,:)</literal>
+                    or <literal>U = M(:,km)</literal>.
                     <para/>
                     <varname>km</varname> is a row if <varname>M</varname> is a row or if
                     <literal>orient="c"</literal> is used. Otherwise it's a column.
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>kn</term>
+                <term>ku</term>
                 <listitem>
-                    Not yet implemented.
-                    Vector of indices of first encountered occurrences, such that
-                    <literal>M(i) = N(kn(i))</literal> or <literal>M(i,:) = N(kn(i),:)</literal>
-                    or <literal>M(:,i) = N(:,kn(i))</literal>.
+                    Array of indices in U, such that, according to the <varname>orient</varname> option
+                    <itemizedlist>
+                        <listitem>
+                            "*": <varname>ku</varname> is of size size(M), and <literal>U(ku) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "r": <varname>ku</varname> is of size [size(M,1), 1], and <literal>U(ku,:) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "c": <varname>ku</varname> is of size [1, size(M,2)], and <literal>U(:,ku) = M</literal>
+                        </listitem>
+                    </itemizedlist>
                     <para/>
                 </listitem>
             </varlistentry>
                 <listitem>
                     Vector of integers > 0, with the same <varname>km</varname> shape:
                     Numbers of occurrences in <varname>M</varname> of respective unduplicated
-                    entities (components, rows, columns) returned in <varname>N</varname>.
+                    entities (components, rows, columns) returned in <varname>U</varname>.
                     <para/>
                 </listitem>
             </varlistentry>
             <literal>"uniqueNan"</literal> is used. Specifying
             <literal>"uniqueNan"</literal> is case-insensitive.
         </para>
+        <para>
+            For booleans, <literal>unique(…)</literal> is useful mainly with the "r" or "c" options.
+        </para>
+        <para>
+            <note>
+                Complex numbers are sorted first by increasing magnitudes, then by increasing
+                phases on [-π,π].
+            </note>
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Examples</title>
@@ -176,14 +193,19 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
     <screen><![CDATA[
 --> c = [1+i, 1-i, -i, i, -i, 1+i]
  c  =
-   1. + i     1. - i  -i    i   -i    1. + i
+   1. + i    1. - i    0. - i    0. + i    0. - i    1. + i
 
 --> [u, k] = unique(c)
  u  =
-  -i    i    1. - i   1. + i
-
+   0. - i    0. + i    1. - i    1. + i
  k  =
    3.   4.   2.   1.
+
+--> [uc, kc] = unique(c, "c")
+ uc  =
+   0. - i    0. + i    1. - i    1. + i
+ kc  =
+   3.   4.   2.   1.
 ]]></screen>
         <para/>
         <para>With some texts:</para>
@@ -193,9 +215,10 @@ t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
     ]
 u = unique(t)'
 [u, kt, ku, nb] = unique(t(1,:))
-[u, kt] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[u, kt] = unique(t(1,:), "keepOrder")  // In original order of row#1 elements
 [uc, ktc, kuc, nb] = unique(t, "c")
-[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
+[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // In original order of columns
+[and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
  ]]></programlisting>
     <screen><![CDATA[
 --> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
@@ -247,6 +270,10 @@ u = unique(t)'
 
  nb  =
    2.   1.   1.   3.   2.   1.   3.   1.   1.
+
+--> [and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
+ ans  =
+  T  T
 ]]></screen>
         <para/>
         <para>With Nan (and Inf) values. "uniqueNan" option:</para>
@@ -333,6 +360,9 @@ unique(M, "c")
                 <revdescription>
                     <itemizedlist>
                         <listitem>
+                            Extension to booleans.
+                        </listitem>
+                        <listitem>
                             "keepOrder" and "uniqueNan" options introduced.
                         </listitem>
                         <listitem>
@@ -341,6 +371,12 @@ unique(M, "c")
                     </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    ku 3rd output implemented.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index 4a5ab3f..8c77997 100644 (file)
     <refsynopsisdiv>
         <title>Séquence d'appel</title>
         <synopsis>
-            [N, km, kn, nb] = unique(M)
-            [N, km, kn, nb] = unique(M, orient)
-            [N, km, kn, nb] = unique(.., "keepOrder")
-            [N, km, kn, nb] = unique(.., "uniqueNan")
+            [U, km, ku, nb] = unique(M)
+            [U, km, ku, nb] = unique(M, orient)
+            [U, km, ku, nb] = unique(.., "keepOrder")
+            [U, km, ku, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -38,7 +38,7 @@
                 <term>M</term>
                 <listitem>
                     <para>
-                        vecteur, matrice, ou hypermatrice de nombres ou de textes.
+                        vecteur, matrice, ou hypermatrice de booléens, de nombres, ou de textes.
                     </para>
                 </listitem>
             </varlistentry>
@@ -52,7 +52,7 @@
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>N</term>
+                <term>U</term>
                 <listitem>
                     <para>
                       <itemizedlist>
@@ -60,9 +60,9 @@
                             <para>
                                 Sans <varname>orient</varname>: vecteur d'éléments de
                                 <varname>M</varname> triés par ordre croissant.
-                                Si <varname>M</varname> est un vecteur ligne, <varname>N</varname>
-                                aussi. Dans tous les autres cas, <varname>N</varname> est une
-                                matrice ou en colonne.
+                                Si <varname>M</varname> est un vecteur ligne, <varname>U</varname>
+                                aussi. Dans tous les autres cas, <varname>U</varname> est un
+                                vecteur colonne.
                             </para>
                         </listitem>
                         <listitem>
@@ -78,8 +78,8 @@
                 <listitem>
                     <para>
                       Indices des éléments, lignes ou colonnes extraits, tels que
-                      <literal>N(i) = M(km(i))</literal> ou <literal>N(i,:) = M(km(i),:)</literal>
-                      ou <literal>N(:,i) = M(:,km(i))</literal>.
+                      <literal>U = M(km)</literal> ou <literal>U = M(km,:)</literal>
+                      ou <literal>U = M(:,km)</literal>.
                     </para>
                     <para>
                         <varname>km</varname> est un vecteur ligne si <varname>M</varname>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>kn</term>
+                <term>ku</term>
                 <listitem>
-                    Not yet implemented.
-                    Vector of indices of first encountered occurrences, such that
-                    <literal>M(i) = N(kn(i))</literal> or <literal>M(i,:) = N(kn(i),:)</literal>
-                    or <literal>M(:,i) = N(:,kn(i))</literal>.
+                    Vecteur, matrice ou hypermatrice d'indices dans U, tel que, selon
+                    l'option <varname>orient</varname>
+                    <itemizedlist>
+                        <listitem>
+                            "*": <varname>ku</varname> est de taille size(M), avec <literal>U(ku) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "r": <varname>ku</varname> est de taille [size(M,1), 1], avec <literal>U(ku,:) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "c": <varname>ku</varname> est de taille [1, size(M,2)], avec <literal>U(:,ku) = M</literal>
+                        </listitem>
+                    </itemizedlist>
                     <para/>
                 </listitem>
             </varlistentry>
                     <para>
                       Vecteur d'entiers > 0, au format de <varname>km</varname> :
                       nombres d'exemplaires dans <varname>M</varname> de chaque entité
-                      (élément, ligne, colonne) retournée dans <varname>N</varname>.
+                      (élément, ligne, colonne) retournée dans <varname>U</varname>.
                     </para>
                 </listitem>
             </varlistentry>
             <literal>"uniqueNan"</literal>. L'indicateur
             <literal>"uniqueNan"</literal> est insensible aux minuscules/majuscules.
         </para>
+        <para>
+            Pour un tableau de booléens, <literal>unique(…)</literal> sera utile principalement
+            avec les options "r" ou "c".
+        </para>
+        <para>
+            <note>
+                Les nombres complexes sont triés par modules croissants, puis par phases croissantes
+                sur [-π, π].
+            </note>
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Exemples</title>
@@ -187,14 +206,19 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
     <screen><![CDATA[
 --> c = [1+i, 1-i, -i, i, -i, 1+i]
  c  =
-   1. + i     1. - i  -i    i   -i    1. + i
+   1. + i    1. - i    0. - i    0. + i    0. - i    1. + i
 
 --> [u, k] = unique(c)
  u  =
-  -i    i    1. - i   1. + i
-
+   0. - i    0. + i    1. - i    1. + i
  k  =
    3.   4.   2.   1.
+
+--> [uc, kc] = unique(c, "c")
+ uc  =
+   0. - i    0. + i    1. - i    1. + i
+ kc  =
+   3.   4.   2.   1.
 ]]></screen>
 
     <para>Dédoublonnement de textes :</para>
@@ -207,6 +231,7 @@ u = unique(t)'
 [u, kt] = unique(t(1,:), "keepOrder")        // ordre initial conservé
 [uc, ktc, kuc, nb] = unique(t, "c")
 [uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // ordre initial des colonnes conservé
+[and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
  ]]></programlisting>
     <screen><![CDATA[
 --> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
@@ -258,6 +283,10 @@ u = unique(t)'
 
  nb  =
    2.   1.   1.   3.   2.   1.   3.   1.   1.
+
+--> [and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
+ ans  =
+  T  T
 ]]></screen>
         <para/>
         <para>Avec des valeurs Nan (et Inf). Option "uniqueNan" :</para>
@@ -344,6 +373,9 @@ unique(M, "c")
                 <revdescription>
                     <itemizedlist>
                         <listitem>
+                            Extension aux booléens.
+                        </listitem>
+                        <listitem>
                             Options "keepOrder" et "uniqueNan" ajoutées.
                         </listitem>
                         <listitem>
@@ -352,6 +384,12 @@ unique(M, "c")
                     </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    3ème résultat ku implémenté.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index f0145d3..a89b38d 100644 (file)
     <refsynopsisdiv>
         <title>呼び出し手順</title>
         <synopsis>
-            [N, km, kn, nb] = unique(M)
-            [N, km, kn, nb] = unique(M, orient)
-            [N, km, kn, nb] = unique(.., "keepOrder")
-            [N, km, kn, nb] = unique(.., "uniqueNan")
+            [U, km, ku, nb] = unique(M)
+            [U, km, ku, nb] = unique(M, orient)
+            [U, km, ku, nb] = unique(.., "keepOrder")
+            [U, km, ku, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -36,7 +36,9 @@
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    <para>数値または文字列のベクトルまたは行列</para>
+                    <para>
+                        vector, matrix, or hypermatrix of booleans, numbers, or strings.
+                    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
@@ -48,7 +50,7 @@
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>N</term>
+                <term>U</term>
                 <listitem>
                     <para>
                       <itemizedlist>
@@ -56,9 +58,9 @@
                             <para>
                               If <varname>orient</varname> is not used: Vector of extracted
                               <varname>M</varname> components sorted in ascending order.
-                              If <varname>M</varname> is a row vector, <varname>N</varname> is also
+                              If <varname>M</varname> is a row vector, <varname>U</varname> is also
                               a row vector. In all other <varname>M</varname> cases,
-                              <varname>N</varname> is a matrix or a column vector.
+                              <varname>U</varname> is a column vector.
                             </para>
                         </listitem>
                         <listitem>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>k</term>
+                <term>km</term>
                 <listitem>
-                    <para>
-                      Vector of indices of first encountered occurences, such that
-                      <literal>N(i) = M(k(i))</literal> or <literal>N(i,:) = M(k(i),:)</literal>
-                      or <literal>N(:,i) = M(:,k(i))</literal>.
-                    </para>
-                    <para>
-                        <varname>k</varname> is a row if <varname>M</varname> is a row or if
-                        <literal>orient="c"</literal> is used. Otherwise it's a column.
-                    </para>
+                    Vector of indices of first encountered occurrences, such that
+                    <literal>U = M(km)</literal> or <literal>U = M(km,:)</literal>
+                    or <literal>U = M(:,km)</literal>.
+                    <para/>
+                    <varname>km</varname> is a row if <varname>M</varname> is a row or if
+                    <literal>orient="c"</literal> is used. Otherwise it's a column.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>kn</term>
+                <term>ku</term>
                 <listitem>
-                    Not yet implemented.
-                    Vector of indices of first encountered occurrences, such that
-                    <literal>M(i) = N(kn(i))</literal> or <literal>M(i,:) = N(kn(i),:)</literal>
-                    or <literal>M(:,i) = N(:,kn(i))</literal>.
+                    Array of indices in U, such that, according to the <varname>orient</varname> option
+                    <itemizedlist>
+                        <listitem>
+                            "*": <varname>ku</varname> is of size size(M), and <literal>U(ku) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "r": <varname>ku</varname> is of size [size(M,1), 1], and <literal>U(ku,:) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "c": <varname>ku</varname> is of size [1, size(M,2)], and <literal>U(:,ku) = M</literal>
+                        </listitem>
+                    </itemizedlist>
                     <para/>
                 </listitem>
             </varlistentry>
                 <term>nb</term>
                 <listitem>
                     <para>
-                      Vector of integers > 0, with the same <varname>k</varname> shape:
+                      Vector of integers > 0, with the same <varname>km</varname> shape:
                       Numbers of occurences in <varname>M</varname> of respective unduplicated
-                      entities (components, rows, columns) returned in <varname>N</varname>.
+                      entities (components, rows, columns) returned in <varname>U</varname>.
                     </para>
                 </listitem>
             </varlistentry>
             <literal>"uniqueNan"</literal> is used. Specifying
             <literal>"uniqueNan"</literal> is case-insensitive.
         </para>
+        <para>
+            For booleans, <literal>unique(…)</literal> is useful mainly with the "r" or "c" options.
+        </para>
+        <para>
+            <note>
+                Complex numbers are sorted first by increasing magnitudes, then by increasing
+                phases on [-π,π].
+            </note>
+        </para>
     </refsection>
     <refsection role="examples">
         <title>例</title>
@@ -182,14 +199,19 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
     <screen><![CDATA[
 --> c = [1+i, 1-i, -i, i, -i, 1+i]
  c  =
-   1. + i     1. - i  -i    i   -i    1. + i
+   1. + i    1. - i    0. - i    0. + i    0. - i    1. + i
 
 --> [u, k] = unique(c)
  u  =
-  -i    i    1. - i   1. + i
-
+   0. - i    0. + i    1. - i    1. + i
  k  =
    3.   4.   2.   1.
+
+--> [uc, kc] = unique(c, "c")
+ uc  =
+   0. - i    0. + i    1. - i    1. + i
+ kc  =
+   3.   4.   2.   1.
 ]]></screen>
 
     <para>With some texts:</para>
@@ -199,9 +221,10 @@ t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
     ]
 u = unique(t)'
 [u, kt, nb] = unique(t(1,:))
-[u, kt] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[u, kt] = unique(t(1,:), "keepOrder")      // In original order of row#1 elements
 [uc, ktc, kuc, nb] = unique(t, "c")
-[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
+[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // In original order of columns
+[and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
  ]]></programlisting>
     <screen><![CDATA[
 --> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
@@ -253,6 +276,10 @@ u = unique(t)'
 
  nb  =
    2.   1.   1.   3.   2.   1.   3.   1.   1.
+
+--> [and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
+ ans  =
+  T  T
 ]]></screen>
         <para/>
         <para>With Nan (and Inf) values. "uniqueNan" option:</para>
@@ -339,6 +366,9 @@ unique(M, "c")
                 <revdescription>
                     <itemizedlist>
                         <listitem>
+                            Extension to booleans.
+                        </listitem>
+                        <listitem>
                             "keepOrder" and "uniqueNan" options introduced.
                         </listitem>
                         <listitem>
@@ -347,6 +377,12 @@ unique(M, "c")
                     </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    ku 3rd output implemented.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
\ No newline at end of file
index 04b6d79..b6f6eb9 100644 (file)
     <refsynopsisdiv>
         <title>Seqüência de Chamamento</title>
         <synopsis>
-            [N, km, kn, nb] = unique(M)
-            [N, km, kn, nb] = unique(M, orient)
-            [N, km, kn, nb] = unique(.., "keepOrder")
-            [N, km, kn, nb] = unique(.., "uniqueNan")
+            [U, km, ku, nb] = unique(M)
+            [U, km, ku, nb] = unique(M, orient)
+            [U, km, ku, nb] = unique(.., "keepOrder")
+            [U, km, ku, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -37,7 +37,7 @@
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    <para>vetor ou matriz de números ou strings </para>
+                    <para>Vetor, matriz ou hipermatriz de booleanos, números, ou texto.</para>
                 </listitem>
             </varlistentry>
             <varlistentry>
@@ -49,7 +49,7 @@
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>N</term>
+                <term>U</term>
                 <listitem>
                     <para>
                       <itemizedlist>
@@ -57,9 +57,9 @@
                             <para>
                               If <varname>orient</varname> is not used: Vector of extracted
                               <varname>M</varname> components sorted in ascending order.
-                            If <varname>M</varname> is a row vector, <varname>N</varname> is also
+                            If <varname>M</varname> is a row vector, <varname>U</varname> is also
                             a row vector. In all other <varname>M</varname> cases,
-                            <varname>N</varname> is a matrix or a column vector.
+                            <varname>U</varname> is a column vector.
                             </para>
                         </listitem>
                         <listitem>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>k</term>
+                <term>km</term>
                 <listitem>
-                    <para>
-                      Vector of indices of first encountered occurences, such that
-                      <literal>N(i) = M(k(i))</literal> or <literal>N(i,:) = M(k(i),:)</literal>
-                      or <literal>N(:,i) = M(:,k(i))</literal>.
-                    </para>
-                    <para>
-                        <varname>k</varname> is a row if <varname>M</varname> is a row or if
-                        <literal>orient="c"</literal> is used. Otherwise it's a column.
-                    </para>
+                    Vector of indices of first encountered occurrences, such that
+                    <literal>U = M(km)</literal> or <literal>U = M(km,:)</literal>
+                    or <literal>U = M(:,km)</literal>.
+                    <para/>
+                    <varname>km</varname> is a row if <varname>M</varname> is a row or if
+                    <literal>orient="c"</literal> is used. Otherwise it's a column.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>kn</term>
+                <term>ku</term>
                 <listitem>
-                    Not yet implemented.
-                    Vector of indices of first encountered occurrences, such that
-                    <literal>M(i) = N(kn(i))</literal> or <literal>M(i,:) = N(kn(i),:)</literal>
-                    or <literal>M(:,i) = N(:,kn(i))</literal>.
+                    Array of indices in U, such that, according to the <varname>orient</varname> option
+                    <itemizedlist>
+                        <listitem>
+                            "*": <varname>ku</varname> is of size size(M), and <literal>U(ku) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "r": <varname>ku</varname> is of size [size(M,1), 1], and <literal>U(ku,:) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "c": <varname>ku</varname> is of size [1, size(M,2)], and <literal>U(:,ku) = M</literal>
+                        </listitem>
+                    </itemizedlist>
                     <para/>
                 </listitem>
             </varlistentry>
                     <para>
                       Vector of integers > 0, with the same <varname>k</varname> shape:
                       Numbers of occurences in <varname>M</varname> of respective unduplicated
-                      entities (components, rows, columns) returned in <varname>N</varname>.
+                      entities (components, rows, columns) returned in <varname>U</varname>.
                     </para>
                 </listitem>
             </varlistentry>
             <literal>"uniqueNan"</literal> is used. Specifying
             <literal>"uniqueNan"</literal> is case-insensitive.
         </para>
+        <para>
+            For booleans, <literal>unique(…)</literal> is useful mainly with the "r" or "c" options.
+        </para>
+        <para>
+            <note>
+                Complex numbers are sorted first by increasing magnitudes, then by increasing
+                phases on [-π,π].
+            </note>
+        </para>
     </refsection>
     <refsection role="description">
         <title>Exemplos</title>
@@ -180,14 +195,19 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
     <screen><![CDATA[
 --> c = [1+i, 1-i, -i, i, -i, 1+i]
  c  =
-   1. + i     1. - i  -i    i   -i    1. + i
+   1. + i    1. - i    0. - i    0. + i    0. - i    1. + i
 
 --> [u, k] = unique(c)
  u  =
-  -i    i    1. - i   1. + i
-
+   0. - i    0. + i    1. - i    1. + i
  k  =
    3.   4.   2.   1.
+
+--> [uc, kc] = unique(c, "c")
+ uc  =
+   0. - i    0. + i    1. - i    1. + i
+ kc  =
+   3.   4.   2.   1.
 ]]></screen>
 
     <para>With some texts:</para>
@@ -197,9 +217,10 @@ t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
     ]
 u = unique(t)'
 [u, kt, ku, nb] = unique(t(1,:))
-[u, kt] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[u, kt] = unique(t(1,:), "keepOrder")      // In original order of row#1 elements
 [uc, ktc, kuc, nb] = unique(t, "c")
-[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
+[uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // In original order of columns
+[and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
  ]]></programlisting>
     <screen><![CDATA[
 --> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
@@ -251,6 +272,10 @@ u = unique(t)'
 
  nb  =
    2.   1.   1.   3.   2.   1.   3.   1.   1.
+
+--> [and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
+ ans  =
+  T  T
 ]]></screen>
         <para/>
         <para>With Nan (and Inf) values. "uniqueNan" option:</para>
@@ -337,6 +362,9 @@ unique(M, "c")
                 <revdescription>
                     <itemizedlist>
                         <listitem>
+                            Extension to booleans.
+                        </listitem>
+                        <listitem>
                             "keepOrder" and "uniqueNan" options introduced.
                         </listitem>
                         <listitem>
@@ -345,6 +373,12 @@ unique(M, "c")
                     </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                    ku 3rd output implemented.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index b5a0dc0..b76d217 100644 (file)
     <refsynopsisdiv>
         <title>Синтаксис</title>
         <synopsis>
-            [N, km, kn, nb] = unique(M)
-            [N, km, kn, nb] = unique(M, orient)
-            [N, km, kn, nb] = unique(.., "keepOrder")
-            [N, km, kn, nb] = unique(.., "uniqueNan")
+            [U, km, ku, nb] = unique(M)
+            [U, km, ku, nb] = unique(M, orient)
+            [U, km, ku, nb] = unique(.., "keepOrder")
+            [U, km, ku, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -36,7 +36,9 @@
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    <para>вектор или матрица чисел или строк</para>
+                    <para>
+                        вектор, матрица или гиперматрица логических значений, чисел или текстов.
+                    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
@@ -48,7 +50,7 @@
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>N</term>
+                <term>U</term>
                 <listitem>
                     <para>
                       <itemizedlist>
@@ -56,9 +58,9 @@
                             <para>
                               Если <varname>orient</varname> не используется: вектор извлечённых
                               <varname>M</varname> компонентов, сортированных в полядке возрастания.
-                              Если <varname>M</varname> является вектором-строкой, то <varname>N</varname>
+                              Если <varname>M</varname> является вектором-строкой, то <varname>U</varname>
                               так же является вектором-строкой. В случаях всех иных <varname>M</varname>
-                              <varname>N</varname> является матрицей или вектором-столбцом.
+                              <varname>U</varname> является вектором-столбцом.
                             </para>
                         </listitem>
                         <listitem>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>k</term>
+                <term>km</term>
                 <listitem>
                     <para>
                       Вектор индексов первых встреченных значений, таких что
-                      <literal>N(i) = M(k(i))</literal> или <literal>N(i,:) = M(k(i),:)</literal>
-                      или <literal>N(:,i) = M(:,k(i))</literal>.
+                      <literal>U = M(km)</literal> или <literal>U = M(km,:)</literal>
+                      или <literal>U = M(:,km)</literal>.
                     </para>
                     <para>
-                        <varname>k</varname> является строкой, если <varname>M</varname> является
+                        <varname>km</varname> является строкой, если <varname>M</varname> является
                         строкой или если используется <literal>orient="c"</literal>. В проитвном случае
                         это столбец.
                     </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>kn</term>
+                <term>ku</term>
                 <listitem>
-                    Not yet implemented.
-                    Vector of indices of first encountered occurrences, such that
-                    <literal>M(i) = N(kn(i))</literal> or <literal>M(i,:) = N(kn(i),:)</literal>
-                    or <literal>M(:,i) = N(:,kn(i))</literal>.
+                    Массив индексов в <varname>U</varname>, таких что в соответствии с опцией
+                    <varname>orient</varname>
+                    <itemizedlist>
+                        <listitem>
+                          "*": <varname>ku</varname> имеет размер <literal>size(M)</literal>, и <literal>U(ku) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "r": <varname>ku</varname> имеет размер <literal>[size(M,1), 1]</literal>, и <literal>U(ku,:) = M</literal>
+                        </listitem>
+                        <listitem>
+                            "c": <varname>ku</varname> имеет размер <literal>[1, size(M,2)]</literal>, и <literal>U(:,ku) = M</literal>
+                        </listitem>
+                    </itemizedlist>
                     <para/>
                 </listitem>
             </varlistentry>
                     <para>
                       Вектор целых чисел > 0 той же формы, что и <varname>k</varname>:
                       количество случаев <varname>M</varname> соответствующих непродублированных элементов
-                      (компоентов, строк, столбцов) возвращаемых в <varname>N</varname>.
+                      (компонентов, строк, столбцов) возвращаемых в <varname>U</varname>.
                     </para>
                 </listitem>
             </varlistentry>
             равен истине, пока не будет использоваться <literal>"uniqueNan"</literal>. Определение
             <literal>"uniqueNan"</literal> нечувствительно к регистру.
         </para>
+        <para>
+            Для логических значений, <literal>unique(…)</literal> полезна главным образом с опциями
+            <literal>"r"</literal> or <literal>"c"</literal>.
+        </para>
+        <para>
+            <note>
+                Комплексные числа сортируются сначала по амплитудам, а затем по фазам в [-π,π].
+            </note>
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Примеры</title>
@@ -178,14 +198,19 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
     <screen><![CDATA[
 --> c = [1+i, 1-i, -i, i, -i, 1+i]
  c  =
-   1. + i     1. - i  -i    i   -i    1. + i
+   1. + i    1. - i    0. - i    0. + i    0. - i    1. + i
 
 --> [u, k] = unique(c)
  u  =
-  -i    i    1. - i   1. + i
-
+   0. - i    0. + i    1. - i    1. + i
  k  =
    3.   4.   2.   1.
+
+--> [uc, kc] = unique(c, "c")
+ uc  =
+   0. - i    0. + i    1. - i    1. + i
+ kc  =
+   3.   4.   2.   1.
 ]]></screen>
 
     <para>С текстом:</para>
@@ -198,6 +223,7 @@ u = unique(t)'
 [u, kt] = unique(t(1,:), "keepOrder")  // сохранение исходного порядка элементов строки №1
 [uc, ktc, kuc, nb] = unique(t, "c")
 [uc, ktc, kuc, nb] = unique(t, "c", "keepOrder")  // сохранение исходного порядка столбцов
+[and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
  ]]></programlisting>
     <screen><![CDATA[
 --> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
@@ -249,6 +275,10 @@ u = unique(t)'
 
  nb  =
    2.   1.   1.   3.   2.   1.   3.   1.   1.
+
+--> [and(t(:,ktc)==uc), and(uc(:,kuc)==t) ]
+ ans  =
+  T  T
 ]]></screen>
         <para/>
         <para>Со значениями Nan (и Inf). Опция "uniqueNan":</para>
@@ -335,6 +365,9 @@ unique(M, "c")
                 <revdescription>
                     <itemizedlist>
                         <listitem>
+                            Расширено до логических значений.
+                        </listitem>
+                        <listitem>
                             Введены опции "keepOrder" и "uniqueNan".
                         </listitem>
                         <listitem>
@@ -343,6 +376,12 @@ unique(M, "c")
                     </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                  Реализован третий выходной аргумент <literal>ku</literal>.
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index db2d194..7d3361a 100644 (file)
@@ -1,7 +1,7 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) INRIA
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
-// Copyright (C) 2018, 2019 - Samuel GOUGEON
+// Copyright (C) 2018 - 2020 - Samuel GOUGEON
 //
 // This file is hereby licensed under the terms of the GNU GPL v2.0,
 // pursuant to article 5.3.4 of the CeCILL v.2.1.
@@ -11,7 +11,7 @@
 // along with this program.
 
 function [x, ki, ko, nb] = unique(x, varargin)
-    // extract unique components of a vector
+    // extract unique components of a vector, matrix, or hypermatrix
     // varargin : orient=1|2|"r"|"c", "uniqueNan", "keepOrder"
     //
     // History:
@@ -19,6 +19,8 @@ function [x, ki, ko, nb] = unique(x, varargin)
     //   - add uniqueNan option: http://bugzilla.scilab.org/15522
     //   - add keepOrder option: http://bugzilla.scilab.org/15795
     //   - add nb output option: http://bugzilla.scilab.org/8418
+    // * 2020 - S. Gougeon :
+    //   - add ku output indices: http://bugzilla.scilab.org/16337
 
     keepOrder = %f
     uniqueNan = %f
@@ -27,6 +29,7 @@ function [x, ki, ko, nb] = unique(x, varargin)
     ki = []
     ko = []
     nb = []
+    sx = size(x)
 
     // CHECKING INPUT ARGUMENTS
     // ------------------------
@@ -34,6 +37,9 @@ function [x, ki, ko, nb] = unique(x, varargin)
     i = 2;  // index of the current input argument
     if size(in)>0 then
         a = in(1)
+        if type(a)==0
+            a = "*"
+        end
         if typeof(a)=="string"
             a = convstr(a)
         end
@@ -57,6 +63,11 @@ function [x, ki, ko, nb] = unique(x, varargin)
         in(1) = null()
         i = 3
     end
+    if or(orient==["r" "c"]) & ndims(x)>2 then
+        msg = _("%s: Argument #%d: ''%s'' not allowed for an hypermatrix.\n")
+        error(msprintf(msg, "unique", 2, orient))
+    end
+
     while size(in)>0 & i<5 then
         a = in(1)
         if typeof(a)=="string"
@@ -79,140 +90,110 @@ function [x, ki, ko, nb] = unique(x, varargin)
     sz = size(x);
     if size(x, orient)==1 then
         ki = 1
+        ko = 1
+        nb = 1
         return
     end
     if uniqueNan
         [x, newInf] = uniqueProcessNan(x, [], "removeNan")
     end
-    getK = argn(1)>1 | keepOrder
+    getK = argn(1) > 1 | keepOrder
 
 
     // [] trivial case
     // ---------------
     if isempty(x) then
-        return  // ki, nb are already []. x is [] or sparse([])
-    end
-
-    // PROCESSING complex numbers
-    // --------------------------
-    if or(type(x)==[1 5]) then
-        if ~isreal(x)
-            if isreal(x,0)
-                x = real(x);
-            else
-                if orient=="*"
-                    x = [real(x(:)) imag(x(:))]
-                    if ~getK
-                        x = unique(x,"r")
-                    else
-                        [x, ki, ko, nb] = unique(x,"r")
-                    end
-                    x = complex(x(:,1),x(:,2));
-                    if sz(1)==1 // => put results in row
-                        x = x.'
-                        if getK
-                            ki = ki'
-                            nb = nb'
-                        end
-                    end
-                elseif orient=="r" | orient==1
-                    x = [real(x) imag(x)]
-                    if ~getK
-                        x = unique(x,"r")
-                    else
-                        [x, ki, ko, nb] = unique(x,"r")
-                    end
-                    x = complex(x(:,1:sz(2)), x(:,sz(2)+1:$));
-                elseif orient=="c" | orient==2
-                    x = [real(x) ; imag(x)]
-                    if ~getK
-                        x = unique(x,"c")
-                    else
-                        [x, ki, ko, nb] = unique(x,"c")
-                    end
-                    x = complex(x(1:sz(1),:), x(sz(1)+1:$,:));
-                end
-                if uniqueNan
-                    x = uniqueProcessNan(x, newInf, "restoreNan")
-                end
-                if keepOrder
-                    [ki, kk] = gsort(ki,"g","i")
-                    select orient
-                    case "*"
-                        x = x(kk)
-                    case "r"
-                        x = x(kk,:)
-                    case "c"
-                        x = x(:,kk)
-                    end
-                    nb = nb(kk)
-                end
-                return
-            end
-        end
+        return  // ki, ko, nb are already []. x is [] or sparse([])
     end
 
-    // PROCESSING text and other numerical types
-    // -----------------------------------------
+    // PROCESSING
+    // ----------
+    areComplex = or(type(x)==[1 5]) && ~isreal(x, 0)
     if orient=="*" then
         if getK then
-            [x,ki] = gsort(x,"g","i");
+            // ki (begin)
+            if areComplex
+                [x,ki] = gsort(x,"g",["i" "i"], list(abs, atan));
+            else
+                [x,ki] = gsort(x,"g","i");
+            end
             keq = x(2:$) == x(1:$-1);
-            if argn(1)>2
-                nb = [0 find(~keq) size(x,"*")]
-                nb = nb(2:$) - nb(1:$-1)
+            if argn(1) > 2
+                // ko (begin)
+                ko(ki) = cumsum(~[%F ; keq(:)])
+                if ko <> [] then
+                    ko = matrix(ko, sx)
+                end
+                // nb
+                if argn(1) > 3
+                    nb = [0 find(~keq) size(x,"*")]
+                    nb = nb(2:$) - nb(1:$-1)
+                end
             end
+            // ki (end)
             keq = find(keq);
-            if keq<>[] then keq = keq+1;end
+            if keq <> [] then keq = keq + 1; end
             x(keq) = [];
             ki(keq) = [];
-            if size(x,1)>1 | ndims(x)>2
-                x = x(:)
-                ki = ki(:)
-                nb = nb(:)
-            end
         else
-            x = gsort(x,"g","d");
+            if areComplex
+                x = gsort(x,"g",["d" "d"], list(abs, atan));
+            else
+                x = gsort(x,"g","d");
+            end
             x = x($:-1:1);
             x( find(x(2:$) == x(1:$-1)) ) = [];
         end
-    elseif  orient==1|orient=="r" then
+        if sx(1) > 1 | length(sx) > 2
+            x = x(:)
+            ki = ki(:)
+            nb = nb(:)
+        end
+
+    else // orient used
+        if  orient==2 | orient=="c" then
+            x = x.'
+        end
         if getK then
-            [x,ki] = gsort(x,"lr","i");
+            if areComplex
+                [x,ki] = gsort(x,"lr",["i" "i"], list(abs, atan));
+            else
+                [x,ki] = gsort(x,"lr","i");
+            end
             keq = and(x(2:$,:) == x(1:$-1,:),"c")
             if argn(1)>2
-                nb = [0 find(~keq) size(x,1)]
-                nb = nb(2:$) - nb(1:$-1)
-                nb = nb(:)
+                ko(ki) = cumsum(~[%F ; keq(:)])
+                // nb
+                if argn(1) > 3
+                    nb = [0 find(~keq) size(x,1)]
+                    nb = nb(2:$) - nb(1:$-1)
+                    nb = nb(:)
+                end
             end
             keq = find(keq)
-            if keq<>[] then keq = keq+1;end
+            if keq <> [] then keq = keq + 1;end
             x(keq,:) = [];
             ki(keq,:) = [];
         else
-            x = gsort(x,"lr","i");
+            if areComplex
+                x = gsort(x,"lr",["i" "i"], list(abs, atan));
+            else
+                x = gsort(x,"lr","i");
+            end
             x( find(and(x(2:$,:) == x(1:$-1,:),"c")),:) = [];
         end
-    elseif  orient==2|orient=="c" then
-        if getK then
-            [x,ki] = gsort(x,"lc","i");
-            keq = and(x(:,2:$) == x(:,1:$-1),"r")
-            if argn(1)>2
-                nb = [0 find(~keq) size(x,2)]
-                nb = nb(2:$) - nb(1:$-1)
-            end
-            keq = find(keq)
-            if keq<>[] then keq = keq+1;end
-            x(:,keq) = [];
-            ki(:,keq) = [];
-        else
-            x = gsort(x,"lc","i");
-            x(:, find(and(x(:,2:$) == x(:,1:$-1),"r")) ) = [];
+        if  orient==2 | orient=="c" then
+            x = x.'
+            ki = matrix(ki, 1, -1)
+            ko = ko'
+            nb = nb'
         end
     end
+
     if uniqueNan
         x = uniqueProcessNan(x, newInf, "restoreNan")
     end
+
     if keepOrder
         [ki, kk] = gsort(ki,"g","i")
         select orient
@@ -225,9 +206,12 @@ function [x, ki, ko, nb] = unique(x, varargin)
         end
         if argn(1)>2
             nb = nb(kk)
+            [?, kk2] = gsort(kk,"g","i")
+            ko = kk2(ko)
         end
     end
 endfunction
+
 // -------------------------------------------------------------------
 
 // To consider Nan mutually equal, we replace all of them with a "regular" substitute.
@@ -238,7 +222,7 @@ endfunction
 
 function [x, newInf] = uniqueProcessNan(x, newInf, way)
 
-    if way=="removeNan" & or(isnan(x)) then 
+    if way=="removeNan" & or(isnan(x)) then
         // Replacing Nan
         // -------------
         if isreal(x)
index 8d838b6..67c15d9 100644 (file)
@@ -1,6 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
-// Copyright (C) 2018-2019 - Samuel Gougeon
+// Copyright (C) 2018-2020 - Samuel Gougeon
 //
 //  This file is distributed under the same license as the Scilab package.
 // =============================================================================
 //
 // <-- CLI SHELL MODE -->
 // <-- NO CHECK REF -->
+// <-- ENGLISH IMPOSED -->
 
 // =====================
 // Checking output sizes
 // =====================
-// "*"
-[u,k,?,nb] = unique([]);
-assert_checkequal(u, []);
-assert_checkequal(k, []);
-assert_checkequal(nb,[]);
-[u,k,?,nb] = unique([1 4 5]);
-sref = [1 3];
-assert_checkequal(size(u), sref);
-assert_checkequal(size(k), sref);
-assert_checkequal(size(nb),sref);
-[u,k,?,nb] = unique([1 4 5]');
-sref = [3 1];
-assert_checkequal(size(u), sref);
-assert_checkequal(size(k), sref);
-assert_checkequal(size(nb),sref);
-[u,k,?,nb] = unique([1 3 4 ; 5 6 7]);
-sref = [6 1];
-assert_checkequal(size(u), sref);
-assert_checkequal(size(k), sref);
-assert_checkequal(size(nb),sref);
-[u,k,?,nb] = unique(rand(3,4,2));
-sref = [24 1];
-assert_checkequal(size(u), sref);
-assert_checkequal(size(k), sref);
-assert_checkequal(size(nb),sref);
-
-// "r"
-[u,k,?,nb] = unique([], "r");
-assert_checkequal(u, []);
-assert_checkequal(k, []);
-assert_checkequal(nb,[]);
-[u,k,?,nb] = unique([1 3 4 ; 5 6 7], "r");
-assert_checkequal(size(u), [2 3]);
-assert_checkequal(size(k), [2 1]);
-assert_checkequal(size(nb),[2 1]);
+objects = list([], 7, 1:5, (1:5)', [1 3 5 ; 2 4 6], matrix(1:12,[2 3 2]));
+for o = objects
+    [u,ki,ko,nb] = unique(o);
+    n = length(o);
+    if o==[], su = [0 0]; else su = [n 1]; end
+    if isrow(o), su = [1 n]; end
+    assert_checkequal(size(u), su);
+    assert_checkequal(size(ki), su);
+    assert_checkequal(size(ko), size(o));
+    assert_checkequal(size(nb), size(ki));
+end
+objects($) = null(); // Removing hypermat (excluded from "r" and "c" options)
+for o = objects
+    [u,ki,ko,nb] = unique(o, "r");
+    [nr, nc] = size(o);
+    if o==[], su = [0 0]; else su = [nr 1]; end
+    assert_checkequal(size(u),  size(o));
+    assert_checkequal(size(ki), su);
+    assert_checkequal(size(ko), su);
+    assert_checkequal(size(nb), size(ki));
+
+    [u,ki,ko,nb] = unique(o, "c");
+    [nr, nc] = size(o);
+    if o==[], su = [0 0]; else su = [1 nc]; end
+    assert_checkequal(size(u),  size(o));
+    assert_checkequal(size(ki), su);
+    assert_checkequal(size(ko), su);
+    assert_checkequal(size(nb), size(ki));
+end
 
-// "c"
-[u,k,?,nb] = unique([], "c");
-assert_checkequal(u,[]);
-assert_checkequal(k,[]);
-[u,k,?,nb] = unique([1 3 4 ; 5 6 7], "c");
-assert_checkequal(size(u), [2 3]);
-assert_checkequal(size(k), [1 3]);
-assert_checkequal(size(nb),[1 3]);
 
 // ====================
 // With decimal numbers
 // ====================
+// -----
+// EMPTY
+// -----
+// By element
+[u,ki,ko,nb] = unique([]);
+assert_checkequal(u, []);
+assert_checkequal(ki, []);
+assert_checkequal(ko, []);
+assert_checkequal(nb, []);
+// "r"
+[u,ki,ko,nb] = unique([], "r");
+assert_checkequal(u, []);
+assert_checkequal(ki, []);
+assert_checkequal(ko, []);
+assert_checkequal(nb, []);
+// "c"
+[u,ki,ko,nb] = unique([], "c");
+assert_checkequal(u, []);
+assert_checkequal(ki, []);
+assert_checkequal(ko, []);
+assert_checkequal(nb, []);
+
+// ---
+// ROW
+// ---
+x = [1 3 %nan 3 %inf 4 0 %nan 4 1];
+
+// By elements
+[u, ki, ko, nb] = unique(x);
+assert_checkequal(u, [0  1  3  4  %inf  %nan  %nan]);
+assert_checkequal(ki, [7  1  2  6  5  3  8]);
+assert_checkequal(x(ki), u);
+assert_checkequal(ko, [2  3  6  3  5  4  1  7  4  2]);
+assert_checkequal(u(ko), x);
+assert_checkequal(nb, [1  2  2  2  1  1  1]);
+// "r"
+[u,ki,ko,nb] = unique(x, "r");
+assert_checkequal(u, x);
+assert_checkequal(ki, 1);
+assert_checkequal(x(ki,:), u);
+assert_checkequal(ko, 1);
+assert_checkequal(u(ko,:), x);
+assert_checkequal(nb, 1);
+// "c"
+[u,ki,ko,nb] = unique(x, "c");
+assert_checkequal(u, [0  1  3  4  %inf  %nan  %nan]);
+assert_checkequal(ki, [7  1  2  6  5  3  8]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(ko, [2  3  6  3  5  4  1  7  4  2]);
+assert_checkequal(u(:,ko), x);
+assert_checkequal(nb, [1  2  2  2  1  1  1]);
+
+// ------
+// COLUMN
+// ------
+x = x';
+// By elements
+[u, ki, ko, nb] = unique(x);
+assert_checkequal(u, [0  1  3  4  %inf  %nan  %nan]');
+assert_checkequal(ki, [7  1  2  6  5  3  8]');
+assert_checkequal(x(ki), u);
+assert_checkequal(ko, [2  3  6  3  5  4  1  7  4  2]');
+assert_checkequal(u(ko), x);
+assert_checkequal(nb, [1  2  2  2  1  1  1]');
+// "r"
+[u,ki,ko,nb] = unique(x, "r");
+assert_checkequal(u, [0  1  3  4  %inf  %nan  %nan]');
+assert_checkequal(ki, [7  1  2  6  5  3  8]');
+assert_checkequal(x(ki,:), u);
+assert_checkequal(ko, [2  3  6  3  5  4  1  7  4  2]');
+assert_checkequal(u(ko,:), x);
+assert_checkequal(nb, [1  2  2  2  1  1  1]');
+// "c"
+[u,ki,ko,nb] = unique(x, "c");
+assert_checkequal(u, x);
+assert_checkequal(ki, 1);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(ko, 1);
+assert_checkequal(u(:,ko), x);
+assert_checkequal(nb, 1);
+
+// ------
+// MATRIX
+// ------
 x = [ 2  0  2  2  2  0  0  0  2  0  0  2  2  1  0  1
       1  2  2  2  1  0  2  2  0  0  1  0  1  1  0  0
     ];
 u = unique(x);
 assert_checkequal(u, [0 1 2]');
-[u,k,?,nb] = unique(x);
+[u,ki,ko,nb] = unique(x);
 assert_checkequal(u, [0 1 2]');
-assert_checkequal(k, [3 2 1]');
+assert_checkequal(ki, [3 2 1]');
+assert_checkequal(ko, x+1);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[13 7 12]');
-
+// "c"
 u = unique(x, "c");
 uxc = [ 0  0  0  1  1  2  2  2
         0  1  2  0  1  0  1  2
       ];
 assert_checkequal(u, uxc);
-[u,k,?,nb] = unique(x, "c");
+[u,ki,ko,nb] = unique(x, "c");
 assert_checkequal(u, uxc);
-assert_checkequal(k, [6  11  2  16  14  9  1  3]);
-assert_checkequal(nb,[3  1   3  1   1   2  3  2]);
-
-u = unique(x', "r");
-assert_checkequal(u, uxc');
-[u,k,?,nb] = unique(x', "r");
-assert_checkequal(u, uxc');
-assert_checkequal(k, [6  11  2  16  14  9  1  3]');
-assert_checkequal(nb,[3  1   3  1   1   2  3  2]');
+assert_checkequal(ki, [6  11  2  16  14  9  1  3]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(ko, [7 3 8 8 7 1 3 3 6 1 2 6 7 5 1 4]);
+assert_checkequal(u(:,ko), x);
+assert_checkequal(nb, [3  1  3  1  1  2  3  2]);
+// "r"
+x = x';
+u = unique(x, "r");
+uxc = [ 0  0  0  1  1  2  2  2
+        0  1  2  0  1  0  1  2
+      ]';
+assert_checkequal(u, uxc);
+[u,ki,ko,nb] = unique(x, "r");
+assert_checkequal(u, uxc);
+assert_checkequal(ki, [6  11  2  16  14  9  1  3]');
+assert_checkequal(x(ki,:), u);
+assert_checkequal(ko, [7 3 8 8 7 1 3 3 6 1 2 6 7 5 1 4]');
+assert_checkequal(u(ko,:), x);
+assert_checkequal(nb, [3  1  3  1  1  2  3  2]');
+
+// -----------
+// HYPERMATRIX
+// -----------
+x = cat(3,[2 0 %nan 1 ; 2 1 0 2], [%inf 2 1 2 ; 1 0 %nan 2]);
+[u,ki,ko,nb] = unique(x);
+assert_checkequal(u, [0 1 2 %inf %nan %nan]');
+assert_checkequal(ki, [3  4  1  9  5  14]');
+assert_checkequal(u(ko), x);
+assert_checkequal(nb, [3  4  6  1  1  1]');
+msg = "unique: Argument #2: ''r'' not allowed for an hypermatrix.";
+assert_checkerror("unique(x, ""r"")", msg);
+msg = "unique: Argument #2: ''c'' not allowed for an hypermatrix.";
+assert_checkerror("unique(x, ""c"")", msg);
 
+// ---------
 // keepOrder
 // ---------
-[u,k,?,nb] = unique(x, "keepOrder");
+x = [ 2  0  2  2  2  0  0  0  2  0  0  2  2  1  0  1
+      1  2  2  2  1  0  2  2  0  0  1  0  1  1  0  0
+    ];
+[u,ki,ko,nb] = unique(x, "keepOrder");
 assert_checkequal(u, [2 1 0]');
-assert_checkequal(k, [1 2 3]');
+assert_checkequal(ki, [1 2 3]');
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[12 7 13]');
 
-[u,k,?,nb] = unique(x, "c", "keepOrder");
 uxc = [2  0  2  0  2  0  1  1
        1  2  2  0  0  1  1  0
       ];
+// "r"
+[u,ki,ko,nb] = unique(x', "r", "keepOrder");
+assert_checkequal(u, uxc');
+assert_checkequal(ki, [1  2  3  6  9  11 14 16]');
+assert_checkequal(x'(ki,:), u);
+assert_checkequal(u(ko,:), x');
+assert_checkequal(nb, [3  3  2  3  2  1  1  1 ]');
+// "c"
+[u,ki,ko,nb] = unique(x, "c", "keepOrder");
 assert_checkequal(u, uxc);
-assert_checkequal(k, [1  2  3  6  9  11 14 16]);
-assert_checkequal(nb,[3  3  2  3  2  1  1  1 ]);
+assert_checkequal(ki, [1  2  3  6  9  11 14 16]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
+assert_checkequal(nb, [3  3  2  3  2  1  1  1 ]);
 
-[u,k,?,nb] = unique(x', "r", "keepOrder");
-assert_checkequal(u, uxc');
-assert_checkequal(k, [1  2  3  6  9  11 14 16]');
-assert_checkequal(nb,[3  3  2  3  2  1  1  1 ]');
 
-// With Nans
-// ---------
+// --------------
+// More with Nans
+// --------------
 Nan = %nan; Inf = %inf;
 x = [Nan  Nan  Inf  Nan  0  Inf  Inf  Nan  Inf  Nan
      Inf  0    Nan  0    0  0    Nan  Nan  0    0
     ];
 u = unique(x);
 assert_checkequal(u, [0 Inf Nan*ones(1,8)]');
-[u,k,?,nb] = unique(x);
+[u,ki,ko,nb] = unique(x);
 assert_checkequal(u, [0 Inf Nan*ones(1,8)]');
-assert_checkequal(k, [4 2 1 3 6 7 14 15 16 19]');
+assert_checkequal(ki, [4 2 1 3 6 7 14 15 16 19]');
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[7 5 1 1 1 1 1  1  1  1]');
 //
 u = unique(x, "c");
@@ -125,43 +237,55 @@ uxc = [0  Inf  Inf  Inf  Nan  Nan  Nan  Nan  Nan
        0  0    Nan  Nan  0    0    0    Inf  Nan
       ];
 assert_checkequal(u, uxc);
-[u,k,?,nb] = unique(x, "c");
+[u,ki,ko,nb] = unique(x, "c");
 assert_checkequal(u, uxc);
-assert_checkequal(k, [5  6  3  7  2  4 10  1  8]);
+assert_checkequal(ki, [5  6  3  7  2  4 10  1  8]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
 assert_checkequal(nb,[1  2  1  1  1  1  1  1  1]);
 
 u = unique(x', "r");
 assert_checkequal(u, uxc');
-[u,k,?,nb] = unique(x', "r");
+[u,ki,ko,nb] = unique(x', "r");
 assert_checkequal(u, uxc');
-assert_checkequal(k, [5  6  3  7  2  4 10  1  8]');
+assert_checkequal(ki, [5  6  3  7  2  4 10  1  8]');
+assert_checkequal(x'(ki,:), u);
+assert_checkequal(u(ko,:), x');
 assert_checkequal(nb,[1  2  1  1  1  1  1  1  1]');
 
 // With Nans & "uniqueNan" option
 // ------------------------------
-[u,k,?,nb] = unique(x, "uniqueNan");
+[u,ki,ko,nb] = unique(x, "uniqueNan");
 assert_checkequal(u, [0 Inf Nan]');
-assert_checkequal(k, [4 2 1]');
+assert_checkequal(ki, [4 2 1]');
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[7 5 8]');
 //
 uxc = [0  Inf  Inf  Nan  Nan  Nan
        0  0    Nan  0    Inf  Nan
       ];
-[u,k,?,nb] = unique(x, "c", "uniqueNan");
+[u,ki,ko,nb] = unique(x, "c", "uniqueNan");
 assert_checkequal(u, uxc);
-assert_checkequal(k, [5  6  3  2  1  8]);
+assert_checkequal(ki, [5  6  3  2  1  8]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
 assert_checkequal(nb,[1  2  2  3  1  1]);
 
-[u,k,?,nb] = unique(x', "r", "uniqueNan");
+[u,ki,ko,nb] = unique(x', "r", "uniqueNan");
 assert_checkequal(u, uxc');
-assert_checkequal(k, [5  6  3  2  1  8]');
+assert_checkequal(ki, [5  6  3  2  1  8]');
+assert_checkequal(x'(ki,:), u);
+assert_checkequal(u(ko,:), x');
 assert_checkequal(nb,[1  2  2  3  1  1]');
 
 // With Nans & "uniqueNan" & "keepOrder" options
 // ---------------------------------------------
-[u,k,?,nb] = unique(x, "uniqueNan", "keepOrder");
+[u,ki,ko,nb] = unique(x, "uniqueNan", "keepOrder");
 assert_checkequal(u, [Nan Inf 0]');
-assert_checkequal(k, [1 2 4]');
+assert_checkequal(ki, [1 2 4]');
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[8 5 7]');
 //
 uxc = [Nan  Nan  Inf  0  Inf  Nan
@@ -169,14 +293,18 @@ uxc = [Nan  Nan  Inf  0  Inf  Nan
       ];
 //x = [Nan  Nan  Inf  Nan  0  Inf  Inf  Nan  Inf  Nan
 //     Inf  0    Nan  0    0  0    Nan  Nan  0    0
-[u,k,?,nb] = unique(x, "c", "uniqueNan", "keepOrder");
+[u,ki,ko,nb] = unique(x, "c", "uniqueNan", "keepOrder");
 assert_checkequal(u, uxc);
-assert_checkequal(k, [1  2  3  5  6  8]);
+assert_checkequal(ki, [1  2  3  5  6  8]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
 assert_checkequal(nb,[1  3  2  1  2  1]);
 
-[u,k,?,nb] = unique(x', "r", "uniqueNan", "keepOrder");
+[u,ki,ko,nb] = unique(x', "r", "uniqueNan", "keepOrder");
 assert_checkequal(u, uxc');
-assert_checkequal(k, [1  2  3  5  6  8]');
+assert_checkequal(ki, [1  2  3  5  6  8]');
+assert_checkequal(x'(ki,:), u);
+assert_checkequal(u(ko,:), x');
 assert_checkequal(nb,[1  3  2  1  2  1]');
 
 // =====================
@@ -188,72 +316,113 @@ x = int8([-3 0 2 0 -3
          ]);
 u = unique(x);
 assert_checkequal(u, int8([-3 0 2])');
-[u,k,?,nb] = unique(x);
+[u,ki,ko,nb] = unique(x);
 assert_checkequal(u, int8([-3 0 2])');
-assert_checkequal(k, [1 4 6]');
+assert_checkequal(ki, [1 4 6]');
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[6 5 4]');
 
 u = unique(x, "r");
 assert_checkequal(u, int8([-3 0 2 0 -3 ; -3 2 0 2 -3]));
-[u,k,?,nb] = unique(x, "r");
+[u,ki,ko,nb] = unique(x, "r");
 assert_checkequal(u, int8([-3 0 2 0 -3 ; -3 2 0 2 -3]));
-assert_checkequal(k, [1;3]);
+assert_checkequal(ki, [1;3]);
+assert_checkequal(x(ki,:), u);
+assert_checkequal(u(ko,:), x);
 assert_checkequal(nb,[2;1]);
 
 u = unique(x, "c");
 assert_checkequal(u, int8([-3 0 2 ; -3 0 2; -3 2 0]));
-[u,k,?,nb] = unique(x, "c");
+[u,ki,ko,nb] = unique(x, "c");
 assert_checkequal(u, int8([-3 0 2 ; -3 0 2; -3 2 0]));
-assert_checkequal(k, [1 2 3]);
+assert_checkequal(ki, [1 2 3]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
 assert_checkequal(nb,[2 2 1]);
 
+// =============
+// With booleans
+// =============
+x = [%F %T %F %F %F %T %T
+     %F %T %T %F %T %F %F ];
+[u,ki,ko,nb] = unique(x);
+assert_checkequal(u, [%F ; %T]);
+assert_checkequal(ki, [1;3]);
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
+assert_checkequal(nb,[8;6]);
+
+[u,ki,ko,nb] = unique(x, "c");
+assert_checkequal(u, [%F %F %T %T ; %F %T %F %T]);
+assert_checkequal(ki, [1 3 6 2]);
+assert_checkequal(x(:,ki), u);
+assert_checkequal(u(:,ko), x);
+assert_checkequal(nb,[2 2 2 1]);
+
+
 
 // ====================
 // With complex numbers
 // ====================
 i = %i;
 x = [1-i, 3+2*i, 1+i, 3-2*i, 3+2*i, 3-i, 1-i];
-assert_checkequal(unique(x), [1-i, 1+i, 3-2*i, 3-i, 3+2*i]);
-[u,k,?,nb] = unique(x);
-assert_checkequal(u, [1-i, 1+i, 3-2*i, 3-i, 3+2*i]);
-assert_checkequal(k, [1  3  4  6  2]);
+assert_checkequal(unique(x), [1-i, 1+i, 3-i, 3-2*i, 3+2*i]);
+[u,ki,ko,nb] = unique(x);
+assert_checkequal(u, [1-i, 1+i, 3-i, 3-2*i, 3+2*i]);
+assert_checkequal(ki, [1  3  6  4  2]);
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[2  1  1  1  2]);
 
 c = [x($:-1:1) ; x ; x($:-1:1) ; 1:7 ; x];
 u = unique(c, "r");
-assert_checkequal(u, c([4 2 1],:));
-[u,k,?,nb] = unique(c, "r");
-assert_checkequal(u, c([4 2 1],:));
-assert_checkequal(k, [4 2 1]');
+assert_checkequal(u, c([4 1 2],:));
+[u,ki,ko,nb] = unique(c, "r");
+assert_checkequal(u, c([4 1 2],:));
+assert_checkequal(ki, [4 1 2]');
+assert_checkequal(c(ki,:), u);
+assert_checkequal(u(ko,:), c);
 assert_checkequal(nb,[1 2 2]');
 
-u = unique(c', "c");
-kref = [4 2 1];
-assert_checkequal(u, c'(:,kref));
-[u,k,?,nb] = unique(c', "c");
-assert_checkequal(u, c'(:,kref));
-assert_checkequal(k, kref);
+c = c.';
+u = unique(c, "c");
+kref = [4 1 2];
+assert_checkequal(u, c(:,kref));
+[u,ki,ko,nb] = unique(c, "c");
+assert_checkequal(u, c(:,kref));
+assert_checkequal(ki, kref);
+assert_checkequal(c(:,ki), u);
+assert_checkequal(u(:,ko), c);
 assert_checkequal(nb,[1 2 2]);
 
+// ---------
 // keepOrder
 // ---------
-[u,k,?,nb] = unique(x, "keepOrder");
+// ROW
+[u,ki,ko,nb] = unique(x, "keepOrder");
 assert_checkequal(u, [1-i, 3+2*i, 1+i, 3-2*i, 3-i]);
-assert_checkequal(k, [1  2  3  4  6]);
+assert_checkequal(ki, [1  2  3  4  6]);
+assert_checkequal(x(ki), u);
+assert_checkequal(u(ko), x);
 assert_checkequal(nb,[2  2 1  1  1 ]);
 
 c = [x($:-1:1) ; x ; x($:-1:1) ; 1:7 ; x];
 kref = [1 2 4];
-[u,k,?,nb] = unique(c, "r", "keepOrder");
+[u,ki,ko,nb] = unique(c, "r", "keepOrder");
 assert_checkequal(u, c(kref,:));
-assert_checkequal(k, kref');
+assert_checkequal(ki, kref');
+assert_checkequal(c(ki,:), u);
+assert_checkequal(u(ko,:), c);
 assert_checkequal(nb,[2 2 1]');
 
-[u,k,?,nb] = unique(c', "c", "keepOrder");
-assert_checkequal(u, c'(:,kref));
-assert_checkequal(k, kref);
-assert_checkequal(nb,[2 2 1]);
-
+c = c.';
+[u,ki,ko,nb] = unique(c, "c", "keepOrder");
+assert_checkequal(u, c(:,kref));
+assert_checkequal(ki, kref);
+assert_checkequal(c(:,ki), u);
+assert_checkequal(u(:,ko), c);
+assert_checkequal(nb, [2 2 1]);
 
 // ==============
 // With some text
@@ -263,9 +432,11 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
     ];
 u = unique(t);
 assert_checkequal(u, ["AA" "AB" "BA" "BB"]');
-[u,k,?,nb] = unique(t);
+[u,ki,ko,nb] = unique(t);
 assert_checkequal(u, ["AA" "AB" "BA" "BB"]');
-assert_checkequal(k, [2 1 3 10]');
+assert_checkequal(ki, [2 1 3 10]');
+assert_checkequal(t(ki), u);
+assert_checkequal(u(ko), t);
 assert_checkequal(nb,[6 10 8 6]');
 
 utc = ["AA"  "AA"  "AB"  "AB"  "AB"  "BA"  "BA"  "BA"  "BB"
@@ -273,34 +444,44 @@ utc = ["AA"  "AA"  "AB"  "AB"  "AB"  "BA"  "BA"  "BA"  "BB"
       ];
 u = unique(t, "c");
 assert_checkequal(u, utc);
-[u,k,?,nb] = unique(t, "c");
+[u,ki,ko,nb] = unique(t, "c");
 assert_checkequal(u, utc);
-assert_checkequal(k, [15 10 1 8 5 2 3 6 9]);
+assert_checkequal(ki, [15 10 1 8 5 2 3 6 9]);
+assert_checkequal(t(:,ki), u);
+assert_checkequal(u(:,ko), t);
 assert_checkequal(nb,[1  1  1 1 3 2 3 2 1]);
 
 u = unique(t', "r");
 assert_checkequal(u, utc');
-[u,k,?,nb] = unique(t', "r");
+[u,ki,ko,nb] = unique(t', "r");
 assert_checkequal(u, utc');
-assert_checkequal(k, [15 10 1 8 5 2 3 6 9]');
+assert_checkequal(ki, [15 10 1 8 5 2 3 6 9]');
+assert_checkequal(t'(ki,:), u);
+assert_checkequal(u(ko,:), t');
 assert_checkequal(nb,[1  1  1 1 3 2 3 2 1]');
 
 // keepOrder
 // ---------
-[u,k,?,nb] = unique(t, "keepOrder");
+[u,ki,ko,nb] = unique(t, "keepOrder");
 assert_checkequal(u, ["AB" "AA" "BA" "BB"]');
-assert_checkequal(k, [1 2 3 10]');
+assert_checkequal(ki, [1 2 3 10]');
+assert_checkequal(t(ki), u);
+assert_checkequal(u(ko), t);
 assert_checkequal(nb,[10 6 8 6]');
 
 utc = ["AB"  "BA"  "BA"  "AB"  "BA"  "AB"  "BB"  "AA"  "AA"
        "AA"  "AA"  "AB"  "BB"  "BB"  "BA"  "AB"  "AB"  "AA"
       ];
-[u,k,?,nb] = unique(t, "c", "keepOrder");
+[u,ki,ko,nb] = unique(t, "c", "keepOrder");
 assert_checkequal(u, utc);
-assert_checkequal(k, [1 2 3 5 6 8 9 10 15]);
+assert_checkequal(ki, [1 2 3 5 6 8 9 10 15]);
+assert_checkequal(t(:,ki), u);
+assert_checkequal(u(:,ko), t);
 assert_checkequal(nb,[1 2 3 3 2 1 1 1  1 ]);
 
-[u,k,?,nb] = unique(t', "r", "keepOrder");
+[u,ki,ko,nb] = unique(t', "r", "keepOrder");
 assert_checkequal(u, utc');
-assert_checkequal(k, [1 2 3 5 6 8 9 10 15]');
+assert_checkequal(ki, [1 2 3 5 6 8 9 10 15]');
+assert_checkequal(t'(ki,:), u);
+assert_checkequal(u(ko,:), t');
 assert_checkequal(nb,[1 2 3 3 2 1 1 1  1 ]');