Salome HOME
Bug with FindClosestTupleIdAlg fixed (preventing the threshold to be null)
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingMemArray.txx
index 69da58300068a9dc9fc2b9c5357e541543b08b6e..a536810981ffd0428c786b6b4ac05e9437d19dcd 100755 (executable)
@@ -593,7 +593,7 @@ namespace MEDCoupling
         std::ostringstream oss; oss << "DataArray::GetSlice : sliceId (" << nbOfSlices << ") must be in [0 , nbOfSlices (" << nbOfSlices << ") ) !";
         throw INTERP_KERNEL::Exception(oss.str().c_str());
       }
-    mcIdType nbElems=DataArrayTemplate<T>::GetNumberOfItemGivenBESRelative(start,stop,step,"DataArray::GetSlice");
+    mcIdType nbElems=DataArrayTools<T>::GetNumberOfItemGivenBESRelative(start,stop,step,"DataArray::GetSlice");
     mcIdType minNbOfElemsPerSlice=nbElems/nbOfSlices;
     startSlice=start+minNbOfElemsPerSlice*step*sliceId;
     if(sliceId<nbOfSlices-1)
@@ -672,6 +672,20 @@ namespace MEDCoupling
     std::copy(v.begin(),v.end(),pt);
     return ret;
   }
+
+  /*!
+   * Returns a newly created array containing a copy of the input array defined by [ \a arrBegin, \a arrEnd )
+   */
+  template<class T>
+  MCAuto< typename Traits<T>::ArrayTypeCh > DataArrayTemplate<T>::NewFromArray(const T *arrBegin, const T *arrEnd)
+  {
+    using DataArrayT = typename Traits<T>::ArrayTypeCh;
+    MCAuto< DataArrayT > ret(DataArrayT::New());
+    std::size_t nbElts(std::distance(arrBegin,arrEnd));
+    ret->alloc(nbElts,1);
+    std::copy(arrBegin,arrEnd,ret->getPointer());
+    return ret;
+  }
   
   template<class T>
   std::vector< MCAuto< typename Traits<T>::ArrayTypeCh > > DataArrayTemplate<T>::explodeComponents() const
@@ -1059,8 +1073,6 @@ namespace MEDCoupling
    * For more info on renumbering see \ref numbering.
    *  \param [in] new2Old - C array of length equal to \a this->getNumberOfTuples()
    *     giving a previous position of i-th new value.
-   *  \return DataArrayDouble * - the new instance of DataArrayDouble that the caller
-   *          is to delete using decrRef() as it is no more needed.
    */
   template<class T>
   void DataArrayTemplate<T>::renumberInPlaceR(const mcIdType *new2Old)
@@ -1087,10 +1099,12 @@ namespace MEDCoupling
   }
 
   /*!
-   * Sorts values of the array.
+   * Sorts values of the array. \b Warning, this method is not const, it alterates \a this content.
+   * 
    *  \param [in] asc - \a true means ascending order, \a false, descending.
    *  \throw If \a this is not allocated.
    *  \throw If \a this->getNumberOfComponents() != 1.
+   *  \sa copySorted
    */
   template<class T>
   void DataArrayTemplate<T>::sort(bool asc)
@@ -1105,6 +1119,23 @@ namespace MEDCoupling
     declareAsNew();
   }
 
