<?xml version="1.0" encoding="utf-8"?>
<!--
 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 * Copyright (C) Bruno Pincon
 * Copyright (C) 2011 - DIGITEO - Michael Baudin
 * Copyright (C) 2013 - Samuel GOUGEON
 *
 * Copyright (C) 2012 - 2016 - Scilab Enterprises
 *
 * This file is hereby licensed under the terms of the GNU GPL v2.0,
 * pursuant to article 5.3.4 of the CeCILL v.2.1.
 * This file was originally licensed under the terms of the CeCILL v2.1,
 * and continues to be available under such terms.
 * For more information, see the COPYING file which you should have received
 * along with this program.
 *
 -->
<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook"   xmlns:scilab="http://www.scilab.org"  xml:id="dsearch" xml:lang="en">
    <refnamediv>
        <refname>dsearch</refname>
        <refpurpose>
            distribute, locate and count elements of a matrix or hypermatrix in given categories
        </refpurpose>
    </refnamediv>
    <refsynopsisdiv>
        <title>Syntax</title>
        <synopsis>
            [i_bin [,counts [,outside]]] = dsearch(X, bins )
            [i_bin [,counts [,outside]]] = dsearch(X, bins , pm )
        </synopsis>
    </refsynopsisdiv>
    <refsection>
        <title>Arguments</title>
        <variablelist>
            <varlistentry>
                <term>X</term>
                <listitem>
                    <para>
                        matrix or hypermatrix of reals, encoded integers, or texts: The entries to categorize.
                        Complex numbers and polynomials are not supported.
                    </para>
                </listitem>
            </varlistentry>
            <varlistentry>
                <term>bins</term>
                <listitem>
                    <para>
                        row or column vector defining categories, of same type as <varname>X</varname> (for encoded integers in <varname>X</varname>, <varname>bins</varname> may be decimals).
                        <itemizedlist>
                            <listitem>
                                Discrete case (pm="d"): <varname>bins</varname> are distinct values to which <varname>X</varname> entries must be identified. If <varname>X</varname> is numeric (reals or encoded integers), <varname>bins</varname> must be sorted in strictly increasing order.
                            </listitem>
                            <listitem>
                                Continuous case (default, pm="c"): <varname>bins</varname> are bounds of contiguous intervals: <literal>I1 = [bins(1), bins(2)]</literal>, <literal>I2 = (bins(2), bins(3)]</literal>,..., <literal>In = (bins(n), bins(n+1)]</literal>. Note that entries from <varname>X</varname> just equal to bins(1) are included in <literal>I1</literal>.
                                The values in <varname>bins</varname> must be in strictly increasing order: bins(1) &lt; bins(2) &lt; ... &lt; bins(n).
                                For text processing, the case-sensitive lexicographic order is considered.
                            </listitem>
                        </itemizedlist>
                    </para>
                </listitem>
            </varlistentry>
            <varlistentry>
                <term>pm</term>
                <listitem>
                    <para>
                        "c" (continuous, default) or "d" (discrete): processing mode. In continuous mode, <varname>bins</varname> defines the bounds of contiguous intervals considered as categories. In discrete mode, <varname>bins</varname> provides the values to which entries from <varname>X</varname> must be identified.
                    </para>
                </listitem>
            </varlistentry>
            <varlistentry>
                <term>i_bin</term>
                <listitem>
                    <para>
                        matrix or hypermatrix with same sizes than <varname>X</varname>: <literal>i_bin(k)</literal> is the index of the category to which <varname>X(k)</varname> belongs. If <varname>X(k)</varname> belongs to none of the categories, <literal>i_bin(k) = 0</literal>
                    </para>
                </listitem>
            </varlistentry>
            <varlistentry>
                <term>counts</term>
                <listitem>number of X entries in respective bins.
                    <para>
                        Continuous case (pm="c"): counts(i) elements of <varname>X</varname> belong to the interval <literal>Ik</literal> as defined above (see the <varname>bins</varname> parameter). Elements of <varname>X</varname> just equal to bins(1) are included in counts(1). <varname>counts</varname> has the size of <varname>bins</varname> - 1
                    </para>
                    <para>
                        Discrete case (pm="d"): <literal>counts(i)</literal> elements of <varname>X</varname> are equal to <literal>bins(i)</literal>
                    </para>
                </listitem>
            </varlistentry>
            <varlistentry>
                <term>outside</term>
                <listitem>
                    <para>
                        Total number of X entries belonging to none of the <literal>bins</literal>.
                    </para>
                </listitem>
            </varlistentry>
        </variablelist>
    </refsection>
    <refsection>
        <title>Description</title>
        <para>
            For each <varname>X(i)</varname> entry, <varname>dsearch</varname> locates the value <literal>bins(j)</literal> or the interval <literal>(bins(j), bins(j+1)]</literal> defined  by <varname>bins</varname> and containing or equal to <varname>X(i)</varname>. Then it returns <literal>i_bin(i) = j</literal> or 0 whether no bin equals or contains it. (the first interval includes <literal>bins(1)</literal>). The population of each bin is returned through <varname>counts</varname>. The total number of unbinned entries is returned in <varname>outside</varname> (therefore <literal>outside = sum(bool2s(i_bin==0))</literal>).
        </para>
        <para>
            <literal>dsearch(..)</literal> can be overloaded.
            The default pm="c" option can be used to compute the empirical histogram of a function given a dataset.
        </para>
    </refsection>

    <refsection>
        <title>Examples</title>
        <programlisting role="example"><![CDATA[
// DISCRETE values of TEXT
// -----------------------
i = grand(4,6,"uin",0,7)+97;
T = matrix(strsplit(ascii(i),1:length(i)-1), size(i));
T(T=="f") = "#";
T(T=="a") = "AA";
T
bins = [ strsplit(ascii(97+(7:-1:0)),1:7)' "AA"]
[i_bin, counts, outside] = dsearch(T, bins, "d")

// BINNING TEXTS in LEXICOGRAPHIC INTERVALS
// ----------------------------------------
// generating a random matrix of text
nL = 3; nC = 5; L  = 3;
s = ascii(grand(1,nL*nC*L,"uin",0,25)+97);
T = matrix(strsplit(s, L:L:nL*nC*L-1), nL, nC);
// generating random bins bounds
L  = 2; nC = 6;
s = ascii(grand(1,nC*L,"uin",0,25)+97);
bins = unique(matrix(strsplit(s, L:L:nC*L-1), 1, nC))
T
[i_bin, counts, outside] = dsearch(T, bins)
    ]]></programlisting>

        <para>
            In the following example, we consider 3 intervals <literal>I1 = [5,11]</literal>,
            <literal>I2 = (11,15]</literal> and <literal>I3 = (15,20]</literal>.
            We are looking for the location of the entries of <literal>X = [11 13 1 7 5 2 9]</literal>
            in these intervals.
        </para>
        <programlisting role="example"><![CDATA[
[i_bin, counts, outside] = dsearch([11 13 1 7 5 2 9], [5 11 15 20])
    ]]></programlisting>
        <para>
            Displayed output:
        </para>
        <screen><![CDATA[
-->[i_bin, counts, outside] = dsearch([11 13 1 7 5 2 9], [5 11 15 20])
 outside  =
    2.
 counts  =
    4.    1.    0.
 i_bin  =
    1.    2.    0.    1.    1.    0.    1.
    ]]></screen>
        <para>
            Indeed,
        </para>
        <itemizedlist>
            <listitem>
                <para>X(1)=11 is in the interval I1, hence i_bin(1)=1.</para>
            </listitem>
            <listitem>
                <para> X(2)=13 is in the interval I2, hence i_bin(2)=2.</para>
            </listitem>
            <listitem>
                <para> X(3)=1 belongs to none of defined intervals, hence i_bin(3)=0.</para>
            </listitem>
            <listitem>
                <para> X(4)=7 is in the interval I1, hence i_bin(4)=1.</para>
            </listitem>
            <listitem>
                <para>...</para>
            </listitem>
            <listitem>
                <para> There are four X entries (5, 7, 9 and 11) in I1, hence counts(1)=4.</para>
            </listitem>
            <listitem>
                <para> There is only one X entry (13) in I2, hence counts(2)=1.</para>
            </listitem>
            <listitem>
                <para> There is no X entry in I3, hence counts(3)=0.</para>
            </listitem>
            <listitem>
                <para> There are two X entries (i.e. 1, 2) which belong to none of defined intervals, hence outside=2.</para>
            </listitem>
        </itemizedlist>
        <programlisting role="example"><![CDATA[
// Numbers in DISCRETE categories (having specific values)
// ------------------------------
[i_bin, counts, outside] = dsearch([11 13 1 7 5 2 9], [5 11 15 20],"d" )
    ]]></programlisting>
        <para>
            displays
        </para>
        <screen><![CDATA[
-->[i_bin, counts, outside] = dsearch([11 13 1 7 5 2 9], [5 11 15 20], "d" )
 outside  =
    5.
 counts  =
    1.    1.    0.    0.
 i_bin  =
    2.    0.    0.    0.    1.    0.    0.
    ]]></screen>
        <para>
            Indeed,
        </para>
        <itemizedlist>
            <listitem>
                <para>
                    X(1)=11 is in the set <literal>bins</literal> at position #2, hence i_bin(1)=2.
                </para>
            </listitem>
            <listitem>
                <para>
                    X(2)=13 is not in the set <literal>bins</literal>, hence i_bin(2)=0.
                </para>
            </listitem>
            <listitem>
                <para>...</para>
            </listitem>
            <listitem>
                <para>
                    X(7)=9 is not in the set <literal>bins</literal>, hence i_bin(7)=0.
                </para>
            </listitem>
            <listitem>
                <para>
                    There is only one entry X (i.e. 5) equal to 5, hence counts(1)=1.
                </para>
            </listitem>
            <listitem>
                <para>
                    There are no entries matching <literal>bins(4)</literal>, hence counts(4)=0.
                </para>
            </listitem>
            <listitem>
                <para>
                    There are five X entries (i.e. 13, 1, 7, 2, 9) which are not in the set <literal>bins</literal>, hence outside=5.
                </para>
            </listitem>
        </itemizedlist>
        <para>
            Numbers in <literal>bins</literal> must be in increasing order, whatever is the processing mode (continuous or discrete).
            If this is not the case, an error is generated:
        </para>
        <screen><![CDATA[
-->dsearch([11 13 1 7 5 2 9], [2 1])
!--error 999
dsearch   : the array s (arg 2) is not well ordered
-->dsearch([11 13 1 7 5 2 9], [2 1],"d")
!--error 999
dsearch   : the array s (arg 2) is not well ordered
    ]]></screen>
    </refsection>
    <refsection>
        <title>Advanced Examples</title>
        <para>
            In the following example, we compare the empirical histogram of uniform
            random numbers in [0,1) with the uniform distribution function.
            To perform this comparison, we use the default search algorithm based on intervals (pm="c").
            We generate X as a collection of m=50 000 uniform random numbers in the range [0,1).
            We consider the n=10 values equally equally spaced values in the [0,1] range and
            consider the associated intervals.
            Then we count the number of entries in X which fall in the intervals:
            this is the empirical histogram of the uniform distribution function.
            The expectation for counts/m is equal to 1/(n-1).
        </para>
        <programlisting role="example"><![CDATA[
m = 50000 ;
n = 10;
X = grand(m, 1, "def");
bins = linspace(0, 1, n)';
[i_bin, counts] = dsearch(X, bins);
e = 1/(n-1)*ones(1, n-1);
scf() ;
plot(bins(1:n-1), counts/m, "bo");
plot(bins(1:n-1), e', "r-");
legend(["Experiment", "Expectation"]);
xtitle("Uniform random numbers", "X", "P(X)");
 ]]></programlisting>
        <scilab:image>
            m = 50000 ;
            n = 10;
            X = grand(m,1, "def");
            bins = linspace(0, 1, n)';
            [i_bin, counts] = dsearch(X, bins);
            e = 1/(n-1)*ones(1, n-1);
            scf() ;
            plot(bins(1:n-1), counts/m, "bo");
            plot(bins(1:n-1), e', "r-");
            legend(["Experiment","Expectation"]);
            xtitle("Uniform random numbers", "X", "P(X)");
        </scilab:image>
        <para>
            In the following example, we compare the histogram of binomially distributed
            random numbers with the binomial probability distribution function B(N,p),
            with N=8 and p=0.5.
            To perform this comparison, we use the discrete search algorithm based on
            a set (pm="d").
        </para>
        <programlisting role="example"><![CDATA[
N = 8 ;
p = 0.5;
m = 50000;
X = grand(m,1,"bin",N,p);
bins = (0:N)';
[i_bin, counts] = dsearch(X, bins, "d");
Pexp = counts/m;
Pexa = binomial(p,N);
scf() ;
plot(bins, Pexp, "bo");
plot(bins, Pexa', "r-");
xtitle("Binomial distribution B(8,0.5)","X","P(X)");
legend(["Experiment","Expectation"]);
]]></programlisting>
        <scilab:image>
            N = 8 ;
            p = 0.5;
            m = 50000;
            X = grand(m,1,"bin",N,p);
            bins = (0:N)';
            [i_bin, counts] = dsearch(X, bins, "d");
            Pexp = counts/m;
            Pexa = binomial(p,N);
            scf() ;
            plot(bins, Pexp, "bo");
            plot(bins, Pexa',"r-");
            xtitle("Binomial distribution B(8,0.5)","X","P(X)");
            legend(["Experiment","Expectation"]);
        </scilab:image>
        <para>
            In the following example, we use piecewise Hermite polynomials to
            interpolate a dataset.
        </para>
        <programlisting role="example"><![CDATA[

      // define Hermite base functions
      function y=Ll(t,k,x)
        // Lagrange left on Ik
        y=(t-x(k+1))./(x(k)-x(k+1))
      endfunction
      function y=Lr(t,k,x)
        // Lagrange right on Ik
        y=(t-x(k))./(x(k+1)-x(k))
      endfunction
      function y=Hl(t,k,x)
        y=(1-2*(t-x(k))./(x(k)-x(k+1))).*Ll(t,k,x).^2
      endfunction
      function y=Hr(t,k,x)
        y=(1-2*(t-x(k+1))./(x(k+1)-x(k))).*Lr(t,k,x).^2
      endfunction
      function y=Kl(t,k,x)
        y=(t-x(k)).*Ll(t,k,x).^2
      endfunction
      function y=Kr(t,k,x)
        y=(t-x(k+1)).*Lr(t,k,x).^2
      endfunction

      x = [0 ; 0.2 ; 0.35 ; 0.5 ; 0.65 ; 0.8 ;  1];
      y = [0 ; 0.1 ;-0.1  ; 0   ; 0.4  ;-0.1 ;  0];
      d = [1 ; 0   ; 0    ; 1   ; 0    ; 0   ; -1];
      X = linspace(0, 1, 200)';
      i_bin = dsearch(X, x);

      // plot the curve
      Y = y(i_bin).*Hl(X,i_bin) + y(i_bin+1).*Hr(X,i_bin) + d(i_bin).*Kl(X,i_bin) + d(i_bin+1).*Kr(X,i_bin);
      scf();
      plot(X,Y,"k-");
      plot(x,y,"bo")
      xtitle("Hermite piecewise polynomial");
      legend(["Polynomial","Data"]);
      // NOTE : it can be verified by adding these ones :
      // YY = interp(X,x,y,d); plot2d(X,YY,3,"000")
      ]]></programlisting>
        <scilab:image>

            function y=Ll(t,k,x)
            y=(t-x(k+1))./(x(k)-x(k+1))
            endfunction
            function y=Lr(t,k,x)
            y=(t-x(k))./(x(k+1)-x(k))
            endfunction
            function y=Hl(t,k,x)
            y=(1-2*(t-x(k))./(x(k)-x(k+1))).*Ll(t,k,x).^2
            endfunction
            function y=Hr(t,k,x)
            y=(1-2*(t-x(k+1))./(x(k+1)-x(k))).*Lr(t,k,x).^2
            endfunction
            function y=Kl(t,k,x)
            y=(t-x(k)).*Ll(t,k,x).^2
            endfunction
            function y=Kr(t,k,x)
            y=(t-x(k+1)).*Lr(t,k,x).^2
            endfunction

            x = [0 ; 0.2 ; 0.35 ; 0.5 ; 0.65 ; 0.8 ;  1];
            y = [0 ; 0.1 ;-0.1  ; 0   ; 0.4  ;-0.1 ;  0];
            d = [1 ; 0   ; 0    ; 1   ; 0    ; 0   ; -1];
            X = linspace(0, 1, 200)';
            i_bin = dsearch(X, x);

            Y = y(i_bin).*Hl(X,i_bin) + y(i_bin+1).*Hr(X,i_bin) + d(i_bin).*Kl(X,i_bin) + d(i_bin+1).*Kr(X,i_bin);
            scf();
            plot(X,Y,"k-");
            plot(x,y,"bo")
            xtitle("Hermite piecewise polynomial");
            legend(["Polynomial","Data"]);
        </scilab:image>
    </refsection>

    <refsection role="see also">
        <title>See also</title>
        <simplelist type="inline">
            <member>
                <link linkend="find">find</link>
            </member>
            <member>
                <link linkend="members">members</link>
            </member>
            <member>
                <link linkend="tabul">tabul</link>
            </member>
        </simplelist>
    </refsection>

    <refsection>
        <title>History</title>
        <revhistory>
            <revision>
                <revnumber>5.5.0</revnumber>
                <revremark>Extension to hypermatrices, encoded integers, and text.</revremark>
            </revision>
        </revhistory>
    </refsection>
</refentry>
