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; }
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 }
MTnode * MTnode::PromotePart() { MTnode *newnode; switch(PROMOTE_PART_FUNCTION) { case RANDOM: { // complexity: constant int i, j; // pick two *different* random entries // cout << "Random promotion: "; i=PickRandom(0, NumEntries()); do j=PickRandom(0, NumEntries()); while (j==i); if(((MTentry *)(*this)[j].Ptr())->Key()->distance==0) { int k=i; i=j; j=k; // if we chose the parent entry, put it in the left node } // cout << "Entries " << (*this)[i].Ptr() << " & " << (*this)[j].Ptr() << " chosen.\n"; newnode=(MTnode *)NCopy(); // re-assign the nodes' object newnode->obj=&((MTentry *)((*newnode)[j].Ptr()))->object(); obj=&((MTentry *)((*this)[i].Ptr()))->object(); if(((MTentry *)(*this)[i].Ptr())->Key()->distance>0) { // if the parent object wasn't confirmed, invalidate also the parent InvalidateEntry(TRUE); InvalidateEntries(); } else InvalidateEntry(FALSE); // else, invalidate only the node's radii break; } case CONFIRMED: { // complexity: determined by the confirmed promotion algorithm int i; BOOL isRoot=TRUE; // cout << "Confirmed promotion: "; // for(i=0; (i<NumEntries())&&(isRoot); i++) isRoot=(((MTentry *)((*this)[i].Ptr()))->Key()->distance==-MAXDIST); isRoot=(((MTentry *)((*this)[0].Ptr()))->Key()->distance==-maxDist()); // we have ordered entries if(isRoot) { // if we're splitting the root we have to use a policy that doesn't use stored distances PROMOTE_PART_FUNCTION=SECONDARY_PART_FUNCTION; newnode=PromotePart(); PROMOTE_PART_FUNCTION=CONFIRMED; } else { int index=-1; for(i=0; (i<NumEntries())&&(index<0); i++) if(((MTentry *)((*this)[i].Ptr()))->Key()->distance==0) index=i; obj=&((MTentry *)((*this)[index].Ptr()))->object(); // now choose the right node parent newnode=PromoteVote(); } InvalidateEntry(FALSE); break; } case MAX_UB_DIST: { // complexity: constant double maxdist=-1, maxdist2; int i, maxcand1, maxcand2; BOOL isRoot=TRUE; // cout << "Largest max dist promotion:\n"; // for(i=0; (i<NumEntries())&&(isRoot); i++) isRoot=(((MTentry *)((*this)[i].Ptr()))->Key()->distance==-MAXDIST); isRoot=(((MTentry *)((*this)[0].Ptr()))->Key()->distance==-maxDist()); // we have ordered entries if(isRoot) { // if we're splitting the root we have to use a policy that doesn't use stored distances PROMOTE_PART_FUNCTION=SECONDARY_PART_FUNCTION; newnode=PromotePart(); PROMOTE_PART_FUNCTION=CONFIRMED; } else if(Tree()->IsOrdered()) { // if the tree is ordered we can choose the last two elements maxcand1=NumEntries()-1; maxcand2=NumEntries()-2; } // the following code should be unreachable else // otherwise we have to search the two objects which are farthest from the parent for (i=0; i<NumEntries(); i++) { MTentry *e=(MTentry *)((*this)[i].Ptr()); if (e->Key()->distance>maxdist) { maxdist2=maxdist; maxdist=e->Key()->distance; maxcand2=maxcand1; maxcand1=i; } else if (e->Key()->distance>maxdist2) { maxdist2=e->Key()->distance; maxcand2=i; } } // cout << "Entries " << (*this)[maxcand1].Ptr() << " & " << (*this)[maxcand2].Ptr() << " chosen.\n"; // for sure the parent isn't confirmed (unless we have a binary tree...) obj=&((MTentry *)((*this)[maxcand1].Ptr()))->object(); InvalidateEntry(TRUE); InvalidateEntries(); newnode=(MTnode *)NCopy(); newnode->obj=&((MTentry *)((*newnode)[maxcand2].Ptr()))->object(); break; } case SAMPLING: { // complexity: O(kn) distance computations // cout << "Sampling: "; int *vec=PickCandidates(), i, j, min1, min2, 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 // initialize distance matrix for(i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) { distances[i]=new double[NumEntries()]; for(j=0; j<NumEntries(); j++) distances[i][j]=-maxDist(); } for(i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) if(((MTentry *)((*this)[vec[i]].Ptr()))->Key()->distance==0) { for(j=0; j<NumEntries(); j++) distances[i][j]=((MTentry *)((*this)[j].Ptr()))->Key()->distance; break; } for(i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) distances[i][vec[i]]=0; // find the candidates with minimum radius for(i=1; i<MIN(NUM_CANDIDATES, NumEntries()); i++) for (j=0; j<i; j++) { MTentry *e1=new MTentry, *e2=new MTentry; MTnode *node1=(MTnode *)NCopy(), *node2=(MTnode *)NCopy(); double value, sec_value; int leftdeletes, rightdeletes, *leftvec=new int[NumEntries()], *rightvec=new int[NumEntries()], k; for(k=0; k<NumEntries(); k++) { ((MTentry *)((*node1)[k].Ptr()))->Key()->distance=distances[i][k]; ((MTentry *)((*node2)[k].Ptr()))->Key()->distance=distances[j][k]; } node1->obj=&((MTentry *)((*this)[vec[i]].Ptr()))->object(); node2->obj=&((MTentry *)((*this)[vec[j]].Ptr()))->object(); // perform the split node1->Split(node2, leftvec, rightvec, &leftdeletes, &rightdeletes); for(k=0; k<NumEntries(); k++) { distances[i][k]=((MTentry *)((*node1)[k].Ptr()))->Key()->distance; distances[j][k]=((MTentry *)((*node2)[k].Ptr()))->Key()->distance; } // 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]; min1=i; min2=j; } // be tidy delete []leftvec; delete []rightvec; delete node1; delete node2; delete e1; delete e2; } // cout << "Entries " << (*this)[vec[min1]].Ptr() << " & " << (*this)[vec[min2]].Ptr() << " chosen.\n"; if(((MTentry *)(*this)[vec[min2]].Ptr())->Key()->distance>0) newnode=(MTnode *)NCopy(); else newnode=(MTnode *)Copy(); newnode->obj=&((MTentry *)((*newnode)[vec[min2]].Ptr()))->object(); obj=&((MTentry *)((*this)[vec[min1]].Ptr()))->object(); if(((MTentry *)(*this)[vec[min1]].Ptr())->Key()->distance>0) { // if the parent object wasn't confirmed, invalidate also the parent InvalidateEntry(TRUE); InvalidateEntries(); } else InvalidateEntry(FALSE); // else, invalidate only the node's radii for(i=0; i<NumEntries(); i++) { ((MTentry *)((*this)[i].Ptr()))->Key()->distance=distances[min1][i]; ((MTentry *)((*newnode)[i].Ptr()))->Key()->distance=distances[min2][i]; } delete []bestlv; delete []bestrv; for(i=0; i<MIN(NUM_CANDIDATES, NumEntries()); i++) delete []distances[i]; delete []distances; break; } case MIN_RAD: case MIN_OVERLAPS: { // complexity: O(n^2) distance computations int min1, min2, i, j, bestld, bestrd, *bestlv=new int[NumEntries()], *bestrv=new int[NumEntries()]; double minvalue=MAXDOUBLE, sec_minvalue=MAXDOUBLE, **distances=new double *[NumEntries()]; // distance matrix // initialize distance matrix for(i=0; i<NumEntries(); i++) { distances[i]=new double[NumEntries()]; for(j=0; j<NumEntries(); j++) distances[i][j]=-maxDist(); } for(i=0; i<NumEntries(); i++) if(((MTentry *)((*this)[i].Ptr()))->Key()->distance==0) { for(j=0; j<NumEntries(); j++) { distances[i][j]=((MTentry *)((*this)[j].Ptr()))->Key()->distance; distances[j][i]=distances[i][j]; } break; } for(i=0; i<NumEntries(); i++) distances[i][i]=0; // if(PROMOTE_PART_FUNCTION==MIN_RADII) cout << "Min radii promotion: "; // else cout << "Min overlaps promotion: "; for (i=1; i<NumEntries(); i++) for (j=0; j<i; j++) { MTentry *e1=new MTentry, *e2=new MTentry; MTnode *node1=(MTnode *)NCopy(), *node2=(MTnode *)NCopy(); double value, sec_value; int leftdeletes, rightdeletes, *leftvec=new int[NumEntries()], *rightvec=new int[NumEntries()], k; for(k=0; k<NumEntries(); k++) { ((MTentry *)((*node1)[k].Ptr()))->Key()->distance=distances[i][k]; ((MTentry *)((*node2)[k].Ptr()))->Key()->distance=distances[j][k]; } node1->obj=&((MTentry *)((*this)[i].Ptr()))->object(); node2->obj=&((MTentry *)((*this)[j].Ptr()))->object(); // perform the split node1->Split(node2, leftvec, rightvec, &leftdeletes, &rightdeletes); for(k=0; k<NumEntries(); k++) { distances[i][k]=((MTentry *)((*node1)[k].Ptr()))->Key()->distance; distances[j][k]=((MTentry *)((*node2)[k].Ptr()))->Key()->distance; distances[k][i]=distances[i][k]; distances[k][j]=distances[j][k]; } // 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 if(PROMOTE_PART_FUNCTION==MIN_RAD) { value=MAX(e1->maxradius(), e2->maxradius()); // this is minMAX_RADII sec_value=MIN(e1->maxradius(), e2->maxradius()); } else value=e1->maxradius()+e2->maxradius()-distances[i][j]; 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]; min1=i; min2=j; } // be tidy delete []leftvec; delete []rightvec; delete node1; delete node2; delete e1; delete e2; } // cout << "Entries " << (*this)[min1].Ptr() << " & " << (*this)[min2].Ptr() << " chosen.\n"; if(((MTentry *)(*this)[min2].Ptr())->Key()->distance>0) newnode=(MTnode *)NCopy(); else newnode=(MTnode *)Copy(); newnode->obj=&((MTentry *)((*newnode)[min2].Ptr()))->object(); obj=&((MTentry *)((*this)[min1].Ptr()))->object(); if(((MTentry *)(*this)[min1].Ptr())->Key()->distance>0) { // if the parent object wasn't confirmed, invalidate also the parent InvalidateEntry(TRUE); InvalidateEntries(); } else InvalidateEntry(FALSE); // else, invalidate only the node's radii for(i=0; i<NumEntries(); i++) { ((MTentry *)((*this)[i].Ptr()))->Key()->distance=distances[min1][i]; ((MTentry *)((*newnode)[i].Ptr()))->Key()->distance=distances[min2][i]; } delete bestlv; delete bestrv; for(i=0; i<NumEntries(); i++) delete []distances[i]; delete []distances; break; } } return newnode; }
MTnode * MTnode::PromotePart () { MTnode *newNode = NULL; switch (PROMOTE_PART_FUNCTION) { case RANDOM: { // pick two *different* random entries, complexity: constant int i = PickRandom (0, NumEntries()); int j; do { j = PickRandom (0, NumEntries()); } while (i == j); if (((MTentry *)(*this)[j].Ptr())->Key()->distance == 0) { // if we chose the parent entry, put it in the left node int temp = i; i = j; j = temp; } // re-assign the nodes' object newNode = (MTnode *) NCopy (); newNode->obj = &((MTentry *)((*newNode)[j].Ptr()))->object(); obj = &((MTentry *)((*this)[i].Ptr()))->object(); if (((MTentry *)(*this)[i].Ptr())->Key()->distance > 0) { // unconfirmed, invalidate also the parent InvalidateEntry (TRUE); InvalidateEntries (); } else { InvalidateEntry (FALSE); // confirmed, invalidate only the node's radii } break; } case CONFIRMED: { // complexity: determined by the confirmed promotion algorithm if (((MTentry *)((*this)[0].Ptr()))->Key()->distance == -MaxDist()) { // if we're splitting the root we have to use a policy that doesn't use stored distances PROMOTE_PART_FUNCTION = SECONDARY_PART_FUNCTION; newNode = PromotePart (); PROMOTE_PART_FUNCTION = CONFIRMED; } else { int index = -1; for (int i=0; i<NumEntries() /*&& index<0*/; i++) { if (((MTentry *)((*this)[i].Ptr()))->Key()->distance == 0) { // parent obj index = i; } } obj = &((MTentry *)((*this)[index].Ptr()))->object(); newNode = PromoteVote (); // now choose the right node parent } InvalidateEntry (FALSE); break; } case SAMPLING: { // complexity: O(kn) distance computations int n = NumEntries (), count = MIN (NUM_CANDIDATES, n-1); double **distances = new double*[count]; // distance matrix int *vec = PickCandidates (); // initialize distance matrix for (int i=0; i<count; i++) { distances[i] = new double[n]; for (int j=0; j<n; j++) { j==vec[i] ? distances[i][j]=0 : distances[i][j]=-MaxDist(); } } // find the candidates with minimum radius int min1, min2; double min = MAXDOUBLE, secMin = MAXDOUBLE; for (int i=1; i<count; i++) { for (int j=0; j<i; j++) { MTnode *node1 = (MTnode *) NCopy (), *node2 = (MTnode *) NCopy (); for (int k=0; k<n; k++) { ((MTentry *)(*node1)[k].Ptr())->Key()->distance = distances[i][k]; ((MTentry *)(*node2)[k].Ptr())->Key()->distance = distances[j][k]; } node1->obj = &((MTentry *)(*this)[vec[i]].Ptr())->object(); node2->obj = &((MTentry *)(*this)[vec[j]].Ptr())->object(); // perform the split int lDel, rDel, *lVec = new int[n], *rVec = new int[n]; node1->Split(node2, lVec, rVec, &lDel, &rDel); for (int k=0; k<n; k++) { distances[i][k] = ((MTentry *)(*node1)[k].Ptr())->Key()->distance; distances[j][k] = ((MTentry *)(*node2)[k].Ptr())->Key()->distance; } node1->DeleteBulk(lVec, lDel); node2->DeleteBulk(rVec, rDel); MTentry *entry1 = new MTentry, *entry2 = new MTentry; entry1->InitKey(); entry2->InitKey(); entry1->SetObject(*node1->obj); entry2->SetObject(*node2->obj); entry1->SetMaxRadius(0); entry2->SetMaxRadius(0); entry1->SetMinRadius(MAXDOUBLE); entry2->SetMinRadius(MAXDOUBLE); node1->mMRadius(entry1); node2->mMRadius(entry2); // check the result double val1 = MAX (entry1->MaxRadius(), entry2->MaxRadius()), val2 = MIN (entry1->MaxRadius(), entry2->MaxRadius()); if (val1<min || (val1==min && val2<secMin)) { min = val1; secMin = val2; min1 = i; min2 = j; } // be tidy delete entry1; delete entry2; delete []lVec; delete []rVec; delete node1; delete node2; } } newNode = (MTnode *) NCopy (); obj = &((MTentry *)(*this)[vec[min1]].Ptr())->object(); newNode->obj = &((MTentry *)(*newNode)[vec[min2]].Ptr())->object(); // the parent object wasn't confirmed, invalidate also the parent InvalidateEntry (TRUE); InvalidateEntries (); for (int i=0; i<n; i++) { ((MTentry *)(*this)[i].Ptr())->Key()->distance = distances[min1][i]; ((MTentry *)(*newNode)[i].Ptr())->Key()->distance = distances[min2][i]; } for (int i=0; i<count; i++) { delete []distances[i]; } delete []distances; break; } case mM_RAD: { // complexity: O(n^2) distance computations int n = NumEntries (); double **distances = new double *[n]; // distance matrix // initialize distance matrix for (int i=0; i<n; i++) { distances[i] = new double[n]; for (int j=0; j<n; j++) { j==i ? distances[i][j]=0 : distances[i][j]=-MaxDist(); } } for (int i=0; i<n; i++) { if (((MTentry *)(*this)[i].Ptr())->Key()->distance == 0) { for (int j=0; j<n; j++) { distances[j][i] = distances[i][j] = ((MTentry *)(*this)[j].Ptr())->Key()->distance; } break; } } int min1, min2; double min = MAXDOUBLE, secMin = MAXDOUBLE; for (int i=1; i<n; i++) { for (int j=0; j<i; j++) { MTnode *node1 = (MTnode *) NCopy (), *node2 = (MTnode *) NCopy (); for (int k=0; k<n; k++) { ((MTentry *)(*node1)[k].Ptr())->Key()->distance = distances[i][k]; ((MTentry *)(*node2)[k].Ptr())->Key()->distance = distances[j][k]; } node1->obj = &((MTentry *)(*this)[i].Ptr())->object(); node2->obj = &((MTentry *)(*this)[j].Ptr())->object(); // perform the split int lDel, rDel, *lVec=new int[n], *rVec=new int[n]; node1->Split(node2, lVec, rVec, &lDel, &rDel); for (int k=0; k<n; k++) { distances[k][i] = distances[i][k] = ((MTentry *)(*node1)[k].Ptr())->Key()->distance; distances[k][j] = distances[j][k] = ((MTentry *)(*node2)[k].Ptr())->Key()->distance; } node1->DeleteBulk(lVec, lDel); node2->DeleteBulk(rVec, rDel); MTentry *entry1 = new MTentry, *entry2 = new MTentry; entry1->InitKey(); entry2->InitKey(); entry1->SetObject(*node1->obj); entry2->SetObject(*node2->obj); entry1->SetMaxRadius(0); entry2->SetMaxRadius(0); entry1->SetMinRadius(MAXDOUBLE); entry2->SetMinRadius(MAXDOUBLE); node1->mMRadius(entry1); node2->mMRadius(entry2); // check the result double val1 = MAX (entry1->MaxRadius(), entry2->MaxRadius()), val2 = MIN (entry1->MaxRadius(), entry2->MaxRadius()); if (val1<min || (val1==min && val2<secMin)) { min = val1; secMin = val2; min1 = i; min2 = j; } // be tidy delete entry1; delete entry2; delete []lVec; delete []rVec; delete node1; delete node2; } } ((MTentry *)(*this)[min2].Ptr())->Key()->distance>0 ? newNode=(MTnode *)NCopy() : newNode=(MTnode *)Copy(); obj = &((MTentry *)(*this)[min1].Ptr())->object(); newNode->obj = &((MTentry *)(*newNode)[min2].Ptr())->object(); if (((MTentry *)(*this)[min1].Ptr())->Key()->distance > 0) { // unconfirmed, invalidate also the parent InvalidateEntry (TRUE); InvalidateEntries (); } else { InvalidateEntry (FALSE); // else, invalidate only the node's radii } for (int i=0; i<n; i++) { ((MTentry *)(*this)[i].Ptr())->Key()->distance = distances[min1][i]; ((MTentry *)(*newNode)[i].Ptr())->Key()->distance = distances[min2][i]; } for (int i=0; i<n; i++) { delete []distances[i]; } delete []distances; break; } } return newNode; }