void Graph::correctToSquare() { auto xMap = canvasMap(QtAPI::Plot::xBottom); auto yMap = canvasMap(QtAPI::Plot::yLeft); double xRatio = xMap.sDist() / xMap.pDist(); if (xRatio == 0) { m_needSquareCorrection = true; return; } double ySDist = xRatio * yMap.pDist(); double y0 = (yMap.s1() + yMap.s2()) / 2; setYAxisScale(y0 - ySDist/2, y0 + ySDist/2,false); std::cerr << y0 - ySDist/2 << ' ' << y0 + ySDist/2 << std::endl; }
const std::list<sClLnk *> JLinkage::DoJLClusterization(void (*OnProgress)(float)){ float tEps = (float)1.0f/(1.0f+(float)mModels.size()); // Just a distance to see if the jaccard distance is equal to one float tOneEpsDistance = 1.0f - tEps; // Just a distance to see if the jaccard distance is equal to one // Update neighboardhood information if(mUseKDTree){ mKDTree.optimise(); /* old FIND WITHING RANGE static std::vector<sPtLnkPointer> nearPtsIdx; static bool firsttime = true; if(firsttime){ nearPtsIdx.reserve(500); firsttime = false; } */ for(std::list<sPtLnk *>::iterator tIterPt = mDataPoints.begin(); tIterPt != mDataPoints.end(); ++tIterPt){ if(!(*tIterPt)->mToBeUpdateKDTree) continue; // Threadable build Distance list for kdtree /* old FIND WITHING RANGE nearPtsIdx.clear(); sPtLnkPointer nPtPointer; nPtPointer.mPtLnk = *tIterPt; mKDTree.find_within_range(nPtPointer, mNNeighboardsUpdateDistance, std::back_inserter(nearPtsIdx)); */ sPtLnkPointer nPtPointer; nPtPointer.mPtLnk = *tIterPt; nPtPointer.mPtLnk->mAlreadyFound = false; std::list<sPtLnkPointer> kneigh = FindKNearest(nPtPointer,std::numeric_limits<float>::max(),mKNeighboards, (int)mDataPointsSize); // Find K-Nearest for(std::list<sPtLnkPointer>::iterator tIter = kneigh.begin(); tIter != kneigh.end(); ++tIter){ //for(std::vector<sPtLnkPointer>::iterator tIter = nearPtsIdx.begin(); tIter != nearPtsIdx.end(); ++tIter){ if((*tIter).mPtLnk->mBelongingCluster == (*tIterPt)->mBelongingCluster) continue; bool alreadyPresent = false; for(std::list<sDist *>::iterator distIter = (*tIter).mPtLnk->mBelongingCluster->mPairwiseJaccardDistance.begin(); distIter != (*tIter).mPtLnk->mBelongingCluster->mPairwiseJaccardDistance.end(); distIter++){ if((*distIter)->mCluster1 == (*tIterPt)->mBelongingCluster || (*distIter)->mCluster2 == (*tIterPt)->mBelongingCluster) alreadyPresent = true; } if(alreadyPresent) continue; sDist *tDist = new sDist; tDist->mCluster1 = (*tIterPt)->mBelongingCluster; tDist->mCluster2 = (*tIter).mPtLnk->mBelongingCluster; (*tIterPt)->mBelongingCluster->mPairwiseJaccardDistance.push_back(tDist); (*tIter).mPtLnk->mBelongingCluster->mPairwiseJaccardDistance.push_back(tDist); tDist->mToBeUpdated = true; mDistancesToBeUpdated.push_back(tDist); mDistancesToBeUpdatedSize++; } (*tIterPt)->mToBeUpdateKDTree = false; } } if(OnProgress != NULL) OnProgress(0.01f); // First step: update all the pw distances that needs an update // Please Note: If a distance don't need to be updated it means that it would be certainly equal to 1 from the previous JLClusterization // --> Store also a list with ALL the pairwise unique jaccard distance std::vector<sDist *> mHeapDistanceList(mDistancesToBeUpdatedSize); unsigned int counter = 0; while(mDistancesToBeUpdatedSize > 0){ sDist *tDist = mDistancesToBeUpdated.back(); mDistancesToBeUpdated.pop_back(); mDistancesToBeUpdatedSize--; tDist->mPairwiseJaccardDistance = PSJaccardDist( tDist->mCluster1->mPreferenceSet, tDist->mCluster2->mPreferenceSet, &(tDist->mPairwiseUnion), &(tDist->mPairwiseIntersection) ); tDist->mToBeUpdated = false; if(tDist->mPairwiseJaccardDistance < tOneEpsDistance){ mHeapDistanceList[counter] = tDist; ++counter; } } if(OnProgress != NULL) OnProgress(0.02f); mHeapDistanceList.resize(counter); // A distance that will invalidate the heap, needing a heap resort float mCurrentInvalidatingDistance = 1.0f; // Make the heap std::sort(mHeapDistanceList.begin(), mHeapDistanceList.end(), sDist()); unsigned int currentSortIdx = 0; unsigned int initialDistance = (unsigned int)mHeapDistanceList.size(); while(mHeapDistanceList.size() > 0){ sDist *sCurrentMinDist = NULL; if(currentSortIdx < mHeapDistanceList.size()) sCurrentMinDist = mHeapDistanceList[currentSortIdx]; // TODO speed up previous line! if(sCurrentMinDist == NULL || sCurrentMinDist->mPairwiseJaccardDistance > tOneEpsDistance && mCurrentInvalidatingDistance > tOneEpsDistance ){ // All the distance will be equals to one - clusterization is finished // We've finished since all distances have been processed or are equal to 1.0f mHeapDistanceList.clear(); } else if(sCurrentMinDist->mCluster1 == NULL || sCurrentMinDist->mCluster2 == NULL ){ // Eliminate the non-valid distance(belong to an eliminated clusters for(std::vector<sDist *>::iterator tIterDist = mHeapDistanceList.begin() + currentSortIdx + 1 ; tIterDist != mHeapDistanceList.end(); tIterDist++){ assert((*tIterDist) != sCurrentMinDist); } delete sCurrentMinDist; ++currentSortIdx; } else if(sCurrentMinDist->mPairwiseJaccardDistance > (mCurrentInvalidatingDistance-tEps)){ // We need an heap resort mHeapDistanceList.erase(mHeapDistanceList.begin(), mHeapDistanceList.begin()+(currentSortIdx)); if(mHeapDistanceList.size() > 1){ // First eliminate all the distance equals to one from the heap // Push all these distances to the end of the vector... unsigned int idxElementProcessing = 0; unsigned int idxLastUsefullElement = (unsigned int)mHeapDistanceList.size() - 1; while(idxElementProcessing <= idxLastUsefullElement && idxLastUsefullElement > 0 ){ if(mHeapDistanceList[idxElementProcessing]->mPairwiseJaccardDistance > tOneEpsDistance || mHeapDistanceList[idxElementProcessing]->mCluster1 == NULL || mHeapDistanceList[idxElementProcessing]->mCluster2 == NULL){ // In this case we need to move the distance to the end // Swap elements sDist *temp = mHeapDistanceList[idxElementProcessing]; mHeapDistanceList[idxElementProcessing] = mHeapDistanceList[idxLastUsefullElement]; mHeapDistanceList[idxLastUsefullElement] = temp; // If the distance belongs to one eliminated cluster, delete it if(mHeapDistanceList[idxLastUsefullElement]->mCluster1 == NULL || mHeapDistanceList[idxLastUsefullElement]->mCluster2 == NULL) delete mHeapDistanceList[idxLastUsefullElement]; idxLastUsefullElement--; } else{ idxElementProcessing++; } } if(idxLastUsefullElement > 0){ // ... and then erase them if(idxLastUsefullElement < mHeapDistanceList.size()-1) mHeapDistanceList.erase(mHeapDistanceList.begin()+idxLastUsefullElement+1, mHeapDistanceList.end()); // Re-Set the heap std::sort(mHeapDistanceList.begin(), mHeapDistanceList.end(), sDist()); } else{ // Ok we finished mHeapDistanceList.clear(); } } mCurrentInvalidatingDistance = 2.0f; currentSortIdx = 0; } else{ // The distance is less than the invalidating distance, merge the two cluster and update the other distances accordingly // if kd-tree is used, merge the distances of the clusters for adding the new ones of the new created cluster std::list<sClLnk *> distancesToBeAdded; sCurrentMinDist->mCluster2->mPairwiseJaccardDistance.remove(sCurrentMinDist); sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.remove(sCurrentMinDist); if(mUseKDTree){ for(std::list<sDist *>::iterator distIter1 = sCurrentMinDist->mCluster2->mPairwiseJaccardDistance.begin(); distIter1 != sCurrentMinDist->mCluster2->mPairwiseJaccardDistance.end(); ++distIter1){ // Threadable Check distance to merge KD-Tree bool add = true; // Check if the distance already exists for(std::list<sDist *>::iterator distIter2 = sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.begin(); distIter2 != sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.end(); ++distIter2){ if((*distIter1)->mCluster1 == (*distIter2)->mCluster1 || (*distIter1)->mCluster2 == (*distIter2)->mCluster2 || (*distIter1)->mCluster2 == (*distIter2)->mCluster1 || (*distIter1)->mCluster1 == (*distIter2)->mCluster2){ add = false; // Point already present break; } } if(add){ if((*distIter1)->mCluster1 != sCurrentMinDist->mCluster2) distancesToBeAdded.push_back((*distIter1)->mCluster1); else if((*distIter1)->mCluster2 != sCurrentMinDist->mCluster2) distancesToBeAdded.push_back((*distIter1)->mCluster2); } } } // Update the cluster pointer of all the points of the deleted cluster for(std::list<sPtLnk *>::iterator ptIter = sCurrentMinDist->mCluster2->mBelongingPts.begin(); ptIter != sCurrentMinDist->mCluster2->mBelongingPts.end(); ptIter++) (*ptIter)->mBelongingCluster = sCurrentMinDist->mCluster1; // Merge the two clusters into cluster 1 sCurrentMinDist->mCluster1->mPreferenceSet &= sCurrentMinDist->mCluster2->mPreferenceSet; sCurrentMinDist->mCluster1->mBelongingPts.merge(sCurrentMinDist->mCluster2->mBelongingPts); // Delete cluster 2 mDataClusters.remove(sCurrentMinDist->mCluster2); if(mUseKDTree){ for(std::list<sClLnk *>::iterator clIter = distancesToBeAdded.begin(); clIter != distancesToBeAdded.end(); ++clIter){ // Threadable Add kd-tree distances sDist *tDist = new sDist; tDist->mCluster1 = sCurrentMinDist->mCluster1; tDist->mCluster2 = *clIter; sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.push_back(tDist); (*clIter)->mPairwiseJaccardDistance.push_back(tDist); mHeapDistanceList.push_back(tDist); } } // Update all the distances of the old cluster -- delete for(std::list<sDist *>::iterator tIterDist = sCurrentMinDist->mCluster2->mPairwiseJaccardDistance.begin(); tIterDist != sCurrentMinDist->mCluster2->mPairwiseJaccardDistance.end(); tIterDist++){ // Threadable: delete distance for the old cluster if(sCurrentMinDist != (*tIterDist)){ if((*tIterDist)->mCluster1 != sCurrentMinDist->mCluster2) (*tIterDist)->mCluster1->mPairwiseJaccardDistance.remove( (*tIterDist)); else if((*tIterDist)->mCluster2 != sCurrentMinDist->mCluster2) (*tIterDist)->mCluster2->mPairwiseJaccardDistance.remove( (*tIterDist)); (*tIterDist)->mCluster1 = NULL; (*tIterDist)->mCluster2 = NULL; } } // Do additional user-defined update steps if specified if(mClusterMergeAdditionalOperation != NULL) mClusterMergeAdditionalOperation(sCurrentMinDist->mCluster1); #ifndef JL_NO_THREADS boost::thread_group *tg = new boost::thread_group(); // Update all the distances of the new cluster for(std::list<sDist *>::iterator tIterDist = sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.begin(); tIterDist != sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.end(); tIterDist++){ // Update distances tg->create_thread(boost::bind(&(UpdateDistance),*tIterDist, &mCurrentInvalidatingDistance, mClusterClusterDiscardTest)); if(tg->size() >= MAXTHREADS){ tg->join_all(); delete tg; tg = new boost::thread_group(); } } tg->join_all(); delete tg; #else for(std::list<sDist *>::iterator tIterDist = sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.begin(); tIterDist != sCurrentMinDist->mCluster1->mPairwiseJaccardDistance.end(); tIterDist++){ // Update distances JLinkage::UpdateDistance(*tIterDist, &mCurrentInvalidatingDistance, mClusterClusterDiscardTest); } #endif if(OnProgress != NULL) OnProgress(1.0f - ((float) (mHeapDistanceList.size() - currentSortIdx) / (float)initialDistance)); // Delete old cluster if(sCurrentMinDist->mCluster2 && mDestroyAdditionalData) mDestroyAdditionalData(sCurrentMinDist->mCluster2); delete sCurrentMinDist->mCluster2; delete sCurrentMinDist; ++currentSortIdx; } } if(OnProgress != NULL) OnProgress(1.0f); // return the list of clusters return mDataClusters; }