+  /*!
+   * Sorts values of the array and put the result in a newly allocated returned array.
+   * This method does not alterate \a this content.
+   * 
+   *  \param [in] asc - \a true means ascending order, \a false, descending.
+   *  \throw If \a this is not allocated.
+   *  \throw If \a this->getNumberOfComponents() != 1.
+   *  \sa sort
+   */
+  template<class T>
+  typename Traits<T>::ArrayTypeCh *DataArrayTemplate<T>::copySortedImpl(bool asc) const
+  {
+    MCAuto<typename Traits<T>::ArrayTypeCh> ret(static_cast<typename Traits<T>::ArrayTypeCh *>(this->deepCopy()));
+    ret->sort(asc);
+    return ret.retn();
+  }
+
   /*!
    * Returns a copy of \a this array with values permuted as required by \a old2New array.
    * The values are permuted so that  \c new[ \a old2New[ i ]] = \c old[ i ].
@@ -1321,7 +1352,7 @@ namespace MEDCoupling
    * Changes the number of components within \a this array so that its raw data **does
    * not** change, instead splitting this data into tuples changes.
    *  \warning This method erases all (name and unit) component info set before!
-   *  \param [in] newNbOfComp - number of components for \a this array to have.
+   *  \param [in] newNbOfCompo - number of components for \a this array to have.
    *  \throw If \a this is not allocated
    *  \throw If getNbOfElems() % \a newNbOfCompo != 0.
    *  \throw If \a newNbOfCompo is lower than 1.
@@ -1436,7 +1467,7 @@ namespace MEDCoupling
     std::size_t newNbOfCompo=compoIds.size();
     std::size_t oldNbOfCompo=getNumberOfComponents();
     for(std::vector<std::size_t>::const_iterator it=compoIds.begin();it!=compoIds.end();it++)
-      if((*it)<0 || (*it)>=oldNbOfCompo)
+      if((*it)>=oldNbOfCompo)  // (*it) >= 0 (it is a size_t)
         {
           std::ostringstream oss; oss << Traits<T>::ArrayTypeName << "::keepSelectedComponents : invalid requested component : " << *it << " whereas it should be in [0," << oldNbOfCompo << ") !";
           throw INTERP_KERNEL::Exception(oss.str().c_str());
@@ -3706,6 +3737,46 @@ struct NotInRange
     switchOnTupleAlg(val,vec,std::not_equal_to<T>());
   }
 
+  /*!
+   * Compute for each element in \a this the occurence rank of that element. This method is typically useful of one-component array having a same element
+   * appearing several times. If each element in \a this appears once an 1 component array containing only 0 will be returned.
+   *
+   * \b Example:
+   * - \a this : [5, 3, 2, 1, 4, 5, 2, 1, 0, 11, 5, 4]
+   * - \a return is : [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 1] because at pos #0 of \a this (ie value 5) is the first occurrence ->0. At pos #10 of \a this (ie value 5 also) is the third occurrence of 5 -> 2.
+   *
+   * \return DataArrayInt * - a new instance of DataArrayInt with same number of tuples than \a this. The caller is to delete this
+   *          array using decrRef() as it is no more needed.
+   * \throw If either this not allocated or not with one component.
+   *
+   * \sa DataArrayInt::FindPermutationFromFirstToSecond
+   */
+  template<class T>
+  DataArrayIdType *DataArrayDiscrete<T>::occurenceRankInThis() const
+  {
+    constexpr char MSG0[] = "occurenceRankInThis :";
+    this->checkAllocated();
+    this->checkNbOfComps(1,MSG0);
+    MCAuto<DataArrayIdType> ret(DataArrayIdType::New());
+    ret->alloc(this->getNumberOfTuples(),1);
+    mcIdType *retPtr(ret->getPointer());
+    std::map<T,mcIdType> m;
+    for(const T *pt = this->begin() ; pt != this->end() ; ++pt, ++retPtr )
+    {
+      auto it = m.find(*pt);
+      if( it == m.end() )
+      {
+        *retPtr = 0;
+        m[*pt] = 1;
+      }
+      else
+      {
+        *retPtr = (*it).second++;
+      }
+    }
+    return ret.retn();
+  }
+
   /*!
    * Creates a new one-dimensional DataArrayInt of the same size as \a this and a given
    * one-dimensional arrays that must be of the same length. The result array describes
@@ -4390,7 +4461,7 @@ struct NotInRange
    * from values of \a this array, which is supposed to contain a renumbering map in
    * "New to Old" mode. The result array contains a renumbering map in "Old to New" mode.
    * To know how to use the renumbering maps see \ref numbering.
-   *  \param [in] newNbOfElem - the number of tuples in the result array.
+   *  \param [in] oldNbOfElem - the number of tuples in the result array.
    *  \return DataArrayInt * - the new instance of DataArrayInt.
    *          The caller is to delete this result array using decrRef() as it is no more
    *          needed.
@@ -4460,7 +4531,6 @@ struct NotInRange
    * from values of \a this array, which is supposed to contain a renumbering map in
    * "New to Old" mode. The result array contains a renumbering map in "Old to New" mode.
    * To know how to use the renumbering maps see \ref numbering.
-   *  \param [in] newNbOfElem - the number of tuples in the result array.
    *  \return MapII  - the new instance of Map.
    *
    *  \if ENABLE_EXAMPLES
@@ -4529,7 +4599,7 @@ struct NotInRange
    *
    * \return - An array of size std::distance(valsBg,valsEnd)
    *
-   * \sa DataArrayInt::FindPermutationFromFirstToSecond
+   * \sa DataArrayInt::FindPermutationFromFirstToSecond , DataArrayInt::FindPermutationFromFirstToSecondDuplicate
    */
   template <class T>
   MCAuto<DataArrayIdType> DataArrayDiscrete<T>::findIdForEach(const T *valsBg, const T *valsEnd) const
