// Copyright (C) 2003-2009 Marc Duruflé
// Copyright (C) 2001-2009 Vivien Mallet
//
// This file is part of the linear-algebra library Seldon,
// http://seldon.sourceforge.net/.
//
// Seldon is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Seldon. If not, see http://www.gnu.org/licenses/.


#ifndef SELDON_FILE_FUNCTIONS_ARRAYS_CXX

/*
  Functions defined in this file
 
  QuickSort(m, n, X);
  QuickSort(m, n, X, Y);
  QuickSort(m, n, X, Y, Z);

  MergeSort(m, n, X);
  MergeSort(m, n, X, Y);
  MergeSort(m, n, X, Y, Z);

  Sort(m, n, X);
  Sort(m, n, X, Y);
  Sort(m, n, X, Y, Z);
  Sort(m, X);
  Sort(m, X, Y);
  Sort(m, X, Y, Z);
  Sort(X);
  Sort(X, Y);
  Sort(X, Y, Z);

  Assemble(m, X);
  Assemble(m, X, Y);
 
  RemoveDuplicate(m, X);
  RemoveDuplicate(m, X, Y);
  RemoveDuplicate(X);
  RemoveDuplicate(X, Y);
*/


namespace Seldon
{
 
 
 
////////////
 
//  SORT  //
 
 
 
//! Intermediary function used for quick sort algorithm.
 
template<class T, class Storage, class Allocator>
 
int PartitionQuickSort(int m, int n,
                         
Vector<T, Storage, Allocator>& t)
 
{
    T temp
, v;
    v
= t(m);
   
int i = m - 1;
   
int j = n + 1;
   
   
while (true)
     
{
       
do
         
{
            j
--;
         
}
       
while (t(j) > v);
       
       
do
         
{
            i
++;
         
}
       
while (t(i) < v);
       
       
if (i < j)
         
{
            temp
= t(i);
            t
(i) = t(j);
            t
(j) = temp;
         
}
       
else
         
{
           
return j;
         
}
     
}
 
}
 
 
 
//! Vector \a t is sorted by using QuickSort algorithm.
 
/*!
    Sorts array \a t between position m and n.
  */

 
template<class T, class Storage, class Allocator>
 
void QuickSort(int m, int n,
                 
Vector<T, Storage, Allocator>& t)
 
{
   
if (m < n)
     
{
       
int p = PartitionQuickSort(m, n, t);
       
QuickSort(m, p, t);
       
QuickSort(p+1, n, t);
     
}
 
}
 
 
 
//! Intermediary function used for quick sort algorithm.
 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
int PartitionQuickSort(int m, int n,
                         
Vector<T1, Storage1, Allocator1>& t1,
                         
Vector<T2, Storage2, Allocator2>& t2)
 
{
    T1 temp1
, v;
    T2 temp2
;
    v
= t1(m);
   
int i = m - 1;
   
int j = n + 1;
   
   
while (true)
     
{
       
do
         
{
            j
--;
         
}
       
while (t1(j) > v);
       
do
         
{
            i
++;
         
}
       
while (t1(i) < v);
       
       
if (i < j)
         
{
            temp1
= t1(i);
            t1
(i) = t1(j);
            t1
(j) = temp1;
            temp2
= t2(i);
            t2
(i) = t2(j);
            t2
(j) = temp2;
         
}
       
else
         
{
           
return j;
         
}
     
}
 
}
 
 
 
//! Vector \a t1 is sorted by using QuickSort algorithm.
 
/*! Sorts array \a t2 between position m and n, the sorting operation
    affects vector \a t2.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void QuickSort(int m, int n,
                 
Vector<T1, Storage1, Allocator1>& t1,
                 
Vector<T2, Storage2, Allocator2>& t2)
 
{
   
if (m < n)
     
{
       
int p = PartitionQuickSort(m, n, t1, t2);
       
QuickSort(m, p, t1, t2);
       
QuickSort(p+1, n, t1, t2);
     
}
 
}
 
 
 
//! Intermediary function used for quick sort algorithm.
 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
int PartitionQuickSort(int m, int n,
                         
Vector<T1, Storage1, Allocator1>& t1,
                         
Vector<T2, Storage2, Allocator2>& t2,
                         
Vector<T3, Storage3, Allocator3>& t3)
 
{
    T1 temp1
, v;
    T2 temp2
;
    T3 temp3
;
    v
= t1(m);
   
int i = m - 1;
   
int j = n + 1;
   
   
while (true)
     
{
       
do
         
{
            j
--;
         
}
       
while (t1(j) > v);
       
       
do
         
{
            i
++;
         
}
       
while (t1(i) < v);
       
       
if (i < j)
         
{
            temp1
= t1(i);
            t1
(i) = t1(j);
            t1
(j) = temp1;
            temp2
= t2(i);
            t2
(i) = t2(j);
            t2
(j) = temp2;
            temp3
= t3(i);
            t3
(i) = t3(j);
            t3
(j) = temp3;
         
}
       
else
         
{
           
return j;
         
}
     
}
 
}
 
 
 
//! Vector \a t1 is sorted by using QuickSort algorithm.
 
/*! Sorts array \a t1 between position m and n, the sorting operation
    affects vectors \a t2 and \a t3.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
void QuickSort(int m, int n,
                 
Vector<T1, Storage1, Allocator1>& t1,
                 
Vector<T2, Storage2, Allocator2>& t2,
                 
Vector<T3, Storage3, Allocator3>& t3)
 
{
   
if (m < n)
     
{
       
int p = PartitionQuickSort(m, n, t1, t2, t3);
       
QuickSort(m, p, t1, t2, t3);
       
QuickSort(p+1, n, t1, t2, t3);
     
}
 
}
 
 
 
//! Vector \a tab1 is sorted by using MergeSort algorithm.
 
/*!
    Sorts array \a tab1 between position m and n.
  */

 
template<class T, class Storage, class Allocator>
 
void MergeSort(int m, int n, Vector<T, Storage, Allocator>& tab1)
 
{
   
if (m <= n)
     
return;
   
   
int inc = 1, ind = 0, current, i, j, sup;
   
Vector<T, Storage, Allocator> tab1t(m-n+1);
   
// Performs a merge sort with a recurrence.
   
// inc = 1, 2, 4, 8, ...
   
while (inc < n)
     
{
       
// 'i' is the first index of the sub array of size 2*inc.
       
// A loop is performed on these sub-arrays.
       
// Each sub array is divided in two sub-arrays of size 'inc'.
       
// These two sub-arrays are then merged.
       
for (i = m; i < n - inc; i += 2 * inc)
         
{
            ind
= i;
            current
= i + inc; // Index of the second sub-array.
            sup
= i + 2 * inc; // End of the merged array.
           
if (sup >= n)
              sup
= n;
            j
= i;
           
// Loop on values of the first sub-array.
           
while (j < i + inc)
             
{
               
// If the second sub-array has still unsorted elements.
               
if (current < sup)
                 
{
                   
// Insert the elements of the second sub-array in the
                   
// merged array until tab1(j) < tab1(current).
                   
while (current < sup && tab1(j) > tab1(current))
                     
{
                        tab1t
(ind-m) = tab1(current);
                        current
++;
                        ind
++;
                     
}
                   
// Inserts the element of the first sub-array now.
                    tab1t
(ind - m) = tab1(j);
                    ind
++;
                    j
++;
                   
// If the first sub-array is sorted, all remaining
                   
// elements of the second sub-array are inserted.
                   
if (j == i + inc)
                     
{
                       
for (j = current; j < sup; j++)
                         
{
                            tab1t
(ind - m) = tab1(j);
                            ind
++;
                         
}
                     
}
                 
}
               
else
                 
{
                   
// If the second sub-array is sorted, all remaining
                   
// elements of the first sub-array are inserted.
                   
for (current = j; current < i + inc; current++)
                     
{
                        tab1t
(ind - m) = tab1(current);
                        ind
++;
                     
}
                    j
= current + 1;
                 
}
             
}
         
}
       
       
for (i = m; i < ind; i++)
          tab1
(i) = tab1t(i - m);
       
        inc
= 2 * inc;
     
}
 
}
 
 
 
//! Vector \a tab1 is sorted by using MergeSort algorithm.
 
/*! Sorts array \a tab1 between position m and n. The sort operation affects
    \a tab2.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void MergeSort(int m, int n, Vector<T1, Storage1, Allocator1>& tab1,
                 
Vector<T2, Storage2, Allocator2>& tab2)
 
{
   
if (m <= n)
     
return;
   
   
int inc = 1, ind = 0, current, i, j, sup;
   
Vector<T1, Storage1, Allocator1> tab1t(m - n + 1);
   
Vector<T2, Storage2, Allocator2> tab2t(m - n + 1);
   
   
while (inc < n)
     
{
       
for (i = 0; i < n - inc; i += 2 * inc)
         
{
            ind
= i;
            current
= i + inc;
            sup
= i + 2 * inc;
           
if (sup >= n)
              sup
= n;
            j
= i;
           
while (j < i + inc)
             
{
               
if (current < sup)
                 
{
                   
while (current < sup && tab1(j) > tab1(current))
                     
{
                        tab1t
(ind - m) = tab1(current);
                        tab2t
(ind - m) = tab2(current);
                        current
++;
                        ind
++;
                     
}
                    tab1t
(ind - m) = tab1(j);
                    tab2t
(ind - m) = tab2(j);
                    ind
++;
                    j
++;
                   
if (j == i + inc)
                     
{
                       
for (j = current; j < sup; j++)
                         
{
                            tab1t
(ind - m) = tab1(j);
                            tab2t
(ind - m) = tab2(j);
                            ind
++;
                         
}
                     
}
                 
}
               
else
                 
{
                   
for (current = j; current < i + inc; current++)
                     
{
                        tab1t
(ind - m) = tab1(current);
                        tab2t
(ind - m) = tab2(current);
                        ind
++;
                     
}
                    j
= current + 1;
                 
}
             
}
         
}
       
for (i = 0; i < ind; i++)
         
{
            tab1
(i) = tab1t(i - m);
            tab2
(i) = tab2t(i - m);
         
}
        inc
= 2 * inc;
     
}
 
}
 
 
 
//! Vector \a tab1 is sorted by using MergeSort algorithm.
 
/*! Sorts array \a tab1 between position m and n. The sort operation affects
    \a tab2 and \a tab3.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
void MergeSort(int m, int n, Vector<T1, Storage1, Allocator1>& tab1,
                 
Vector<T2, Storage2, Allocator2>& tab2,
                 
Vector<T3, Storage3, Allocator3>& tab3)
 
{
   
if (m <= n)
     
return;
   
   
int inc = 1, ind = 0, current, i, j, sup;
   
Vector<T1, Storage1, Allocator1> tab1t(n - m + 1);
   
Vector<T2, Storage2, Allocator2> tab2t(n - m + 1);
   
Vector<T3, Storage3, Allocator3> tab3t(n - m + 1);
   
   
while (inc < n)
     
{
       
for (i = 0; i < n - inc; i += 2 * inc)
         
{
            ind
= i;
            current
= i + inc;
            sup
= i + 2 * inc;
           
if (sup >= n)
              sup
= n;
            j
= i;
           
while (j < i + inc)
             
{
               
if (current < sup)
                 
{
                   
while (current < sup && tab1(j) > tab1(current))
                     
{
                        tab1t
(ind - m) = tab1(current);
                        tab2t
(ind - m) = tab2(current);
                        tab3t
(ind - m) = tab3(current);
                        current
++;
                        ind
++;
                     
}
                    tab1t
(ind - m) = tab1(j);
                    tab2t
(ind - m) = tab2(j);
                    tab3t
(ind - m) = tab3(j);
                    ind
++;
                    j
++;
                   
if (j == i + inc)
                     
{
                       
for (j = current; j < sup; j++)
                         
{
                            tab1t
(ind - m) = tab1(j);
                            tab2t
(ind - m) = tab2(j);
                            tab3t
(ind - m) = tab3(j);
                            ind
++;
                         
}
                     
}
                 
}
               
else
                 
{
                   
for (current = j; current < i + inc; current++)
                     
{
                        tab1t
(ind - m) = tab1(current);
                        tab2t
(ind - m) = tab2(current);
                        tab3t
(ind - m) = tab3(current);
                        ind
++;
                     
}
                    j
= current+1;
                 
}
             
}
         
}
       
for (i = 0; i < ind; i++)
         
{
            tab1
(i) = tab1t(i - m);
            tab2
(i) = tab2t(i - m);
            tab3
(i) = tab3t(i - m);
         
}
        inc
= 2 * inc;
     
}
 
}
 
 
 
//! Assembles a sparse vector.
 
/*! The function sorts the indices in \a Node and adds the corresponding
    values of \a Vect corresponding.

    For example, if Node = [3 2 2 0], Vect = [1.0 0.4 0.4 -0.3], the function
    will return: n = 3, Node = [0 2 3], Vect = [-0.3 0.8 1.0].

    \param[in,out] n on entry, the number of elements to assemble; on exit,
    the number of values after assembling.
    \param[in,out] Node positions in the vector.
    \param[in,out] Vect values.
    \warning Vectors \a Node and \a Vect are not resized.
  */

 
template<class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2 >
 
void Assemble(int& n, Vector<int, Storage1, Allocator1>& Node,
               
Vector<T2, Storage2, Allocator2>& Vect)
 
{
   
if (n <= 1)
     
return;
   
   
Sort(n, Node, Vect);
   
int prec = Node(0);
   
int nb = 0;
   
for (int i = 1; i < n; i++)
     
if (Node(i) == prec)
       
{
         
Vect(nb) += Vect(i);
       
}
     
else
       
{
          nb
++;
         
Node(nb) = Node(i);
         
Vect(nb) = Vect(i);
          prec
= Node(nb);
       
}
    n
= nb + 1;
 
}
 
 
 
//! Sorts and removes duplicate entries of a vector.
 
/*!
    \param[in,out] n on entry, the number of elements to assemble; on exit,
    the number of values after assembling.
    \param[in,out] Node vector to be assembled.
    \warning The vector \a Node is not resized.
  */

 
template<class T, class Storage1, class Allocator1>
 
void Assemble(int& n, Vector<T, Storage1, Allocator1>& Node)
 
{
   
if (n <= 1)
     
return;
   
   
Sort(n, Node);
    T prec
= Node(0);
   
int nb = 1;
   
for (int i = 1; i < n; i++)
     
if (Node(i) != prec)
       
{
         
Node(nb) = Node(i);
          prec
= Node(nb);
          nb
++;
       
}
    n
= nb;
 
}
 

 
//! Sorts and removes duplicate entries of a vector.
 
template<class T, class Storage1, class Allocator1>
 
void Assemble(Vector<T, Storage1, Allocator1>& Node)
 
{
   
int nb = Node.GetM();
   
Assemble(nb, Node);
   
Node.Resize(nb);
 
}
 
 
 
//! Sorts and removes duplicate entries of a vector.
 
/*!
    Sorting operations on \a Node also affect \a Node2.
  */

 
template<class T, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void RemoveDuplicate(int& n, Vector<T, Storage1, Allocator1>& Node,
                       
Vector<T2, Storage2, Allocator2>& Node2)
 
{
   
if (n <= 1)
     
return;
   
   
Sort(n, Node, Node2);
    T prec
= Node(0);
   
int nb = 1;
   
for (int i = 1; i < n; i++)
     
if (Node(i) != prec)
       
{
         
Node(nb) = Node(i);
         
Node2(nb) = Node2(i);
          prec
= Node(nb);
          nb
++;
       
}
    n
= nb;
 
}
 
 
 
//! Sorts and removes duplicate entries of a vector.
 
template<class T, class Storage1, class Allocator1>
 
void RemoveDuplicate(int& n, Vector<T, Storage1, Allocator1>& Node)
 
{
   
Assemble(n, Node);
 
}
 
 
 
//! Sorts and removes duplicate entries of a vector.
 
/*!
    Sorting operations of \a Node also affect \a Node2.
  */

 
template<class T, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void RemoveDuplicate(Vector<T, Storage1, Allocator1>& Node,
                       
Vector<T2, Storage2, Allocator2>& Node2)
 
{
   
int n = Node.GetM();
   
if (n <= 1)
     
return;
   
   
RemoveDuplicate(n, Node, Node2);
   
Node.Resize(n);
   
Node2.Resize(n);
 
}

 
 
//! Sorts and removes duplicate entries of a vector.
 
template<class T, class Storage1, class Allocator1>
 
void RemoveDuplicate(Vector<T, Storage1, Allocator1>& Node)
 
{
   
int n = Node.GetM();
   
if (n <= 1)
     
return;
   
   
Assemble(n, Node);
   
Node.Resize(n);
 
}
 
 
 
//! Sorts vector \a V between a start position and an end position.
 
template<class T, class Storage, class Allocator>
 
void Sort(int m, int n, Vector<T, Storage, Allocator>& V)
 
{
   
QuickSort(m, n, V);
 
}
 
 
 
//! Sorts vector \a V between a start position and an end position.
 
/*!
    The sorting operation of \a V also affects \a V2.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void Sort(int m, int n, Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2)
 
{
   
QuickSort(m, n, V, V2);
 
}
 
 
 
//! Sorts vector \a V between a start position and an end position.
 
/*!
    The sorting operation of \a V also affects \a V2 and \a V3.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
void Sort(int m, int n, Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2,
           
Vector<T3, Storage3, Allocator3>& V3)
 
{
   
QuickSort(m, n, V, V2, V3);
 
}
 
 
 
//! Sorts the \a n first elements of \a V.
 
template<class T, class Storage, class Allocator>
 
void Sort(int n, Vector<T, Storage, Allocator>& V)
 
{
   
Sort(0, n - 1, V);
 
}
 
 
 
//! Sorts the \a n first elements of \a V.
 
/*!
    The sorting operation of \a V also affects \a V2.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void Sort(int n, Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2)
 
{
   
Sort(0, n - 1, V, V2);
 
}
 
 
 
//! Sorts the \a n first elements of \a V.
 
/*!
    The sorting operation of \a V also affects \a V2 and \a V3.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
void Sort(int n, Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2,
           
Vector<T3, Storage3, Allocator3>& V3)
 
{
   
Sort(0, n - 1, V, V2, V3);
 
}
 
 
 
//! Sorts vector \a V.
 
template<class T, class Storage, class Allocator>
 
void Sort(Vector<T, Storage, Allocator>& V)
 
{
   
Sort(0, V.GetM() - 1, V);
 
}
 
 
 
//! Sorts vector \a V.
 
/*!
    The sorting operation of \a V also affects \a V2.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2>
 
void Sort(Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2)
 
{
   
Sort(0, V.GetM() - 1, V, V2);
 
}
 
 
 
//! Sorts vector \a V.
 
/*!
    The sorting operation of \a V also affects \a V2 and \a V3.
  */

 
template<class T1, class Storage1, class Allocator1,
           
class T2, class Storage2, class Allocator2,
           
class T3, class Storage3, class Allocator3>
 
void Sort(Vector<T1, Storage1, Allocator1>& V,
           
Vector<T2, Storage2, Allocator2>& V2,
           
Vector<T3, Storage3, Allocator3>& V3)
 
{
   
Sort(0, V.GetM() - 1, V, V2, V3);
 
}
 
 
 
//  SORT  //
 
////////////
 
 
} // namespace Seldon

#define SELDON_FILE_FUNCTIONS_ARRAYS_CXX
#endif