* Bugs 8418 15522 15795 fixed: unique() upgraded 18/20918/4
Samuel GOUGEON [Tue, 2 Apr 2019 18:23:47 +0000 (20:23 +0200)]
  http://bugzilla.scilab.org/8418
  http://bugzilla.scilab.org/15522
  http://bugzilla.scilab.org/15795

  Page updated (PDF): http://bugzilla.scilab.org/attachment.cgi?id=4927

Change-Id: If6b85f3fa5fe1c5bd948868aacd3da8fc18d3408

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 5fe0c60..2591b72 100644 (file)
@@ -120,6 +120,10 @@ Feature changes and additions
 * `editvar()` GUI support copy-paste of strings removing quotes.
 * calendar() can now display formated calendars.
 * `xmlSetValues()` clones `setPreferencesValue` that is now obsolete.
+* `unique()` is upgraded to:
+  - return the number of occurences of distinct entities found in the input array.
+  - return distinct entities in their initial order (rather than sorted), with the `"keepOrder"` option.
+  - consider all `Nan` values as the same one, with the `"uniqueNan"` option.
 
 
 Help pages:
@@ -176,6 +180,7 @@ Bug Fixes
 * [#7765](http://bugzilla.scilab.org/show_bug.cgi?id=7765): `champ1()` is useless. `champ().colored` is available for a long time.
 * [#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.
 * [#8784](http://bugzilla.scilab.org/show_bug.cgi?id=8784): Automatic self-adjusting blocks `SCALE_CSCOPE` & `SCALE_CMSCOPE` in Xcos.
 * [#5512](http://bugzilla.scilab.org/show_bug.cgi?id=5512): `disp()` puzzlingly displayed arguments in reverse order.
 * [#9529](http://bugzilla.scilab.org/show_bug.cgi?id=9529): `assert_checkequal(list(1,,3), list(1,,3))` yielded an error.
@@ -210,10 +215,12 @@ Bug Fixes
 * [#15425](http://bugzilla.scilab.org/show_bug.cgi?id=15425): The Kronecker product `a.*.b` failed when `a` or `b` or both are hypermatrices, with one or both being polynomials or rationals.
 * [#15451](http://bugzilla.scilab.org/show_bug.cgi?id=15451): The code was not adapted to use `lucene 4.10` in Debian.
 * [#15514](http://bugzilla.scilab.org/show_bug.cgi?id=15514): The `set()` documentation page needed to be overhauled.
+* [#15522](http://bugzilla.scilab.org/show_bug.cgi?id=15522): `unique()` was not able to consider all Nan values as the same value. A `uniqueNan` option now allows it. 
 * [#15523](http://bugzilla.scilab.org/show_bug.cgi?id=15523): `%ODEOPTIONS(1)=2` didn't work with solvers 'rk' and 'rkf'
 * [#15248](http://bugzilla.scilab.org/show_bug.cgi?id=15248): `lsq()`was leaking memory.
 * [#15577](http://bugzilla.scilab.org/show_bug.cgi?id=15577): `edit` did not accept a line number as text, as with `edit linspace 21`.
 * [#15580](http://bugzilla.scilab.org/show_bug.cgi?id=15580): `det(sparse([],[]))` yielded an error.
+* [#15595](http://bugzilla.scilab.org/show_bug.cgi?id=15595): `unique()` was not able to return distinct values in their original order, without sorting them. A `keepOrder` option now allows it. 
 * [#15668](http://bugzilla.scilab.org/show_bug.cgi?id=15668): `save(filename)` saved all predefined Scilab constants %e %pi etc.. (regression)
 * [#15715](http://bugzilla.scilab.org/show_bug.cgi?id=15715): `%nan` indices crashed Scilab.
 * [#15742](http://bugzilla.scilab.org/show_bug.cgi?id=15742): The `compatibility_functions` module should be merged in the `m2sci` one.
@@ -284,3 +291,4 @@ Bug Fixes
 * [#16299](http://bugzilla.scilab.org/show_bug.cgi?id=16299): After `graypolarplot()`, `colorbar()` displayed an empty ungraduated color bar.
 * [#16303](http://bugzilla.scilab.org/show_bug.cgi?id=16303): log10(x) had wrong dimensions when x is an hypermatrix.
 
+
index 341fa59..ed0498c 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2017, 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2017 - 2019 - 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.
     <refsynopsisdiv>
         <title>Syntax</title>
         <synopsis>
-            N = unique(M)
-            N = unique(M, orient)
-            [N, k] = unique(..)
+            [N, k, nb] = unique(M)
+            [N, k, nb] = unique(M, orient)
+            [N, k, nb] = unique(.., "keepOrder")
+            [N, k, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
@@ -36,7 +36,7 @@
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    <para>vector, matrix, or hypermatrix of numbers or strings.</para>
+                    <para>vector, matrix, or hypermatrix of numbers or of strings.</para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                     <para>
                       <itemizedlist>
                         <listitem>
-                          If <varname>orient</varname> is not used: Vector of extracted
-                          <varname>M</varname> components sorted in ascending order.
+                            <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 a row vector. In all other <varname>M</varname> cases,
+                                <varname>N</varname> is a matrix or a column vector.
+                            </para>
                         </listitem>
                         <listitem>
                           If <varname>orient</varname> is used: Matrix of extracted
                       <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>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>nb</term>
+                <listitem>
+                    <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>.
+                    </para>
                 </listitem>
             </varlistentry>
         </variablelist>
             duplicates of <varname>M</varname> columns and returns unique columns in lexicographic
             ascending order.
         </para>
-        <note>
-          Extracted components, rows or columns can be resorted in their initial order by sorting
-          <varname>k</varname>. See the first example.
-        </note>
+        <para>
+            <literal>unique(M,.. "keepOrder")</literal> returns <varname>M</varname> unduplicated
+            entries in their original order in <varname>M</varname>.
+            <literal>"keepOrder"</literal> is case-insensitive.
+        </para>
+        <para>
+            <literal>unique(M,.. "uniqueNan")</literal> considers all Nan values as the same one,
+            and unduplicates them. By default, any Nan is different
+            from any other Nan, including itself: <literal>%nan&lt;>%nan</literal> is true, unless
+            <literal>"uniqueNan"</literal> is used. Specifying
+            <literal>"uniqueNan"</literal> is case-insensitive.
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Examples</title>
@@ -112,8 +139,8 @@ M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
 M(:, gsort(kc,"g","i"))
  ]]></programlisting>
     <screen><![CDATA[
---> M 
- M = 
+--> M
+ M =
   2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
   0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
 
@@ -142,6 +169,7 @@ M(:, gsort(kc,"g","i"))
   2  0  2  1  1  0  1  0
   0  1  2  1  2  2  0  0
 ]]></screen>
+        <para/>
         <para>With complex numbers:</para>
         <programlisting role="example"><![CDATA[
 i = %i;
@@ -161,40 +189,115 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
  k  =
    3.   4.   2.   1.
 ]]></screen>
-
-    <para>With some texts:</para>
+        <para/>
+        <para>With some texts:</para>
         <programlisting role="example"><![CDATA[
-t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
-     "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+     "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ]
-[u, k] = unique(t)
-[uc, kc] = unique(t, "c")
+u = unique(t)'
+[u, k, nb] = unique(t(1,:))
+[u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[uc, kc, nb] = unique(t, "c")
+[uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
  ]]></programlisting>
     <screen><![CDATA[
+--> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+  >      "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+  >     ]
  t  =
-!AB  BA  BA  BA  AB  BA  AB  AB  BB  AA  AB  BA  BA  BA  AA  !
-!AA  AA  AB  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+!BA  BB  AB  BA  AB  BA  AB  AB  BA  AA  AB  BA  BA  BA  AA  !
+!AA  AB  AA  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
 
---> [u, k] = unique(t);
+--> u = unique(t)'
  u  =
-!AA  !
-!AB  !
-!BA  !
-!BB  !
+!AA  AB  BA  BB  !
+
+--> [u, k, nb] = unique(t(1,:))
+ u  =
+!AA  AB  BA  BB  !
 
  k  =
-   2.
-   1.
-   3.
-   10.
+   10.   3.   1.   2.
+
+ nb  =
+   2.   5.   7.   1.
+
+--> [u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order
+ u  =
+!BA  BB  AB  AA  !
+
+ k  =
+   1.   2.   3.   10.
+
+--> [uc, kc, nb] = unique(t, "c")
+ nb  =
+   1.   1.   1.   1.   3.   2.   3.   2.   1.
+
+ kc  =
+   15.   10.   3.   8.   5.   1.   9.   6.   2.
 
---> [uc, kc] = unique(t, "c")
  uc  =
-!AA  AA  AB  AB  AB  BA  BA  BA  BB  !
+!AA  AA  AB  AB  AB  BA  BA  BA  BB  !             Sorted columns
 !AA  AB  AA  BA  BB  AA  AB  BB  AB  !
 
+--> [uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order
+ uc  =
+!BA  BB  AB  AB  BA  AB  BA  AA  AA  !
+!AA  AB  AA  BB  BB  BA  AB  AB  AA  !
+
  kc  =
-   15.   10.   1.   8.   5.   2.   3.   6.   9.
+   1.   2.   3.   5.   6.   8.   9.   10.   15.
+
+ nb  =
+   2.   1.   1.   3.   2.   1.   3.   1.   1.
+]]></screen>
+        <para/>
+        <para>With Nan (and Inf) values. "uniqueNan" option:</para>
+        <programlisting role="example"><![CDATA[
+M = [2  2  %nan  1     2  0     1  %nan  0    %nan
+     1  0  1     %nan  0  %inf  0  1     %inf 1
+    ];
+[v,k,n] = unique(M); v',n'
+[v,k,n] = unique(M, "uniqueNan"); v',n'
+unique(M, "c")
+[v, k, n] = unique(M, "c", "uniqueNan")
+ ]]></programlisting>
+    <screen><![CDATA[
+--> M
+ M  =
+   2.   2.   Nan   1.    2.   0.    1.   Nan   0.    Nan
+   1.   0.   1.    Nan   0.   Inf   0.   1.    Inf   1.
+
+--> [v,k,n] = unique(M); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan   Nan   Nan   Nan
+
+ ans  =
+   5.   6.   3.   2.   1.   1.   1.   1.
+
+--> [v,k,n] = unique(M, "uniqueNan"); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan
+
+ ans  =
+   5.   6.   3.   2.   4.
+
+--> unique(M, "c")
+ ans  =
+   0.    1.   1.    2.   2.   Nan   Nan   Nan
+   Inf   0.   Nan   0.   1.   1.    1.    1.
+
+--> [v, k, n] = unique(M, "c", "uniqueNan")
+ v  =
+   0.    1.   1.    2.   2.   Nan
+   Inf   0.   Nan   0.   1.   1.
+
+ k  =
+   6.   7.   4.   2.   1.   3.
+
+ n  =
+   2.   1.   1.   2.   1.   3.
 ]]></screen>
     </refsection>
     <refsection role="see also">
@@ -229,6 +332,19 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
                     unique() can now be used to unduplicate complex numbers.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            "keepOrder" and "uniqueNan" options introduced.
+                        </listitem>
+                        <listitem>
+                            Third output argument <literal>nb</literal> introduced.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index e00d599..746ead1 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2017, 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2017 - 2019 - 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.
     <refsynopsisdiv>
         <title>Séquence d'appel</title>
         <synopsis>
-            N = unique(M)
-            N = unique(M, orient)
-            [N, k] = unique(..)
+            [N, k, nb] = unique(M)
+            [N, k, nb] = unique(M, orient)
+            [N, k, nb] = unique(.., "keepOrder")
+            [N, k, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
             <varlistentry>
                 <term>M</term>
                 <listitem>
-                    <para>vecteur, matrice, ou hypermatrice de nombres ou de textes.
+                    <para>
+                        vecteur, matrice, ou hypermatrice de nombres ou de textes.
                     </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>orient</term>
                 <listitem>
-                    <para>1 ou "r", 2 ou "c". Ne peut pas être utilisé si <varname>M</varname>
-                        est une hypermatrice.
+                    <para>
+                        1 ou "r", 2 ou "c". Ne peut pas être utilisé si <varname>M</varname> est
+                        une hypermatrice.
                     </para>
                 </listitem>
             </varlistentry>
                     <para>
                       <itemizedlist>
                         <listitem>
-                          Sans <varname>orient</varname>: vecteur d'éléments de <varname>M</varname>
-                          triés par ordre croissant.
+                            <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.
+                            </para>
                         </listitem>
                         <listitem>
-                          Avec <varname>orient</varname>: Matrice de lignes ou colonnes extraites de
-                          <varname>M</varname>, triées par ordre lexicographique croissant.
+                          Avec <varname>orient</varname>: Matrice de lignes ou de colonnes extraites
+                          de <varname>M</varname>, triées par ordre lexicographique croissant.
                         </listitem>
                       </itemizedlist>
                     </para>
                       <literal>N(i) = M(k(i))</literal> ou <literal>N(i,:) = M(k(i),:)</literal>
                       ou <literal>N(:,i) = M(:,k(i))</literal>.
                     </para>
+                    <para>
+                        <varname>k</varname> est un vecteur ligne si <varname>M</varname>
+                        l'est aussi ou si <literal>orient="c"</literal> est utilisé.
+                        Sinon <varname>k</varname> est en colonne.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>nb</term>
+                <listitem>
+                    <para>
+                      Vecteur d'entiers > 0, au format de <varname>k</varname> :
+                      nombres d'exemplaires dans <varname>M</varname> de chaque entité
+                      (élément, ligne, colonne) retournée dans <varname>N</varname>.
+                    </para>
                 </listitem>
             </varlistentry>
         </variablelist>
             <literal>unique(M,2)</literal>retourne les colonnes uniques
             <literal>M</literal> triées dans l'ordre lexicographique croissant.
         </para>
-        <note>
-          Les éléments, lignes ou colonnes extraits peuvent être remis dans leur ordre initial en
-          triant <varname>k</varname>. Voir le 1er exemple.
-        </note>
+        <para>
+            <literal>unique(M,.. "keepOrder")</literal> donne le vecteur des valeurs distinctes
+            de <varname>M</varname> selon leur ordre initial d'apparition dans <varname>M</varname>
+            (au lieu d'être par défaut triées par ordre croissant). L'indicateur
+            <literal>"keepOrder"</literal> est insensible aux minuscules/majuscules.
+        </para>
+        <para>
+            <literal>unique(M,.. "uniqueNan")</literal> considère toute valeur Nan comme égale
+            à toute autre Nan, et les dédoublonne comme pour n'importe quelle autre valeur numérique.
+            Par défaut, toute valeur Nan est distincte de toute autre Nan, y compris elle-même :
+            <literal>%nan&lt;>%nan</literal> est vrai, à moins d'utiliser
+            <literal>"uniqueNan"</literal>. L'indicateur
+            <literal>"uniqueNan"</literal> est insensible aux minuscules/majuscules.
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Exemples</title>
@@ -114,8 +146,8 @@ M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
 M(:, gsort(kc,"g","i"))
  ]]></programlisting>
     <screen><![CDATA[
---> M 
- M = 
+--> M
+ M =
   2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
   0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
 
@@ -166,37 +198,112 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
 
     <para>Dédoublonnement de textes :</para>
         <programlisting role="example"><![CDATA[
-t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
-     "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+     "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ]
-[u, k] = unique(t)
-[uc, kc] = unique(t, "c")
+u = unique(t)'
+[u, k, nb] = unique(t(1,:))
+[u, k] = unique(t(1,:), "keepOrder")        // ordre initial conservé
+[uc, kc, nb] = unique(t, "c")
+[uc, kc, nb] = unique(t, "c", "keepOrder")  // ordre initial des colonnes conservé
  ]]></programlisting>
     <screen><![CDATA[
+--> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+  >      "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+  >     ]
  t  =
-!AB  BA  BA  BA  AB  BA  AB  AB  BB  AA  AB  BA  BA  BA  AA  !
-!AA  AA  AB  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+!BA  BB  AB  BA  AB  BA  AB  AB  BA  AA  AB  BA  BA  BA  AA  !
+!AA  AB  AA  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+
+--> u = unique(t)'
+ u  =
+!AA  AB  BA  BB  !
 
---> [u, k] = unique(t);
+--> [u, k, nb] = unique(t(1,:))
  u  =
-!AA  !
-!AB  !
-!BA  !
-!BB  !
+!AA  AB  BA  BB  !
 
  k  =
-   2.
-   1.
-   3.
-   10.
+   10.   3.   1.   2.
+
+ nb  =
+   2.   5.   7.   1.
+
+--> [u, k] = unique(t(1,:), "keepOrder")  // ordre initial conservé
+ u  =
+!BA  BB  AB  AA  !
+
+ k  =
+   1.   2.   3.   10.
+
+--> [uc, kc, nb] = unique(t, "c")
+ nb  =
+   1.   1.   1.   1.   3.   2.   3.   2.   1.
+
+ kc  =
+   15.   10.   3.   8.   5.   1.   9.   6.   2.
 
---> [uc, kc] = unique(t, "c")
  uc  =
-!AA  AA  AB  AB  AB  BA  BA  BA  BB  !
+!AA  AA  AB  AB  AB  BA  BA  BA  BB  !             colonnes triées
 !AA  AB  AA  BA  BB  AA  AB  BB  AB  !
 
+--> [uc, kc, nb] = unique(t, "c", "keepOrder")  // ordre initial des colonnes conservé
+ uc  =
+!BA  BB  AB  AB  BA  AB  BA  AA  AA  !
+!AA  AB  AA  BB  BB  BA  AB  AB  AA  !
+
  kc  =
-   15.   10.   1.   8.   5.   2.   3.   6.   9.
+   1.   2.   3.   5.   6.   8.   9.   10.   15.
+
+ nb  =
+   2.   1.   1.   3.   2.   1.   3.   1.   1.
+]]></screen>
+        <para/>
+        <para>Avec des valeurs Nan (et Inf). Option "uniqueNan" :</para>
+        <programlisting role="example"><![CDATA[
+M = [2  2  %nan  1     2  0     1  %nan  0    %nan
+     1  0  1     %nan  0  %inf  0  1     %inf 1
+    ];
+[v,k,n] = unique(M); v',n'
+[v,k,n] = unique(M, "uniqueNan"); v',n'
+unique(M, "c")
+[v, k, n] = unique(M, "c", "uniqueNan")
+ ]]></programlisting>
+    <screen><![CDATA[
+--> M
+ M  =
+   2.   2.   Nan   1.    2.   0.    1.   Nan   0.    Nan
+   1.   0.   1.    Nan   0.   Inf   0.   1.    Inf   1.
+
+--> [v,k,n] = unique(M); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan   Nan   Nan   Nan
+
+ ans  =
+   5.   6.   3.   2.   1.   1.   1.   1.
+
+--> [v,k,n] = unique(M, "uniqueNan"); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan
+
+ ans  =
+   5.   6.   3.   2.   4.
+
+--> unique(M, "c")
+ ans  =
+   0.    1.   1.    2.   2.   Nan   Nan   Nan
+   Inf   0.   Nan   0.   1.   1.    1.    1.
+
+--> [v, k, n] = unique(M, "c", "uniqueNan")
+ v  =
+   0.    1.   1.    2.   2.   Nan
+   Inf   0.   Nan   0.   1.   1.
+
+ k  =
+   6.   7.   4.   2.   1.   3.
+
+ n  =
+   2.   1.   1.   2.   1.   3.
 ]]></screen>
     </refsection>
     <refsection role="see also">
@@ -231,6 +338,19 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
                     unique() peut maintenant être utilisée pour dédoublonner des nombres complexes.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            Options "keepOrder" et "uniqueNan" ajoutées.
+                        </listitem>
+                        <listitem>
+                            3ème résultat <literal>nb</literal> ajouté.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index d6cc82c..a8398ac 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2017, 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2017 - 2019 - 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.
     <refsynopsisdiv>
         <title>呼び出し手順</title>
         <synopsis>
-            N = unique(M)
-            N = unique(M, orient)
-            [N, k] = unique(..)
+            [N, k, nb] = unique(M)
+            [N, k, nb] = unique(M, orient)
+            [N, k, nb] = unique(.., "keepOrder")
+            [N, k, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
                     <para>
                       <itemizedlist>
                         <listitem>
-                          If <varname>orient</varname> is not used: Vector of extracted
-                          <varname>M</varname> components sorted in ascending order.
+                            <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
+                              a row vector. In all other <varname>M</varname> cases,
+                              <varname>N</varname> is a matrix or a column vector.
+                            </para>
                         </listitem>
                         <listitem>
                           If <varname>orient</varname> is used: Matrix of extracted
                       <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>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>nb</term>
+                <listitem>
+                    <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>.
+                    </para>
                 </listitem>
             </varlistentry>
         </variablelist>
             <literal>M</literal>のユニークな列を
             辞書式の昇順にして返します.
         </para>
-        <note>
-          Extracted components, rows or columns can be resorted in their initial order by sorting
-          <varname>k</varname>. See the first example.
-        </note>
+        <para>
+            <literal>unique(M,.. "keepOrder")</literal> returns <varname>M</varname> unduplicated
+            entries in their original order in <varname>M</varname>.
+            <literal>"keepOrder"</literal> is case-insensitive.
+        </para>
+        <para>
+            <literal>unique(M,.. "uniqueNan")</literal> considers all Nan values as the same one,
+            and unduplicates them. By default, any Nan is different
+            from any other Nan, including itself: <literal>%nan&lt;>%nan</literal> is true, unless
+            <literal>"uniqueNan"</literal> is used. Specifying
+            <literal>"uniqueNan"</literal> is case-insensitive.
+        </para>
     </refsection>
     <refsection role="examples">
         <title>例</title>
@@ -114,8 +141,8 @@ M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
 M(:, gsort(kc,"g","i"))
  ]]></programlisting>
     <screen><![CDATA[
---> M 
- M = 
+--> M
+ M =
   2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
   0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
 
@@ -166,37 +193,112 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
 
     <para>With some texts:</para>
         <programlisting role="example"><![CDATA[
-t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
-     "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+     "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ]
-[u, k] = unique(t)
-[uc, kc] = unique(t, "c")
+u = unique(t)'
+[u, k, nb] = unique(t(1,:))
+[u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[uc, kc, nb] = unique(t, "c")
+[uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
  ]]></programlisting>
     <screen><![CDATA[
+--> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+  >      "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+  >     ]
  t  =
-!AB  BA  BA  BA  AB  BA  AB  AB  BB  AA  AB  BA  BA  BA  AA  !
-!AA  AA  AB  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+!BA  BB  AB  BA  AB  BA  AB  AB  BA  AA  AB  BA  BA  BA  AA  !
+!AA  AB  AA  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
 
---> [u, k] = unique(t);
+--> u = unique(t)'
  u  =
-!AA  !
-!AB  !
-!BA  !
-!BB  !
+!AA  AB  BA  BB  !
+
+--> [u, k, nb] = unique(t(1,:))
+ u  =
+!AA  AB  BA  BB  !
 
  k  =
-   2.
-   1.
-   3.
-   10.
+   10.   3.   1.   2.
+
+ nb  =
+   2.   5.   7.   1.
+
+--> [u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order
+ u  =
+!BA  BB  AB  AA  !
+
+ k  =
+   1.   2.   3.   10.
+
+--> [uc, kc, nb] = unique(t, "c")
+ nb  =
+   1.   1.   1.   1.   3.   2.   3.   2.   1.
+
+ kc  =
+   15.   10.   3.   8.   5.   1.   9.   6.   2.
 
---> [uc, kc] = unique(t, "c")
  uc  =
-!AA  AA  AB  AB  AB  BA  BA  BA  BB  !
+!AA  AA  AB  AB  AB  BA  BA  BA  BB  !             Sorted columns
 !AA  AB  AA  BA  BB  AA  AB  BB  AB  !
 
+--> [uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order
+ uc  =
+!BA  BB  AB  AB  BA  AB  BA  AA  AA  !
+!AA  AB  AA  BB  BB  BA  AB  AB  AA  !
+
  kc  =
-   15.   10.   1.   8.   5.   2.   3.   6.   9.
+   1.   2.   3.   5.   6.   8.   9.   10.   15.
+
+ nb  =
+   2.   1.   1.   3.   2.   1.   3.   1.   1.
+]]></screen>
+        <para/>
+        <para>With Nan (and Inf) values. "uniqueNan" option:</para>
+        <programlisting role="example"><![CDATA[
+M = [2  2  %nan  1     2  0     1  %nan  0    %nan
+     1  0  1     %nan  0  %inf  0  1     %inf 1
+    ];
+[v,k,n] = unique(M); v',n'
+[v,k,n] = unique(M, "uniqueNan"); v',n'
+unique(M, "c")
+[v, k, n] = unique(M, "c", "uniqueNan")
+ ]]></programlisting>
+    <screen><![CDATA[
+--> M
+ M  =
+   2.   2.   Nan   1.    2.   0.    1.   Nan   0.    Nan
+   1.   0.   1.    Nan   0.   Inf   0.   1.    Inf   1.
+
+--> [v,k,n] = unique(M); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan   Nan   Nan   Nan
+
+ ans  =
+   5.   6.   3.   2.   1.   1.   1.   1.
+
+--> [v,k,n] = unique(M, "uniqueNan"); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan
+
+ ans  =
+   5.   6.   3.   2.   4.
+
+--> unique(M, "c")
+ ans  =
+   0.    1.   1.    2.   2.   Nan   Nan   Nan
+   Inf   0.   Nan   0.   1.   1.    1.    1.
+
+--> [v, k, n] = unique(M, "c", "uniqueNan")
+ v  =
+   0.    1.   1.    2.   2.   Nan
+   Inf   0.   Nan   0.   1.   1.
+
+ k  =
+   6.   7.   4.   2.   1.   3.
+
+ n  =
+   2.   1.   1.   2.   1.   3.
 ]]></screen>
     </refsection>
     <refsection role="see also">
@@ -231,6 +333,19 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
                     unique() can now be used to unduplicate complex numbers.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            "keepOrder" and "uniqueNan" options introduced.
+                        </listitem>
+                        <listitem>
+                            Third output argument <literal>nb</literal> introduced.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
\ No newline at end of file
index aab2cf4..a8d164a 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2017, 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2017 - 2019 - 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.
     <refsynopsisdiv>
         <title>Seqüência de Chamamento</title>
         <synopsis>
-            N = unique(M)
-            N = unique(M, orient)
-            [N, k] = unique(..)
+            [N, k, nb] = unique(M)
+            [N, k, nb] = unique(M, orient)
+            [N, k, nb] = unique(.., "keepOrder")
+            [N, k, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
                     <para>
                       <itemizedlist>
                         <listitem>
-                          If <varname>orient</varname> is not used: Vector of extracted
-                          <varname>M</varname> components sorted in ascending order.
+                            <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
+                            a row vector. In all other <varname>M</varname> cases,
+                            <varname>N</varname> is a matrix or a column vector.
+                            </para>
                         </listitem>
                         <listitem>
                           If <varname>orient</varname> is used: Matrix of extracted
                       <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>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>nb</term>
+                <listitem>
+                    <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>.
+                    </para>
                 </listitem>
             </varlistentry>
         </variablelist>
             <literal>unique(M,2)</literal>retorna as linhas únicas de
             <literal>M</literal> em ordem lexicográfica ascendente.
         </para>
-        <note>
-          Extracted components, rows or columns can be resorted in their initial order by sorting
-          <varname>k</varname>. See the first example.
-        </note>
+        <para>
+            <literal>unique(M,.. "keepOrder")</literal> returns <varname>M</varname> unduplicated
+            entries in their original order in <varname>M</varname>.
+            <literal>"keepOrder"</literal> is case-insensitive.
+        </para>
+        <para>
+            <literal>unique(M,.. "uniqueNan")</literal> considers all Nan values as the same one,
+            and unduplicates them. By default, any Nan is different
+            from any other Nan, including itself: <literal>%nan&lt;>%nan</literal> is true, unless
+            <literal>"uniqueNan"</literal> is used. Specifying
+            <literal>"uniqueNan"</literal> is case-insensitive.
+        </para>
     </refsection>
     <refsection role="description">
         <title>Exemplos</title>
@@ -112,8 +139,8 @@ M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
 M(:, gsort(kc,"g","i"))
  ]]></programlisting>
     <screen><![CDATA[
---> M 
- M = 
+--> M
+ M =
   2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
   0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
 
@@ -164,37 +191,112 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
 
     <para>With some texts:</para>
         <programlisting role="example"><![CDATA[
-t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
-     "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+     "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ]
-[u, k] = unique(t)
-[uc, kc] = unique(t, "c")
+u = unique(t)'
+[u, k, nb] = unique(t(1,:))
+[u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order of row#1 elements
+[uc, kc, nb] = unique(t, "c")
+[uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order of columns
  ]]></programlisting>
     <screen><![CDATA[
+--> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+  >      "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+  >     ]
  t  =
-!AB  BA  BA  BA  AB  BA  AB  AB  BB  AA  AB  BA  BA  BA  AA  !
-!AA  AA  AB  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+!BA  BB  AB  BA  AB  BA  AB  AB  BA  AA  AB  BA  BA  BA  AA  !
+!AA  AB  AA  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
 
---> [u, k] = unique(t);
+--> u = unique(t)'
  u  =
-!AA  !
-!AB  !
-!BA  !
-!BB  !
+!AA  AB  BA  BB  !
+
+--> [u, k, nb] = unique(t(1,:))
+ u  =
+!AA  AB  BA  BB  !
 
  k  =
-   2.
-   1.
-   3.
-   10.
+   10.   3.   1.   2.
+
+ nb  =
+   2.   5.   7.   1.
+
+--> [u, k] = unique(t(1,:), "keepOrder")  // Keeping the original order
+ u  =
+!BA  BB  AB  AA  !
+
+ k  =
+   1.   2.   3.   10.
+
+--> [uc, kc, nb] = unique(t, "c")
+ nb  =
+   1.   1.   1.   1.   3.   2.   3.   2.   1.
+
+ kc  =
+   15.   10.   3.   8.   5.   1.   9.   6.   2.
 
---> [uc, kc] = unique(t, "c")
  uc  =
-!AA  AA  AB  AB  AB  BA  BA  BA  BB  !
+!AA  AA  AB  AB  AB  BA  BA  BA  BB  !             Sorted columns
 !AA  AB  AA  BA  BB  AA  AB  BB  AB  !
 
+--> [uc, kc, nb] = unique(t, "c", "keepOrder")  // Keeping the original order
+ uc  =
+!BA  BB  AB  AB  BA  AB  BA  AA  AA  !
+!AA  AB  AA  BB  BB  BA  AB  AB  AA  !
+
  kc  =
-   15.   10.   1.   8.   5.   2.   3.   6.   9.
+   1.   2.   3.   5.   6.   8.   9.   10.   15.
+
+ nb  =
+   2.   1.   1.   3.   2.   1.   3.   1.   1.
+]]></screen>
+        <para/>
+        <para>With Nan (and Inf) values. "uniqueNan" option:</para>
+        <programlisting role="example"><![CDATA[
+M = [2  2  %nan  1     2  0     1  %nan  0    %nan
+     1  0  1     %nan  0  %inf  0  1     %inf 1
+    ];
+[v,k,n] = unique(M); v',n'
+[v,k,n] = unique(M, "uniqueNan"); v',n'
+unique(M, "c")
+[v, k, n] = unique(M, "c", "uniqueNan")
+ ]]></programlisting>
+    <screen><![CDATA[
+--> M
+ M  =
+   2.   2.   Nan   1.    2.   0.    1.   Nan   0.    Nan
+   1.   0.   1.    Nan   0.   Inf   0.   1.    Inf   1.
+
+--> [v,k,n] = unique(M); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan   Nan   Nan   Nan
+
+ ans  =
+   5.   6.   3.   2.   1.   1.   1.   1.
+
+--> [v,k,n] = unique(M, "uniqueNan"); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan
+
+ ans  =
+   5.   6.   3.   2.   4.
+
+--> unique(M, "c")
+ ans  =
+   0.    1.   1.    2.   2.   Nan   Nan   Nan
+   Inf   0.   Nan   0.   1.   1.    1.    1.
+
+--> [v, k, n] = unique(M, "c", "uniqueNan")
+ v  =
+   0.    1.   1.    2.   2.   Nan
+   Inf   0.   Nan   0.   1.   1.
+
+ k  =
+   6.   7.   4.   2.   1.   3.
+
+ n  =
+   2.   1.   1.   2.   1.   3.
 ]]></screen>
     </refsection>
     <refsection role="see also">
@@ -229,6 +331,19 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
                     unique() can now be used to unduplicate complex numbers.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            "keepOrder" and "uniqueNan" options introduced.
+                        </listitem>
+                        <listitem>
+                            Third output argument <literal>nb</literal> introduced.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index d818f66..a995870 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2008 - INRIA
- * Copyright (C) 2017, 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2017 - 2019 - 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.
     <refsynopsisdiv>
         <title>Синтаксис</title>
         <synopsis>
-            N = unique(M)
-            N = unique(M, orient)
-            [N, k] = unique(..)
+            [N, k, nb] = unique(M)
+            [N, k, nb] = unique(M, orient)
+            [N, k, nb] = unique(.., "keepOrder")
+            [N, k, nb] = unique(.., "uniqueNan")
         </synopsis>
     </refsynopsisdiv>
     <refsection role="parameters">
                     <para>
                       <itemizedlist>
                         <listitem>
-                          Если <varname>orient</varname> не используется: вектор извлечённых
-                          <varname>M</varname> компонентов, сортированных в полядке возрастания.
+                            <para>
+                              Если <varname>orient</varname> не используется: вектор извлечённых
+                              <varname>M</varname> компонентов, сортированных в полядке возрастания.
+                              Если <varname>M</varname> является вектором-строкой, то <varname>N</varname>
+                              так же является вектором-строкой. В случаях всех иных <varname>M</varname>
+                              <varname>N</varname> является матрицей или вектором-столбцом.
+                            </para>
                         </listitem>
                         <listitem>
                           Если <varname>orient</varname> используется: матрица извлечённых
-                          <varname>M</varname> строк или столбцов, сортированных в лексикографическом порядке возрастания.
+                          <varname>M</varname> строк или столбцов, сортированных в лексикографическом
+                          порядке возрастания.
                         </listitem>
                       </itemizedlist>
                     </para>
                       <literal>N(i) = M(k(i))</literal> или <literal>N(i,:) = M(k(i),:)</literal>
                       или <literal>N(:,i) = M(:,k(i))</literal>.
                     </para>
+                    <para>
+                        <varname>k</varname> является строкой, если <varname>M</varname> является
+                        строкой или если используется <literal>orient="c"</literal>. В проитвном случае
+                        это столбец.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>nb</term>
+                <listitem>
+                    <para>
+                      Вектор целых чисел > 0 той же формы, что и <varname>k</varname>:
+                      количество случаев <varname>M</varname> соответствующих непродублированных элементов
+                      (компоентов, строк, столбцов) возвращаемых в <varname>N</varname>.
+                    </para>
                 </listitem>
             </varlistentry>
         </variablelist>
             <literal>unique(M,"c")</literal> или <literal>unique(M,2)</literal> возвращает
             уникальные столбцы <literal>M</literal> в лексикографическом порядке возрастания.
         </para>
-        <note>
-          Извлечённые компоненты, строки или столбцы могут быть пересортированны в их исходном порядке через
-          сортировку с помощью <varname>k</varname>. См. первый пример.
-        </note>
+        <para>
+            <literal>unique(M,.. "keepOrder")</literal> возвращает <varname>M</varname> недублированных
+            входов в их исходном порядке в <varname>M</varname>.  <literal>"keepOrder"</literal> нечувствителен
+            к регистру.
+        </para>
+        <para>
+            <literal>unique(M,.. "uniqueNan")</literal> принимает все значения Nan одинаковыми и не дублирует их.
+            По умолчанию любой Nan отличается от другого Nan включая себя самого: <literal>%nan&lt;>%nan</literal>
+            равен истине, пока не будет использоваться <literal>"uniqueNan"</literal>. Определение
+            <literal>"uniqueNan"</literal> нечувствительно к регистру.
+        </para>
     </refsection>
     <refsection role="examples">
         <title>Примеры</title>
-        <para>With some numbers:</para>
+        <para>С некотороми числами:</para>
         <programlisting role="example"><![CDATA[
 M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
           0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
@@ -109,8 +137,8 @@ M = int8([2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
 M(:, gsort(kc,"g","i"))
  ]]></programlisting>
     <screen><![CDATA[
---> M 
- M = 
+--> M
+ M =
   2  0  2  2  1  1  1  2  1  1  0  1  1  0  1  1
   0  1  2  0  1  2  2  0  1  1  2  0  1  0  0  0
 
@@ -161,37 +189,112 @@ c = [1+i, 1-i, -i, i, -i, 1+i]
 
     <para>С текстом:</para>
         <programlisting role="example"><![CDATA[
-t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
-     "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+     "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ]
-[u, k] = unique(t)
-[uc, kc] = unique(t, "c")
+u = unique(t)'
+[u, k, nb] = unique(t(1,:))
+[u, k] = unique(t(1,:), "keepOrder")  // сохранение исходного порядка элементов строки №1
+[uc, kc, nb] = unique(t, "c")
+[uc, kc, nb] = unique(t, "c", "keepOrder")  // сохранение исходного порядка столбцов
  ]]></programlisting>
     <screen><![CDATA[
+--> t = ["BA" "BB" "AB" "BA" "AB" "BA" "AB" "AB" "BA" "AA" "AB" "BA" "BA" "BA" "AA"
+  >      "AA" "AB" "AA" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
+  >     ]
  t  =
-!AB  BA  BA  BA  AB  BA  AB  AB  BB  AA  AB  BA  BA  BA  AA  !
-!AA  AA  AB  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
+!BA  BB  AB  BA  AB  BA  AB  AB  BA  AA  AB  BA  BA  BA  AA  !
+!AA  AB  AA  AA  BB  BB  BB  BA  AB  AB  BB  BB  AB  AB  AA  !
 
---> [u, k] = unique(t);
+--> u = unique(t)'
  u  =
-!AA  !
-!AB  !
-!BA  !
-!BB  !
+!AA  AB  BA  BB  !
+
+--> [u, k, nb] = unique(t(1,:))
+ u  =
+!AA  AB  BA  BB  !
 
  k  =
-   2.
-   1.
-   3.
-   10.
+   10.   3.   1.   2.
+
+ nb  =
+   2.   5.   7.   1.
+
+--> [u, k] = unique(t(1,:), "keepOrder")  // сохранение исходного порядка
+ u  =
+!BA  BB  AB  AA  !
+
+ k  =
+   1.   2.   3.   10.
+
+--> [uc, kc, nb] = unique(t, "c")
+ nb  =
+   1.   1.   1.   1.   3.   2.   3.   2.   1.
+
+ kc  =
+   15.   10.   3.   8.   5.   1.   9.   6.   2.
 
---> [uc, kc] = unique(t, "c")
  uc  =
-!AA  AA  AB  AB  AB  BA  BA  BA  BB  !
+!AA  AA  AB  AB  AB  BA  BA  BA  BB  !             сортированные столбцы
 !AA  AB  AA  BA  BB  AA  AB  BB  AB  !
 
+--> [uc, kc, nb] = unique(t, "c", "keepOrder")  // сохранение исходного порядка
+ uc  =
+!BA  BB  AB  AB  BA  AB  BA  AA  AA  !
+!AA  AB  AA  BB  BB  BA  AB  AB  AA  !
+
  kc  =
-   15.   10.   1.   8.   5.   2.   3.   6.   9.
+   1.   2.   3.   5.   6.   8.   9.   10.   15.
+
+ nb  =
+   2.   1.   1.   3.   2.   1.   3.   1.   1.
+]]></screen>
+        <para/>
+        <para>Со значениями Nan (и Inf). Опция "uniqueNan":</para>
+        <programlisting role="example"><![CDATA[
+M = [2  2  %nan  1     2  0     1  %nan  0    %nan
+     1  0  1     %nan  0  %inf  0  1     %inf 1
+    ];
+[v,k,n] = unique(M); v',n'
+[v,k,n] = unique(M, "uniqueNan"); v',n'
+unique(M, "c")
+[v, k, n] = unique(M, "c", "uniqueNan")
+ ]]></programlisting>
+    <screen><![CDATA[
+--> M
+ M  =
+   2.   2.   Nan   1.    2.   0.    1.   Nan   0.    Nan
+   1.   0.   1.    Nan   0.   Inf   0.   1.    Inf   1.
+
+--> [v,k,n] = unique(M); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan   Nan   Nan   Nan
+
+ ans  =
+   5.   6.   3.   2.   1.   1.   1.   1.
+
+--> [v,k,n] = unique(M, "uniqueNan"); v',n'
+ ans  =
+   0.   1.   2.   Inf   Nan
+
+ ans  =
+   5.   6.   3.   2.   4.
+
+--> unique(M, "c")
+ ans  =
+   0.    1.   1.    2.   2.   Nan   Nan   Nan
+   Inf   0.   Nan   0.   1.   1.    1.    1.
+
+--> [v, k, n] = unique(M, "c", "uniqueNan")
+ v  =
+   0.    1.   1.    2.   2.   Nan
+   Inf   0.   Nan   0.   1.   1.
+
+ k  =
+   6.   7.   4.   2.   1.   3.
+
+ n  =
+   2.   1.   1.   2.   1.   3.
 ]]></screen>
     </refsection>
     <refsection role="see also">
@@ -226,6 +329,19 @@ t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
                     unique() теперь может использоваться для удаления дубликатов комплексных чисел.
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            Введены опции "keepOrder" и "uniqueNan".
+                        </listitem>
+                        <listitem>
+                            Введён третий выходной аргумент <literal>nb</literal>.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
index f18fe63..45c3f70 100644 (file)
@@ -1,8 +1,7 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) INRIA
-// Copyright (C) 2018 - Samuel GOUGEON
-//
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2018, 2019 - 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 [x,k]=unique(x,orient)
+function [x, k, nb] = unique(x, varargin)
     // extract unique components of a vector
+    // varargin : orient=1|2|"r"|"c", "uniqueNan", "keepOrder"
+    //
+    // History:
+    // * 2019 - S. Gougeon :
+    //   - 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
+
+    keepOrder = %f
+    uniqueNan = %f
+    orient = "*"
+    newInf = [] // init Inf substitute in case of "uniqueNan" and or(x==%inf)
+    k = []
+    nb = []
+
+    // CHECKING INPUT ARGUMENTS
+    // ------------------------
+    in = varargin
+    i = 2;  // index of the current input argument
+    if size(in)>0 then
+        a = in(1)
+        if typeof(a)=="string"
+            a = convstr(a)
+        end
+        select a
+        case 1
+            orient = "r"
+        case 2
+            orient = "c"
+        case "uniquenan"
+            uniqueNan = %t
+        case "keeporder"
+            keepOrder = %t
+        case "r"
+            orient = "r"
+        case "c"
+            orient = "c"
+        else
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "unique", i, "1,2,""r"",""c"",""keepOrder"",""uniqueNan"""))
+        end
+        in(1) = null()
+        i = 3
+    end
+    while size(in)>0 & i<5 then
+        a = in(1)
+        if typeof(a)=="string"
+            a = convstr(a)
+        end
+        select a
+        case "uniquenan"
+            uniqueNan = %t
+        case "keeporder"
+            keepOrder = %t
+        else
+            msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
+            error(msprintf(msg, "unique", i, """keepOrder"",""uniqueNan"""))
+        end
+        in(1) = null()
+        i = i+1
+    end
+    uniqueNan = uniqueNan & or(type(x)==[1 5])
 
-    if argn(2)<2 then orient = "*",end
     sz = size(x);
     if size(x, orient)==1 then
         k = 1
         return
     end
+    if uniqueNan
+        [x, newInf] = uniqueProcessNan(x, [], "removeNan")
+    end
+    getK = argn(1)>1 | keepOrder
+
+
+    // [] trivial case
+    // ---------------
+    if isempty(x) then
+        return  // k, 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)
@@ -29,37 +101,50 @@ function [x,k]=unique(x,orient)
             else
                 if orient=="*"
                     x = [real(x(:)) imag(x(:))]
-                    if argn(1)==1
+                    if ~getK
                         x = unique(x,"r")
                     else
-                        [x, k] = unique(x,"r")
+                        [x, k, nb] = unique(x,"r")
                     end
                     x = complex(x(:,1),x(:,2));
                     if sz(1)==1 // => put results in row
                         x = x.'
-                        if argn(1)>1
+                        if getK
                             k = k'
+                            nb = nb'
                         end
                     end
                 elseif orient=="r" | orient==1
                     x = [real(x) imag(x)]
-                    if argn(1)==1
+                    if ~getK
                         x = unique(x,"r")
                     else
-                        [x, k] = unique(x,"r")
+                        [x, k, 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 argn(1)==1
+                    if ~getK
                         x = unique(x,"c")
                     else
-                        [x, k] = unique(x,"c")
+                        [x, k, nb] = unique(x,"c")
                     end
                     x = complex(x(1:sz(1),:), x(sz(1)+1:$,:));
-                else
-                    msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
-                    error(msprintf(msg, "unique", 2, "1,""r"",2,""c"""));
+                end
+                if uniqueNan
+                    x = uniqueProcessNan(x, newInf, "restoreNan")
+                end
+                if keepOrder
+                    [k, kk] = gsort(k,"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
@@ -67,48 +152,137 @@ function [x,k]=unique(x,orient)
     end
 
     // PROCESSING text and other numerical types
+    // -----------------------------------------
     if orient=="*" then
-        if argn(1) == 2 then
-            [x,k] = gsort(x,"g","d");
-            keq = find( x(2:$) == x(1:$-1) );
+        if getK then
+            [x,k] = gsort(x,"g","i");
+            keq = x(2:$) == x(1:$-1);
+            if argn(1)>2
+                nb = [0 find(~keq) size(x,"*")]
+                nb = nb(2:$) - nb(1:$-1)
+            end
+            keq = find(keq);
             if keq<>[] then keq = keq+1;end
             x(keq) = [];
             k(keq) = [];
-            k = k($:-1:1);
-            x = x($:-1:1);
+            if size(x,1)>1 | ndims(x)>2
+                x = x(:)
+                k = k(:)
+                nb = nb(:)
+            end
         else
             x = gsort(x,"g","d");
             x = x($:-1:1);
             x( find(x(2:$) == x(1:$-1)) ) = [];
         end
     elseif  orient==1|orient=="r" then
-        if argn(1) == 2 then
-            [x,k] = gsort(x,"lr","d");
-            keq = find(and(x(2:$,:) == x(1:$-1,:),"c"))
+        if getK then
+            [x,k] = gsort(x,"lr","i");
+            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(:)
+            end
+            keq = find(keq)
             if keq<>[] then keq = keq+1;end
             x(keq,:) = [];
             k(keq,:) = [];
-            k = k($:-1:1,:);
-            x = x($:-1:1,:);
         else
             x = gsort(x,"lr","i");
             x( find(and(x(2:$,:) == x(1:$-1,:),"c")),:) = [];
         end
     elseif  orient==2|orient=="c" then
-        if argn(1) == 2 then
-            [x,k] = gsort(x,"lc","d");
-            keq = find(and(x(:,2:$) == x(:,1:$-1),"r"))
+        if getK then
+            [x,k] = 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) = [];
             k(:,keq) = [];
-            k = k(:,$:-1:1);
-            x = x(:,$:-1:1);
         else
             x = gsort(x,"lc","i");
             x(:, find(and(x(:,2:$) == x(:,1:$-1),"r")) ) = [];
         end
-    else
-        msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
-        error(msprintf(msg, "unique", 2, "1,""r"",2,""c"""));
+    end
+    if uniqueNan
+        x = uniqueProcessNan(x, newInf, "restoreNan")
+    end
+    if keepOrder
+        [k, kk] = gsort(k,"g","i")
+        select orient
+        case "*"
+            x = x(kk)
+        case "r"
+            x = x(kk,:)
+        case "c"
+            x = x(:,kk)
+        end
+        if argn(1)>2
+            nb = nb(kk)
+        end
+    end
+endfunction
+// -------------------------------------------------------------------
+
+// To consider Nan mutually equal, we replace all of them with a "regular" substitute.
+// Since Nan are sorted as > Inf, we must use anyway Inf as the Nan substitute.
+// If the original array have already some Inf, we must priorly replace them with
+// a decimal greater than the finite maximum of the array values.
+// After processing, we restore Inf => Nan (, and maxNum => Inf).
+
+function [x, newInf] = uniqueProcessNan(x, newInf, way)
+
+    if way=="removeNan" & or(isnan(x)) then 
+        // Replacing Nan
+        // -------------
+        if isreal(x)
+            if or(x==%inf)
+                b = x==%inf
+                m = max([1 max(x(~b))])
+                newInf = m*1.5
+                x(b) = newInf
+            end
+            x(x<>x) = %inf
+        else
+            r = real(x)
+            i = imag(x)
+            if or([r i]==%inf)
+                br = r==%inf
+                m = max(r(~br),1)
+                bi = i==%inf
+                m = max(i(~bi),m,1)
+                newInf = m*1.5
+                r(br) = newInf
+                i(bi) = newInf
+            end
+            r(r<>r) = %inf
+            i(i<>i) = %inf
+            x = complex(r,i);
+        end
+
+    // Restoring  NaN
+    // --------------
+    elseif way=="restoreNan"
+        if isreal(x)
+            x(x==%inf) = %nan
+            if newInf~=[]
+                x(x==newInf) = %inf
+            end
+        else
+            r = real(x)
+            r(r==%inf) = %nan
+            i = imag(x)
+            i(i==%inf) = %nan
+            if newInf~=[]
+                r(r==newInf) = %inf
+                i(i==newInf) = %inf
+            end
+            x = complex(r, i)
+        end
     end
 endfunction
index c0d6043..55b5afe 100644 (file)
@@ -1,6 +1,6 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
-// Copyright (C) 2018 - Samuel Gougeon
+// Copyright (C) 2018-2019 - Samuel Gougeon
 //
 //  This file is distributed under the same license as the Scilab package.
 // =============================================================================
 // <-- CLI SHELL MODE -->
 // <-- NO CHECK REF -->
 
+// =====================
 // Checking output sizes
-// ---------------------
+// =====================
 // "*"
-[u,k] = unique([]);
-assert_checkequal(u,[]);
-assert_checkequal(k,[]);
-[u,k] = unique([1 4 5]);
-assert_checkequal(size(u),[1 3]);
-assert_checkequal(size(k),[1 3]);
-[u,k] = unique([1 4 5]');
-assert_checkequal(size(u),[3 1]);
-assert_checkequal(size(k),[3 1]);
-[u,k] = unique([1 4 5]');
-assert_checkequal(size(u),[3 1]);
-assert_checkequal(size(k),[3 1]);
-[u,k] = unique([1 3 4 ; 5 6 7]);
-assert_checkequal(size(u),[6 1]);
-assert_checkequal(size(k),[6 1]);
-[u,k] = unique([1 3 4 ; 5 6 7]);
-assert_checkequal(size(u),[6 1]);
-assert_checkequal(size(k),[6 1]);
-[u,k] = unique(rand(3,4,2));
-assert_checkequal(size(u),[24 1]);
-assert_checkequal(size(k),[24 1]);
+[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] = unique([], "r");
-assert_checkequal(u,[]);
-assert_checkequal(k,[]);
-[u,k] = unique([1 3 4 ; 5 6 7], "r");
-assert_checkequal(size(u),[2 3]);
-assert_checkequal(size(k),[2 1]);
+[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]);
 
 // "c"
-[u,k] = unique([], "c");
+[u,k,nb] = unique([], "c");
 assert_checkequal(u,[]);
 assert_checkequal(k,[]);
-[u,k] = unique([1 3 4 ; 5 6 7], "c");
-assert_checkequal(size(u),[2 3]);
-assert_checkequal(size(k),[1 3]);
+[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
-// --------------------
+// ====================
 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, k] = unique(x);
+u = unique(x);
+assert_checkequal(u, [0 1 2]');
+[u,k,nb] = unique(x);
 assert_checkequal(u, [0 1 2]');
 assert_checkequal(k, [3 2 1]');
-[u, k] = unique(x, "c");
+assert_checkequal(nb,[13 7 12]');
+
+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");
+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]');
+
+// keepOrder
+// ---------
+[u,k,nb] = unique(x, "keepOrder");
+assert_checkequal(u, [2 1 0]');
+assert_checkequal(k, [1 2 3]');
+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
+      ];
+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 ]);
+
+[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
+// ---------
+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);
+assert_checkequal(u, [0 Inf Nan*ones(1,8)]');
+assert_checkequal(k, [4 2 1 3 6 7 14 15 16 19]');
+assert_checkequal(nb,[7 5 1 1 1 1 1  1  1  1]');
+//
+u = unique(x, "c");
+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");
+assert_checkequal(u, uxc);
+assert_checkequal(k, [5  6  3  7  2  4 10  1  8]);
+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");
+assert_checkequal(u, uxc');
+assert_checkequal(k, [5  6  3  7  2  4 10  1  8]');
+assert_checkequal(nb,[1  2  1  1  1  1  1  1  1]');
+
+// With Nans & "uniqueNan" option
+// ------------------------------
+[u,k,nb] = unique(x, "uniqueNan");
+assert_checkequal(u, [0 Inf Nan]');
+assert_checkequal(k, [4 2 1]');
+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");
+assert_checkequal(u, uxc);
+assert_checkequal(k, [5  6  3  2  1  8]);
+assert_checkequal(nb,[1  2  2  3  1  1]);
+
+[u,k,nb] = unique(x', "r", "uniqueNan");
+assert_checkequal(u, uxc');
+assert_checkequal(k, [5  6  3  2  1  8]');
+assert_checkequal(nb,[1  2  2  3  1  1]');
 
+// With Nans & "uniqueNan" & "keepOrder" options
+// ---------------------------------------------
+[u,k,nb] = unique(x, "uniqueNan", "keepOrder");
+assert_checkequal(u, [Nan Inf 0]');
+assert_checkequal(k, [1 2 4]');
+assert_checkequal(nb,[8 5 7]');
+//
+uxc = [Nan  Nan  Inf  0  Inf  Nan
+       Inf  0    Nan  0  0    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");
+assert_checkequal(u, uxc);
+assert_checkequal(k, [1  2  3  5  6  8]);
+assert_checkequal(nb,[1  3  2  1  2  1]);
+
+[u,k,nb] = unique(x', "r", "uniqueNan", "keepOrder");
+assert_checkequal(u, uxc');
+assert_checkequal(k, [1  2  3  5  6  8]');
+assert_checkequal(nb,[1  3  2  1  2  1]');
+
+// =====================
 // With encoded integers
-// ---------------------
+// =====================
 x = int8([-3 0 2 0 -3
           -3 0 2 0 -3
           -3 2 0 2 -3
          ]);
-[u,k] = unique(x);
+u = unique(x);
+assert_checkequal(u, int8([-3 0 2])');
+[u,k,nb] = unique(x);
 assert_checkequal(u, int8([-3 0 2])');
 assert_checkequal(k, [1 4 6]');
-[u,k] = unique(x, "r");
+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");
 assert_checkequal(u, int8([-3 0 2 0 -3 ; -3 2 0 2 -3]));
 assert_checkequal(k, [1;3]);
-[u,k] = unique(x, "c");
+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");
 assert_checkequal(u, int8([-3 0 2 ; -3 0 2; -3 2 0]));
 assert_checkequal(k, [1 2 3]);
+assert_checkequal(nb,[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];
+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(nb,[2  1  1  1  2]);
+
 c = [x($:-1:1) ; x ; x($:-1:1) ; 1:7 ; x];
-[u, k] = unique(c, "r");
+u = unique(c, "r");
 assert_checkequal(u, c([4 2 1],:));
-[u, k] = unique(c', "c");
-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(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);
+assert_checkequal(nb,[1 2 2]);
+
+// keepOrder
+// ---------
+[u,k,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(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");
+assert_checkequal(u, c(kref,:));
+assert_checkequal(k, kref');
+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]);
+
+
+// ==============
 // With some text
-// --------------
+// ==============
 t = ["AB" "BA" "BA" "BA" "AB" "BA" "AB" "AB" "BB" "AA" "AB" "BA" "BA" "BA" "AA"
      "AA" "AA" "AB" "AA" "BB" "BB" "BB" "BA" "AB" "AB" "BB" "BB" "AB" "AB" "AA"
     ];
-[u, k] = unique(t);
+u = unique(t);
+assert_checkequal(u, ["AA" "AB" "BA" "BB"]');
+[u,k,nb] = unique(t);
 assert_checkequal(u, ["AA" "AB" "BA" "BB"]');
 assert_checkequal(k, [2 1 3 10]');
+assert_checkequal(nb,[6 10 8 6]');
 
 utc = ["AA"  "AA"  "AB"  "AB"  "AB"  "BA"  "BA"  "BA"  "BB"
        "AA"  "AB"  "AA"  "BA"  "BB"  "AA"  "AB"  "BB"  "AB"
       ];
-[u, k] = unique(t, "c");
+u = unique(t, "c");
+assert_checkequal(u, utc);
+[u,k,nb] = unique(t, "c");
 assert_checkequal(u, utc);
 assert_checkequal(k, [15 10 1 8 5 2 3 6 9]);
-[u, k] = unique(t', "r");
+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");
 assert_checkequal(u, utc');
 assert_checkequal(k, [15 10 1 8 5 2 3 6 9]');
+assert_checkequal(nb,[1  1  1 1 3 2 3 2 1]');
+
+// keepOrder
+// ---------
+[u,k,nb] = unique(t, "keepOrder");
+assert_checkequal(u, ["AB" "AA" "BA" "BB"]');
+assert_checkequal(k, [1 2 3 10]');
+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");
+assert_checkequal(u, utc);
+assert_checkequal(k, [1 2 3 5 6 8 9 10 15]);
+assert_checkequal(nb,[1 2 3 3 2 1 1 1  1 ]);
+
+[u,k,nb] = unique(t', "r", "keepOrder");
+assert_checkequal(u, utc');
+assert_checkequal(k, [1 2 3 5 6 8 9 10 15]');
+assert_checkequal(nb,[1 2 3 3 2 1 1 1  1 ]');