@@ -5182,7 +5252,7 @@ struct NotInRange
     const T *ptr=this->getConstPointer();
     mcIdType nbTuple(this->getNumberOfTuples());
     std::size_t nbComps(this->getNumberOfComponents());
-    if(compId<0 || compId>=nbComps)
+    if(compId>=nbComps) // compId >= 0 (it is a size_t)
       throw INTERP_KERNEL::Exception("DataArrayInt::accumulate : Invalid compId specified : No such nb of components !");
     T ret=0;
     for(mcIdType i=0;i<nbTuple;i++)
@@ -5652,6 +5722,50 @@ struct NotInRange
     arrs[0]=dynamic_cast<const DataArrayType *>(this); arrs[1]=other;
     return DataArrayDiscrete<T>::BuildIntersection(arrs);
   }
+  /*!
+   * This method can be applied on allocated with one component DataArrayInt instance.
+   * Locate groups of all consecutive same values in \a this and return them into an indexed array of positions pointing to \a this starting with 0.
+   * Number of tuples of returned array is equal to size of \a this->buildUnique() + 1.
+   * Last value of returned array is equal to \a this->getNumberOfTuples()
+   * 
+   * \b Example:
+   * - \a this : [0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 11]
+   * - \a return is : [0, 1, 3, 5, 6, 8, 11, 12]
+   *
+   * \return a newly allocated array containing the indexed array format of groups by same consecutive value.
+   * \throw if \a this is not allocated or if \a this has not exactly one component.
+   * \sa DataArrayInt::buildUnique, MEDCouplingSkyLineArray::groupPacks
+   */
+  template <class T>
+  DataArrayIdType *DataArrayDiscrete<T>::indexOfSameConsecutiveValueGroups() const
+  {
+    this->checkAllocated();
+    if(this->getNumberOfComponents()!=1)
+      throw INTERP_KERNEL::Exception("DataArrayInt::indexOfSameConsecutiveValueGroups : only single component allowed !");
+    const T *pt(this->begin());
+    const T *const ptEnd(this->end()) , * const ptBg(this->begin());
+    // first find nb of different values in this
+    std::size_t nbOfTuplesOut(0);
+    while( pt != ptEnd )
+    {
+      T val(*pt);
+      const T *endOfPack(std::find_if(pt+1,ptEnd,[val](T elt){ return val!=elt; }));
+      pt = endOfPack;
+      ++nbOfTuplesOut;
+    }
+    MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfTuplesOut+1,1);
+    mcIdType *retPtr(ret->getPointer()); *retPtr++ = 0;
+    pt = this->begin();
+    while( pt != ptEnd )
+    {
+      T val(*pt);
+      const T *endOfPack(std::find_if(pt+1,ptEnd,[val](T elt){ return val!=elt; }));
+      *retPtr++ = ToIdType( std::distance(ptBg,endOfPack) );
+      pt = endOfPack;
+      ++nbOfTuplesOut;
+    }
+    return ret.retn();
+  }
 
   /*!
    * This method can be applied on allocated with one component DataArrayInt instance.
@@ -5660,7 +5774,7 @@ struct NotInRange
    *
    * \return a newly allocated array that contain the result of the unique operation applied on \a this.
    * \throw if \a this is not allocated or if \a this has not exactly one component.
-   * \sa DataArrayInt::buildUniqueNotSorted
+   * \sa DataArrayInt::buildUniqueNotSorted, DataArrayInt::indexOfSameConsecutiveValueGroups
    */
   template <class T>
   typename Traits<T>::ArrayType *DataArrayDiscrete<T>::buildUnique() const
