void MTnode::SortEntries () { int n = NumEntries (); MTentry **array = new MTentry *[n], *objEntry = NULL; for (int i=0; i<n; i++) { array[i] = (MTentry *) ((MTentry *)(*this)[i].Ptr())->Copy(); if (&((MTentry *)(*this)[i].Ptr())->object() == obj) { objEntry = array[i]; } } qsort (array, n, sizeof(MTentry *), MTentryCmp); while (NumEntries() > 0) { DeleteEntry (0); // also delete the obj } int obji = -1; for (int i=0; i<n; i++) { InsertBefore (*(array[i]), i); if (array[i] == objEntry) { obji = i; } delete array[i]; } delete []array; if (obji >= 0) { obj = &((MTentry *)(*this)[obji].Ptr())->object(); } }
GiSTnode * MTnode::PickSplit() { MTnode *rightnode; int leftdeletes, rightdeletes; // number of entries to be deleted from each node int *leftvec=new int[NumEntries()], *rightvec=new int[NumEntries()]; // array of entries to be deleted from each node // promote the right node (possibly reassigning the left node); // the right node's page is copied from left node; // we'll delete from the nodes as appropriate after the splitting phase // cout << "In PickSplit with node " << this << "\n"; rightnode=PromotePart(); // now perform the split Split(rightnode, leftvec, rightvec, &leftdeletes, &rightdeletes); // complexity: O(n) // given the deletion vectors, do bulk deletes DeleteBulk(leftvec, leftdeletes); rightnode->DeleteBulk(rightvec, rightdeletes); // cout << "Nodes:\n" << this << rightnode; // order the entries in both nodes Order(); rightnode->Order(); delete []leftvec; delete []rightvec; // return the right node return rightnode; }
const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte) { const char *cs = "ISO6937"; // Workaround for broadcaster stupidity: according to // "ETSI EN 300 468" the default character set is ISO6937. But unfortunately some // broadcasters actually use ISO-8859-9, but fail to correctly announce that. if (OverrideCharacterTable) cs = OverrideCharacterTable; if (isSingleByte) *isSingleByte = false; if (length <= 0) return cs; unsigned int tag = buffer[0]; if (tag >= 0x20) return cs; if (tag == 0x10) { if (length >= 3) { tag = (buffer[1] << 8) | buffer[2]; if (tag < NumEntries(CharacterTables2) && CharacterTables2[tag]) { buffer += 3; length -= 3; if (isSingleByte) *isSingleByte = true; return CharacterTables2[tag]; } } } else if (tag < NumEntries(CharacterTables1) && CharacterTables1[tag]) { buffer += 1; length -= 1; if (isSingleByte) *isSingleByte = tag <= SingleByteLimit; return CharacterTables1[tag]; } return cs; }
void MTnode::Print(ostream& os) const { if(obj!=NULL) os << *obj << " "; // else cout << "obj NULL...\n"; os << ((MTnode *)this)->Path() << " #Entries: " << NumEntries() << ", Level " << Level(); if(IsLeaf()) os << "(Leaf)"; else os << "(Internal)"; os << ", Sibling: " << Sibling() << ", Size: " << Size() << "/" << Tree()->Store()->PageSize() << endl; for(int i=0; i<NumEntries(); i++) (*this)[i]->Print(os); }
void MTnode::Print (ostream& os) const { if (obj) { os << *obj << " "; } os << ((MTnode *)this)->Path() << " #Entries: " << NumEntries() << ", Level " << Level(); IsLeaf () ? os << "(Leaf)" : os << "(Internal)"; os << ", Sibling: " << Sibling() << ", Size: " << Size() << "/" << Tree()->Store()->PageSize() << endl; for (int i=0; i<NumEntries(); i++) { (*this)[i]->Print(os); } }
// We are moving entries from node, which is to our right, to this. // If this is a non-empty internal page, the rightmost entry on this // has an upperbound of +inf, and the leftmost entry on node has // a lower bound of -inf. This code takes care of that -- both // these values should be set to the right bound of our parent entry. void BTnode::Coalesce(const GiSTnode& node, const GiSTentry& entry) // entry is in 1 level up, and // points to this { if (!NumEntries() || IsLeaf()) { GiSTnode::Coalesce(node, entry); } else { int n = NumEntries(); GiSTnode::Coalesce(node, entry); const BTentry &bte = (const BTentry&) entry; ((BTentry*)(*this)[n-1].Ptr())->SetUpperBound(bte.UpperBound()); ((BTentry*)(*this)[n].Ptr())->SetLowerBound(bte.UpperBound()); } }
// insert before the original number according to the sequence instead of index void MTnode::InsertBefore (const GiSTentry& newEntry, int index) { int n = NumEntries (); assert (index>=0 && index<=n); BOOL bOrder = TRUE; if (index > 0) { bOrder = (*this)[index-1]->Compare(newEntry) <= 0; } if (index < n) { bOrder = bOrder && (*this)[index]->Compare(newEntry) >= 0; } if (bOrder) { // yes, the position is right for this entry GiSTentry *entry = (GiSTentry *) newEntry.Copy (); entry->SetLevel(Level()); entry->SetPosition(index); entry->SetNode(this); // Move everything else over for (int i=n; i>index; i--) { GiSTentry *e = (*this)[i-1]; e->SetPosition(i); (*this)[i] = e; } // Stick the entry in (*this)[index] = entry; // Bump up the count SetNumEntries (n+1); } else { Insert (newEntry); // find the right place } }
void BTnode::InsertBefore(const GiSTentry& entry, int index) { // Only BTentry's can be inserted into BTnodes. assert(entry.IsA() == BTENTRY_CLASS); BTentry e((const BTentry&) entry); // If this is an internal node, adjust the lower/upper bounds if (!IsLeaf()) { // If not leftmost entry... if (index != 0) { // -inf changes to the upper bound of previous item BTentry *prev = (BTentry*) (*this)[index-1].Ptr(); if (e.LowerBound() == NegInf) e.SetLowerBound(prev->UpperBound()); } // If not rightmost entry... if (index != NumEntries()) { // +inf changes to the lower bound of next item BTentry *next = (BTentry*) (*this)[index].Ptr(); if (e.UpperBound() == PosInf) e.SetUpperBound(next->LowerBound()); } } // Insert it into the node GiSTnode::InsertBefore(e, index); }
void MTnode::InvalidateEntries () { for (int i=0; i<NumEntries(); i++) { ((MTentry *)((*this)[i].Ptr()))->Key()->distance = -MaxDist(); } }
void MTnode::InsertBefore(const GiSTentry& entry, int index) { int n=NumEntries(); BOOL ordered=TRUE; if(index>0) ordered=((*this)[index-1]->Compare(entry)<=0); if(index<n) ordered=ordered&&((*this)[index]->Compare(entry)>=0); if(ordered) { // yes, the position is right for this entry assert(index<=n); GiSTentry *e=(GiSTentry *)entry.Copy(); e->SetLevel(Level()); e->SetPosition(index); e->SetNode(this); // Move everything else over for(int i=n; i>index; i--) { GiSTentry *e=(*this)[i-1]; e->SetPosition(i); (*this)[i]=e; } // Stick the entry in (*this)[index]=e; // Bump up the count SetNumEntries(n+1); } else Insert(entry); // find the right place }
int * MTnode::PickCandidates() { int max_ind=MIN(NUM_CANDIDATES, NumEntries()), *vec=new int[max_ind], i; BOOL *used=new BOOL[NumEntries()]; for(i=0; i<NumEntries(); i++) used[i]=(((MTentry *)(*this)[i].Ptr())->Key()->distance==0); // insert in vec the indices of the candidates for promotion for(i=0; i<max_ind; i++) { int j; do j=PickRandom(0, NumEntries()); while(used[j]); vec[i]=j; used[j]=TRUE; } return vec; }
void GiSTnode::InsertBefore (const GiSTentry& entry, int index) { assert (index <= NumEntries()); GiSTentry *e = (GiSTentry*)entry.Copy(); e->SetLevel (Level()); e->SetPosition (index); e->SetNode (this); // Move everything else over for (int i=NumEntries(); i>index; i--) { GiSTentry *e = (*this)[i-1]; e->SetPosition (i); (*this)[i] = e; } // Stick the entry in (*this)[index] = e; // Bump up the count numEntries++; }
void GiSTnode::Coalesce (const GiSTnode &source) { // Coalesce by one-by-one insertion // Take each entry from the source node // and insert it into this node. for (int i=0; i<source.numEntries; i++) { // GiSTentry& e=source[i]; // this is deleted by myself InsertBefore ((GiSTentry&)source[i], NumEntries()); } }
// quick-sort the entries with respect to the distance from the parent void MTnode::Order() { int i, obji=-1, n=NumEntries(); MTentry **array=new MTentry *[n], *objEntry=NULL; for(i=0; i<n; i++) { array[i]=(MTentry *)((MTentry *)(*this)[i].Ptr())->Copy(); if(obj==&((MTentry *)(*this)[i].Ptr())->object()) objEntry=array[i]; } qsort(array, n, sizeof(MTentry *), MTentrycmp); while(NumEntries()>0) DeleteEntry(0); for(i=0; i<n; i++) { InsertBefore(*(array[i]), i); if(objEntry==array[i]) obji=i; delete array[i]; } delete []array; if(obji>=0) obj=&((MTentry *)(*this)[obji].Ptr())->object(); }
void GiSTnode::Insert(const GiSTentry& entry) { // Find out where to insert it int i; for (i=0; i<NumEntries(); i++) if ((*this)[i]->Compare(entry) > 0) break; // Do the deed InsertBefore(entry, i); }
void GiSTnode::Coalesce(const GiSTnode &source, const GiSTentry& entry) // entry is the entry in the // parent node that points to this { // Coalesce by one-by-one insertion // Take each entry from the source node // and insert it into this node. for (int i=0; i<source.numEntries; i++) { GiSTentry& e = source[i]; InsertBefore(e, NumEntries()); } }
GiSTnode * MTnode::PickSplit () { int lDel, rDel; // number of entries to be deleted from each node int *lArray = new int[NumEntries()], *rArray = new int[NumEntries()]; // array of entries to be deleted from each node // promote the right node (possibly reassigning the left node); // the right node's page is copied from left node; // we'll delete from the nodes as appropriate after the splitting phase MTnode *rNode = PromotePart (); // now perform the split Split (rNode, lArray, rArray, &lDel, &rDel); // complexity: O(n) // given the deletion vectors, do bulk deletes DeleteBulk (lArray, lDel); rNode->DeleteBulk(rArray, rDel); // order the entries in both nodes SortEntries (); rNode->SortEntries(); delete []lArray; delete []rArray; return rNode; // return the right node }
bool SetSystemCharacterTable(const char *CharacterTable) { if (CharacterTable) { for (unsigned int i = 0; i < NumEntries(CharacterTables1); i++) { if (CharacterTables1[i] && strcasecmp(CharacterTable, CharacterTables1[i]) == 0) { SystemCharacterTable = CharacterTables1[i]; SystemCharacterTableIsSingleByte = i <= SingleByteLimit; return true; } } for (unsigned int i = 0; i < NumEntries(CharacterTables2); i++) { if (CharacterTables2[i] && strcasecmp(CharacterTable, CharacterTables2[i]) == 0) { SystemCharacterTable = CharacterTables2[i]; SystemCharacterTableIsSingleByte = true; return true; } } } else { SystemCharacterTable = NULL; SystemCharacterTableIsSingleByte = true; return true; } return false; }
GiSTlist<MTentry *> MTnode::RangeSearch(const MTquery &query) { GiSTlist<MTentry *> result; if(IsLeaf()) for(int i=0; i<NumEntries(); i++) { MTentry *e=(MTentry *)(*this)[i].Ptr()->Copy(); MTquery *q=(MTquery *)query.Copy(); if(q->Consistent(*e)) { // object qualifies e->setmaxradius(q->Grade()); result.Append(e); } else delete e; delete q; } else for(int i=0; i<NumEntries(); i++) { MTentry *e=(MTentry *)(*this)[i].Ptr(); MTquery *q=(MTquery *)query.Copy(); if(q->Consistent(*e)) { // sub-tree not excluded GiSTpath childpath=Path(); MTnode *child; GiSTlist<MTentry *>list; childpath.MakeChild(e->Ptr()); child=(MTnode *)((MT *)Tree())->ReadNode(childpath); list=child->RangeSearch(*q); // recurse the search while(!list.IsEmpty()) result.Append(list.RemoveFront()); delete child; } delete q; } return result; }
GiSTlist<MTentry *> MTnode::RangeSearch (const MTquery &query) { GiSTlist<MTentry *> results; if (IsLeaf()) { for (int i=0; i<NumEntries(); i++) { MTentry *entry = (MTentry *) (*this)[i].Ptr()->Copy(); MTquery *newQuery = (MTquery *) query.Copy(); if (newQuery->Consistent(*entry)) { // object qualifies entry->SetMaxRadius(newQuery->Grade()); results.Append (entry); } else { delete entry; } delete newQuery; } } else { for (int i=0; i<NumEntries(); i++) { MTentry *entry = (MTentry *) (*this)[i].Ptr(); MTquery *newQuery = (MTquery *) query.Copy(); if (newQuery->Consistent(*entry)) { // sub-tree included GiSTpath childPath = Path (); childPath.MakeChild (entry->Ptr()); MTnode *childNode = (MTnode *) ((MT *)Tree())->ReadNode(childPath); GiSTlist<MTentry *> childResults = childNode->RangeSearch(*newQuery); // recurse the search while (!childResults.IsEmpty()) { results.Append (childResults.RemoveFront()); } delete childNode; } delete newQuery; } } return results; }
void MTnode::mMRadius(MTentry *e) const { for (int i=0; i<NumEntries(); i++) { MTentry *mte=(MTentry *)(*this)[i].Ptr(); mte->Key()->recomp=FALSE; if (mte->Key()->distance<0) { // this code should be unreachable cout << "Computing distance with " << mte << "??????????????????????????????????????????????\n"; // this code should be unreachable mte->Key()->distance=obj->distance(mte->object()); } if (mte->Key()->distance+mte->maxradius()>e->maxradius()) e->setmaxradius(mte->Key()->distance+mte->maxradius()); if (MAX(mte->Key()->distance-mte->maxradius(), 0)<e->minradius()) e->setminradius(MAX(mte->Key()->distance-mte->maxradius(), 0)); } }
void GiSTnode::Print (ostream& os) const { os << path << " #Entries: " << NumEntries() << ", "; os << "Level " << Level(); if (IsLeaf()) { os << "(Leaf)"; } else { os << "(Internal)"; } os << ", Sibling: " << Sibling(); os << ", Size: " << Size() << "/" << tree->Store()->PageSize() << endl; for (int i=0; i<numEntries; i++) { (*this)[i]->Print(os); } }
GiSTentry* BTnode::Union() const { BTentry *u = new BTentry; int first = 1; for (int i=0; i<NumEntries(); i++) { BTentry *bte = (BTentry*) (*this)[i].Ptr(); if (first || bte->LowerBound() < u->LowerBound()) u->SetLowerBound(bte->LowerBound()); if (first || bte->UpperBound() > u->UpperBound()) u->SetUpperBound(bte->UpperBound()); first = 0; } //u->SetPtr(node.Path().Page()); return u; }
void GiSTnode::Pack(char *page) const { // Pack the header GiSTheader *h = (GiSTheader *) page; h->level = Level(); h->numEntries = NumEntries(); h->sibling = Sibling(); int fixlen = FixedLength(); GiSTlte *ltable = (GiSTlte *) (page+tree->Store()->PageSize()); GiSTlte ltptr = GIST_PAGE_HEADER_SIZE; for (int i=0; i<numEntries; i++) { GiSTcompressedEntry compressedEntry = (*this)[i]->Compress(); if (fixlen) assert(fixlen == compressedEntry.keyLen); // Copy the entry onto the page if (compressedEntry.keyLen > 0) memcpy(page+ltptr, compressedEntry.key, compressedEntry.keyLen); memcpy(page+ltptr+compressedEntry.keyLen, &compressedEntry.ptr, sizeof(GiSTpage)); // Be tidy if (compressedEntry.key) delete compressedEntry.key; // Enter a pointer to the entry in the line table if (!fixlen) *--ltable = ltptr; int entryLen = compressedEntry.keyLen + sizeof(GiSTpage); ltptr += entryLen; } // Store extra line table entry so we know last entry's length *--ltable = ltptr; }
void MTnode::mMRadius (MTentry *unionEntry) const { for (int i=0; i<NumEntries(); i++) { MTentry *entry = (MTentry *) (*this)[i].Ptr(); entry->Key()->splitted = FALSE; if (entry->Key()->distance < 0) { entry->Key()->distance = obj->distance(entry->object()); } double tempMax = entry->Key()->distance + entry->MaxRadius(); if (tempMax > unionEntry->MaxRadius()) { unionEntry->SetMaxRadius(tempMax); } double tempMin = MAX(entry->Key()->distance - entry->MaxRadius(), 0); if (tempMin < unionEntry->MinRadius()) { unionEntry->SetMinRadius(tempMin); } } }
int * MTnode::PickCandidates () { int n = NumEntries (); BOOL *bUsed = new BOOL[n]; for (int i=0; i<n; i++) { bUsed[i] = ((MTentry *)(*this)[i].Ptr())->Key()->distance == 0; // exclude parent entry } int count = MIN (NUM_CANDIDATES, n-1), *results = new int[count]; // insert in results the indices of the candidates for promotion for (int i=0; i<count; i++) { int j; do { j = PickRandom (0, n); } while (bUsed[j]); results[i] = j; bUsed[j] = TRUE; } delete []bUsed; return results; }
// SearchMinPenalty returns where a new entry should be inserted. // Overriden to insert the distance from the parent in the new entry. GiSTpage MTnode::SearchMinPenalty(const GiSTentry& newEntry) const { MTentry *minEntry=NULL; MTpenalty *minPenalty=NULL; for(int i=0; i<NumEntries(); i++) { MTentry *e=(MTentry *)((*this)[i].Ptr()); assert((MTnode *)e->Node()==this); MTpenalty *penalty=(MTpenalty *)e->Penalty(newEntry, minPenalty); // use the alternate Penalty method in order to avoid some distance computations if((minEntry==NULL)||(*penalty)<(*minPenalty)) { minEntry=e; if(minPenalty) delete minPenalty; minPenalty=penalty; } else delete penalty; } ((MTentry&)newEntry).Key()->distance=minPenalty->distance; delete minPenalty; return minEntry->Ptr(); }
void MTnode::Split (MTnode *node, int *lArray, int *rArray, int *lDel, int *rDel) { *lDel = *rDel = 0; int n = NumEntries (); double *lDist = new double[n], *rDist = new double[n]; for (int i=0; i<n; i++) { // compute the distance between entries and their parent entry lDist[i] = Distance (i); rDist[i] = node->Distance(i); } // balance entries up to minimum utilization while (*lDel < n*MIN_UTIL && *rDel < n*MIN_UTIL) { int i = FindMin (lDist, n); ((MTentry *)(*this)[i].Ptr())->Key()->distance = lDist[i]; ((MTentry *)(*node)[i].Ptr())->Key()->distance = rDist[i]; rArray[(*rDel)++] = i; lDist[i] = rDist[i] = MAXDOUBLE; i = FindMin (rDist, n); if (i >= 0) { ((MTentry *)(*node)[i].Ptr())->Key()->distance = rDist[i]; ((MTentry *)(*this)[i].Ptr())->Key()->distance = lDist[i]; lArray[(*lDel)++] = i; lDist[i] = rDist[i] = MAXDOUBLE; } } // then perform the hyperplane split (assigning each entry to its nearest node) for (int i=0; i<n; i++) { if (rDist[i] == MAXDOUBLE) { // entry have been assigned through balanced policy continue; } ((MTentry *)(*this)[i].Ptr())->Key()->distance = lDist[i]; ((MTentry *)(*node)[i].Ptr())->Key()->distance = rDist[i]; ((MTentry *)(*this)[i].Ptr())->Key()->distance < ((MTentry *)(*node)[i].Ptr())->Key()->distance ? rArray[(*rDel)++] = i : lArray[(*lDel)++] = i; } delete []rDist; delete []lDist; }
void MTnode::Split(MTnode *node, int *leftvec, int *rightvec, int *leftdeletes, int *rightdeletes) { int i; *rightdeletes=0; *leftdeletes=0; // cout << "Now splitting between:\n"; // cout << obj << " & " << node->obj << endl; switch(SPLIT_FUNCTION) { case G_HYPERPL: { int numentries=NumEntries(); double *rightdistances=new double[numentries], *leftdistances=new double[numentries]; for(i=0; i<numentries; i++) { leftdistances[i]=distance(i); rightdistances[i]=node->distance(i); } while((*rightdeletes<numentries*MIN_UTIL)&&(*leftdeletes<numentries*MIN_UTIL)) { // balance entries up to minimum utilization (assigning to each node its remaining nearest entry) i=FindMin(leftdistances, numentries); ((MTentry *)(*this)[i].Ptr())->Key()->distance=leftdistances[i]; ((MTentry *)(*node)[i].Ptr())->Key()->distance=rightdistances[i]; // cout << (*this)[i].Ptr() << " (" << leftdistances[i] << ", " << rightdistances[i] << ") to the left\n"; rightvec[(*rightdeletes)++]=i; rightdistances[i]=MAXDOUBLE; leftdistances[i]=MAXDOUBLE; i=FindMin(rightdistances, numentries); if(i>=0) { ((MTentry *)(*node)[i].Ptr())->Key()->distance=rightdistances[i]; ((MTentry *)(*this)[i].Ptr())->Key()->distance=leftdistances[i]; // cout << (*node)[i].Ptr() << " (" << leftdistances[i] << ", " << rightdistances[i] << ") to the right\n"; leftvec[(*leftdeletes)++]=i; rightdistances[i]=MAXDOUBLE; leftdistances[i]=MAXDOUBLE; } } for(i=0; i<numentries; i++) { // then perform the hyperplane split (assigning each entry to its nearest node) if(rightdistances[i]==MAXDOUBLE) continue; // ((MTentry *)(*this)[i].Ptr())->Key()->distance=distance(i)+((MTentry *)(*this)[i].Ptr())->maxradius(); // ((MTentry *)(*node)[i].Ptr())->Key()->distance=node->distance(i)+((MTentry *)(*node)[i].Ptr())->maxradius(); ((MTentry *)(*this)[i].Ptr())->Key()->distance=leftdistances[i]; ((MTentry *)(*node)[i].Ptr())->Key()->distance=rightdistances[i]; if (((MTentry *)(*this)[i].Ptr())->Key()->distance<((MTentry *)(*node)[i].Ptr())->Key()->distance) { // cout << (*this)[i].Ptr() << " (" << ((MTentry *)(*this)[i].Ptr())->Key()->distance << ", " << ((MTentry *)(*node)[i].Ptr())->Key()->distance << ") to the left\n"; rightvec[(*rightdeletes)++]=i; } else { // cout << (*node)[i].Ptr() << " (" << ((MTentry *)(*this)[i].Ptr())->Key()->distance << ", " << ((MTentry *)(*node)[i].Ptr())->Key()->distance << ") to the right\n"; leftvec[(*leftdeletes)++]=i; } } delete []rightdistances; delete []leftdistances; break; } case BAL_G_HYPERPL: { int numentries=NumEntries(), j; for(i=0; i<NumEntries(); i++) { // assign the parents' entries if(obj==&((MTentry *)((*this)[i].Ptr()))->object()) { // cout << (*this)[i].Ptr() << " to the left\n"; ((MTentry *)(*this)[i].Ptr())->Key()->distance=0; rightvec[(*rightdeletes)++]=i; } if(node->obj==&((MTentry *)((*node)[i].Ptr()))->object()) { // cout << (*node)[i].Ptr() << " to the right\n"; ((MTentry *)(*node)[i].Ptr())->Key()->distance=0; leftvec[(*leftdeletes)++]=i; } } for(i=0; (*rightdeletes<(numentries+1)/2)&&(*leftdeletes<(numentries+1)/2); i++) { // perform the hyperplane split up to a node utilization of the 50% if((obj!=&((MTentry *)((*this)[i].Ptr()))->object())&&(node->obj!=&((MTentry *)((*node)[i].Ptr()))->object())) { // the parents' entries were already assigned ((MTentry *)(*this)[i].Ptr())->Key()->distance=distance(i); ((MTentry *)(*node)[i].Ptr())->Key()->distance=node->distance(i); if (((MTentry *)(*this)[i].Ptr())->Key()->distance<((MTentry *)(*node)[i].Ptr())->Key()->distance) { // cout << (*this)[i].Ptr() << " (" << ((MTentry *)(*this)[i].Ptr())->Key()->distance << ", " << ((MTentry *)(*node)[i].Ptr())->Key()->distance << ") to the left\n"; rightvec[(*rightdeletes)++]=i; } else { // cout << (*node)[i].Ptr() << " (" << ((MTentry *)(*this)[i].Ptr())->Key()->distance << ", " << ((MTentry *)(*node)[i].Ptr())->Key()->distance << ") to the right\n"; leftvec[(*leftdeletes)++]=i; } } } // then balance the remaining entries for(j=*rightdeletes; j<numentries/2; j++, i++) if((obj!=&((MTentry *)((*this)[i].Ptr()))->object())&&(node->obj!=&((MTentry *)((*node)[i].Ptr()))->object())) { // the parents' entries were already assigned ((MTentry *)(*this)[i].Ptr())->Key()->distance=distance(i); ((MTentry *)(*node)[i].Ptr())->Key()->distance=-maxDist(); // cout << (*this)[i].Ptr() << " (" << ((MTentry *)(*this)[i].Ptr())->Key()->distance << ") to the left\n"; rightvec[(*rightdeletes)++]=i; } else j--; for(j=*leftdeletes; j<numentries/2; j++, i++) if((obj!=&((MTentry *)((*this)[i].Ptr()))->object())&&(node->obj!=&((MTentry *)((*node)[i].Ptr()))->object())) { // the parents' entries were already assigned ((MTentry *)(*node)[i].Ptr())->Key()->distance=node->distance(i); ((MTentry *)(*this)[i].Ptr())->Key()->distance=-maxDist(); // cout << (*node)[i].Ptr() << " (" << ((MTentry *)(*node)[i].Ptr())->Key()->distance << ") to the right\n"; leftvec[(*leftdeletes)++]=i; } else j--; break; } case BALANCED: { // assign iteratively to each node its remaining nearest entry int numentries=NumEntries(); double *rightdistances=new double[numentries], *leftdistances=new double[numentries]; for(i=0; i<numentries; i++) { leftdistances[i]=distance(i); rightdistances[i]=node->distance(i); } while((*rightdeletes<(numentries+1)/2)&&(*leftdeletes<(numentries+1)/2)) { i=FindMin(leftdistances, numentries); ((MTentry *)(*this)[i].Ptr())->Key()->distance=leftdistances[i]; ((MTentry *)(*node)[i].Ptr())->Key()->distance=rightdistances[i]; // cout << (*this)[i].Ptr() << " (" << leftdistances[i] << ", " << rightdistances[i] << ") to the left\n"; rightvec[(*rightdeletes)++]=i; rightdistances[i]=MAXDOUBLE; leftdistances[i]=MAXDOUBLE; i=FindMin(rightdistances, numentries); if(i>=0) { ((MTentry *)(*node)[i].Ptr())->Key()->distance=rightdistances[i]; ((MTentry *)(*this)[i].Ptr())->Key()->distance=leftdistances[i]; // cout << (*node)[i].Ptr() << " (" << leftdistances[i] << ", " << rightdistances[i] << ") to the right\n"; leftvec[(*leftdeletes)++]=i; rightdistances[i]=MAXDOUBLE; leftdistances[i]=MAXDOUBLE; } } delete []rightdistances; delete []leftdistances; break; } } }
MTnode * MTnode::PromoteVote() { MTnode *newnode=(MTnode *)NCopy(); int i; switch(PROMOTE_VOTE_FUNCTION) { case RANDOMV: { // complexity: constant // cout << "Random voting: "; // pick a random entry (different from the parent) do i=PickRandom(0, NumEntries()); while(((MTentry *)(*this)[i].Ptr())->Key()->distance==0); // cout << "Entry " << (*this)[i].Ptr() << " chosen.\n"; newnode->obj=&((MTentry *)((*newnode)[i].Ptr()))->object(); break; } case SAMPLINGV: { // complexity: O(kn) distance computations // cout << "Sampling voting: "; int *vec=PickCandidates(), bestcand, bestld, bestrd, *bestlv=new int[NumEntries()], *bestrv=new int[NumEntries()]; double minvalue=MAXDOUBLE, sec_minvalue=MAXDOUBLE, **distances=new double *[MIN(NUM_CANDIDATES, NumEntries())]; // distance matrix // find the candidate with minimum radius for (i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) { MTentry *cand=(MTentry *)((*this)[vec[i]].Ptr()), *e1=new MTentry, *e2=new MTentry; MTnode *node1=(MTnode *)Copy(), *node2=(MTnode *)NCopy(); double value, sec_value; int leftdeletes, rightdeletes, *leftvec=new int[NumEntries()], *rightvec=new int[NumEntries()], j; // cout << "Entry " << cand; // initialize distance matrix distances[i]=new double[NumEntries()]; for (j=0; j<NumEntries(); j++) distances[i][j]=((vec[i]==j)? 0: cand->object().distance(((MTentry *)((*this)[j].Ptr()))->object())); for(j=0; j<NumEntries(); j++) ((MTentry *)((*node2)[j].Ptr()))->Key()->distance=distances[i][j]; node1->obj=obj; node2->obj=&((MTentry *)((*this)[vec[i]].Ptr()))->object(); // perform the split node1->Split(node2, leftvec, rightvec, &leftdeletes, &rightdeletes); // given the deletion vectors, do bulk deletes node1->DeleteBulk(leftvec, leftdeletes); node2->DeleteBulk(rightvec, rightdeletes); e1->InitKey(); e2->InitKey(); e1->setobject(*node1->obj); e2->setobject(*node2->obj); e1->setmaxradius(0); e2->setmaxradius(0); e1->setminradius(MAXDOUBLE); e2->setminradius(MAXDOUBLE); // compute the radii node1->mMRadius(e1); node2->mMRadius(e2); // check the result value=MAX(e1->maxradius(), e2->maxradius()); // this is minMAX_RADII sec_value=MIN(e1->maxradius(), e2->maxradius()); if((value<minvalue)||((value==minvalue)&&(sec_value<sec_minvalue))) { int index; minvalue=value; sec_minvalue=sec_value; bestld=leftdeletes; bestrd=rightdeletes; for(index=0; index<leftdeletes; index++) bestlv[index]=leftvec[index]; for(index=0; index<rightdeletes; index++) bestrv[index]=rightvec[index]; bestcand=i; } // be tidy delete e1; delete e2; delete node1; delete node2; delete []leftvec; delete []rightvec; } // cout << "Entry " << (*this)[vec[bestcand]].Ptr() << " chosen.\n"; newnode->obj=&((MTentry *)((*newnode)[vec[bestcand]].Ptr()))->object(); // update the distance of the children from the new parent for (i=0; i<NumEntries(); i++) ((MTentry *)((*newnode)[i].Ptr()))->Key()->distance=distances[bestcand][i]; for (i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) delete []distances[i]; delete []distances; delete []vec; delete []bestlv; delete []bestrv; break; } case MAX_LB_DIST: { // complexity: constant double maxdist=-1; int maxcand; // cout << "Largest min dist voting:\n"; if(Tree()->IsOrdered()) maxcand=NumEntries()-1; // if the tree is ordered we can choose the last element else // otherwise we have to search the object which is farthest from the parent for (i=0; i<NumEntries(); i++) { MTentry *e=(MTentry *)((*this)[i].Ptr()); if (e->Key()->distance>maxdist) { maxdist=e->Key()->distance; maxcand=i; } } // cout << "Entry " << (*this)[maxcand].Ptr() << " chosen.\n"; newnode->obj=&((MTentry *)((*newnode)[maxcand].Ptr()))->object(); break; } case mM_RAD: { // complexity: constant double minradius=MAXDOUBLE; int bestcand; // cout << "Best radius voting:\n"; for (i=0; i<NumEntries(); i++) { MTentry *cand=(MTentry *)((*this)[i].Ptr()); double radius=0; if(cand->Key()->distance==0) continue; for (int j=0; j<NumEntries(); j++) { MTentry *e=(MTentry *)((*this)[j].Ptr()); double dmin, dmax; if (i==j) continue; dmin=fabs(cand->Key()->distance-e->Key()->distance); dmax=cand->Key()->distance+e->Key()->distance; switch (RADIUS_FUNCTION) { case LB: radius=MAX(radius, dmin); break; case AVG: radius=MAX(radius, (dmin+dmax)/2); break; case UB: radius=MAX(radius, dmax); break; } } if (radius<minradius) { bestcand=i; minradius=radius; } } // cout << "Entry " << (*this)[bestcand].Ptr() << " chosen.\n"; newnode->obj=&((MTentry *)((*newnode)[bestcand].Ptr()))->object(); break; } } return newnode; }