@@ -5668,12 +5782,12 @@ struct NotInRange
     this->checkAllocated();
     if(this->getNumberOfComponents()!=1)
       throw INTERP_KERNEL::Exception("DataArrayInt::buildUnique : only single component allowed !");
-    std::size_t nbOfElements=this->getNumberOfTuples();
-    MCAuto<DataArrayType> tmp=DataArrayType::New();
-    tmp->deepCopyFrom (*this);
-    T *data=tmp->getPointer();
-    T *last=std::unique(data,data+nbOfElements);
-    MCAuto<DataArrayType> ret=DataArrayType::New();
+    std::size_t nbOfElements(this->getNumberOfTuples());
+    MCAuto<DataArrayType> tmp(DataArrayType::New());
+    tmp->deepCopyFrom(*this);
+    T *data(tmp->getPointer());
+    T *last(std::unique(data,data+nbOfElements));
+    MCAuto<DataArrayType> ret(DataArrayType::New());
     ret->alloc(std::distance(data,last),1);
     std::copy(data,last,ret->getPointer());
     return ret.retn();
@@ -6636,7 +6750,7 @@ struct NotInRange
    *          array using decrRef() as it is no more needed.
    * \throw If either ids1 or ids2 is null not allocated or not with one components.
    *
-   * \sa DataArrayInt::findIdForEach
+   * \sa DataArrayInt::findIdForEach, DataArrayInt::FindPermutationFromFirstToSecondDuplicate, DataArrayInt::rankOfElementInThis
    */
   template<class T>
   DataArrayIdType *DataArrayDiscrete<T>::FindPermutationFromFirstToSecond(const DataArrayType *ids1, const DataArrayType *ids2)
@@ -6664,6 +6778,84 @@ struct NotInRange
     return p2.retn();
   }
 
+  /*!
+   * This method tries to find the permutation to apply to the first input \a ids1 to obtain the same array (without considering strings information) the second
+   * input array \a ids2.
+   * \a ids1 and \a ids2 are expected to be both a list of ids (both with number of components equal to one) not sorted and with values that can be negative.
+   * This method will throw an exception is no such permutation array can be obtained. It is typically the case if there is some ids in \a ids1 not in \a ids2 or
+   * inversely.
+   * The difference with DataArrayInt::FindPermutationFromFirstToSecond is that this method supports multiple same values in \a ids1 and \a ids2 whereas 
+   * DataArrayInt::FindPermutationFromFirstToSecond doesn't. It implies that this method my be slower than the DataArrayInt::FindPermutationFromFirstToSecond one.
+   * 
+   * In case of success both assertion will be true (no throw) :
+   * \c ids1->renumber(ret)->isEqual(ids2) where \a ret is the return of this method.
+   * \c ret->transformWithIndArr(ids2)->isEqual(ids1)
+   *
+   * \b Example:
+   * - \a ids1 : [5, 3, 2, 1, 4, 5, 2, 1, 0, 11, 5, 4]
+   * - \a ids2 : [0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 11]
+   * - \a return is : [8, 5, 3, 1, 6, 9, 4, 2, 0, 11, 10, 7] because ids2[8]==ids1[0], ids2[5]==ids1[1], ids2[3]==ids1[2], ids2[1]==ids1[3]...
+   *
+   * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete this
+   *          array using decrRef() as it is no more needed.
+   * \throw If either ids1 or ids2 is null not allocated or not with one components.
+   *
+   * \sa DataArrayInt::findIdForEach, DataArrayInt::FindPermutationFromFirstToSecond, DataArrayInt::occurenceRankInThis
+   */
+  template<class T>
+  DataArrayIdType *DataArrayDiscrete<T>::FindPermutationFromFirstToSecondDuplicate(const DataArrayType *ids1, const DataArrayType *ids2)
+  {
+    if(!ids1 || !ids2)
+      throw INTERP_KERNEL::Exception("DataArrayInt::FindPermutationFromFirstToSecondDuplicate : the two input arrays must be not null !");
+    constexpr char MSG0[] = "DataArrayInt::FindPermutationFromFirstToSecondDuplicate :";
+    ids1->checkAllocated(); ids2->checkAllocated();
+    ids1->checkNbOfComps(1,MSG0); ids2->checkNbOfComps(1,MSG0);
+    mcIdType nbTuples(ids1->getNumberOfTuples());
+    if(nbTuples != ids2->getNumberOfTuples())
+      {
+        std::ostringstream oss; oss << "DataArrayInt::FindPermutationFromFirstToSecondDuplicate : first array has " << ids1->getNumberOfTuples() << " tuples and the second one " << ids2->getNumberOfTuples() << " tuples ! No chance to find a permutation between the 2 arrays !";
+        throw INTERP_KERNEL::Exception(oss.str().c_str());
+      }
+    MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbTuples,1);
+    MCAuto<DataArrayIdType> oids2(ids2->occurenceRankInThis());
+    std::map< std::pair<T,mcIdType>, mcIdType> m;
+    mcIdType pos(0);
+    const mcIdType *oids2Ptr(oids2->begin());
+    for(const T * it2 = ids2->begin() ; it2 != ids2->end() ; ++it2, ++oids2Ptr, ++pos)
+      m[{*it2,*oids2Ptr}] = pos;
+    mcIdType *retPtr(ret->getPointer());
+    //
+    std::map<T,mcIdType> mOccurence1; // see DataArrayInt::occurenceRankInThis : avoid to compute additionnal temporary array
+    //
+    for(const T * it1 = ids1->begin() ; it1 != ids1->end() ; ++it1, ++retPtr)
+    {
+      auto it = mOccurence1.find(*it1);
+      mcIdType occRk1;
+      if( it == mOccurence1.end() )
+      {
+        occRk1 = 0;
+        mOccurence1[*it1] = 1;
+      }
+      else
+      {
+        occRk1 = (*it).second++;
+      }
+      //
+      auto it2 = m.find({*it1,occRk1});
+      if(it2 != m.end())
+      {
+        *retPtr = (*it2).second;
+      }
+      else
+      {
+        std::ostringstream oss; oss << MSG0 << "At pos " << std::distance(ids1->begin(),it1) << " value is " << *it1 << " and occurence rank is " << occRk1 << ". No such item into second array !"; 
+        throw INTERP_KERNEL::Exception(oss.str());
+      }
+      
+    }
+    return ret.retn();
+  }
+
   /*!
    * Returns a C array which is a renumbering map in "Old to New" mode for the input array.
    * This map, if applied to \a start array, would make it sorted. For example, if
@@ -7020,7 +7212,7 @@ struct NotInRange
    *
    * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
    * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
-   * \param [in] idsOfSelectStep
+   * \param [in] idsOfSelectStep step of set of ids of the input extraction
    * \param [in] arrIn arr origin array from which the extraction will be done.
    * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
    * \param [out] arrOut the resulting array