source: XIOS/trunk/extern/remap/src/node.cpp @ 856

Last change on this file since 856 was 694, checked in by rlacroix, 9 years ago

Fix compilation issues caused by the new "remap" library.

Use our MPI header so that C++ bindings are always disabled.

File size: 17.3 KB
Line 
1#include "mpi.hpp"
2#include <cstdlib>
3#include <cmath>
4#include <iostream>
5#include <cassert>
6#include "tree.hpp"
7#include "elt.hpp"
8#include "intersect.hpp"
9#include <vector>
10#include <set>
11#include <algorithm>
12
13#include "node.hpp"
14
15namespace sphereRemap {
16
17
18#define UPDATE_EVERY 1
19
20using namespace std;
21
22//#ifdef DEBUG
23//std::map<void*, struct mem_info> _mem_deb; // reference counter
24//
25//void NodePtr::unlink()
26//{
27//      _mem_deb[ptr].ref_cnt -= 1;
28//      if (_mem_deb[ptr].ref_cnt == 0) // we were last reference
29//      {
30//              if (_mem_deb[ptr].stat == DELETED) // delete has already been called, everything is fine, free memory now
31//              {
32//                      _mem_deb.erase(ptr);
33//                      ::delete [] ((char *) ptr);
34//              }
35//              else // no more pointer, but memory not freed -> memory leak !!
36//              {
37//                      std::cerr << "WARNING: Memory leak created at address " << ptr << ".";
38//                      assert(_mem_deb[ptr].stat == ALLOCATED); // and not BORROWED
39//#ifdef AUTO_LEAK_FIX
40//                      // free automatically, just for fun
41//                      _mem_deb.erase(ptr);
42//                      ptr->~Node(); // call destructor, since `Node::delete` has not been applied it has not been called
43//                      ::delete [] ((char *) ptr);
44//                      std::cerr << " LEAK FIXED.";
45//#endif
46//
47//                      std::cerr << std::endl;
48//              }
49//      }
50//}
51//
52//void memory_report()
53//{
54//      for (std::map<void*, struct mem_info>::iterator it = _mem_deb.begin(); it != _mem_deb.end(); it++)
55//      {
56//              if (it->second.stat == BORROWED) continue;
57//              std::cerr << "Node at " << it->first << " has " << it->second.ref_cnt << " references to it and "
58//                        << ((it->second.stat == DELETED) ? "has" : "has *not*") << " been deleted." << std::endl;
59//#ifdef AUTO_LEAK_FIX
60//              if (it->second.stat == ALLOCATED) // `Node::delete` has not been called
61//                      ((Node *) it->first)->~Node();
62//              delete [] ((char *)  it->first);
63//#endif
64//      }
65//}
66//
67//int ref_cnt(void *ptr)
68//{
69//      return _mem_deb[ptr].ref_cnt;
70//}
71//#endif
72
73int compareDist(NodePtr n1, NodePtr n2)
74{
75        return squaredist(n1->tree->ref->centre, n1->centre)
76             < squaredist(n2->tree->ref->centre, n2->centre);
77}
78
79/* On level `level` find the node in our subtree that is closest to `src` and return through argument `closest`.
80   The return value is just for recursive calling */
81void Node::findClosest(int level, NodePtr src, double& minDist2, NodePtr &closest)
82{
83        double r2;
84
85        r2 = squaredist(src->centre, this->centre);
86        if (level == this->level)
87        {
88                if (r2 < minDist2 || closest == NULL)
89                {
90                        minDist2 = r2;
91                        closest = this;
92                }
93        }
94        else if (r2 < radius*radius)
95        {
96                for(int i = 0; i < child.size(); i++)
97                        child[i]->findClosest(level, src, minDist2, closest);
98        }
99}
100
101NodePtr Node::farthest(vector<NodePtr >& list)
102{
103        assert(this);
104        double dmax = -HUGE_VAL;
105        NodePtr node = NULL;
106        for (size_t i=0; i < list.size(); i++)
107        {
108                double d = ds(this->centre, list[i]->centre);
109                if (d > dmax) {
110                        node = list[i];
111                        dmax = d;
112                }
113        }
114        return node;
115}
116
117/* returns element in `list` cosest to us (`this`) by meassure `ds`.
118   If `n` is negative finds element furthest away instead. */
119NodePtr Node::closest(vector<NodePtr >& list, int n)
120{
121        assert(this);
122        double dmin2 = (n>0) ? HUGE_VAL : -HUGE_VAL;
123        NodePtr node = NULL;
124        for (int i = 0; i < list.size(); i++)
125        {
126                double d2 = squaredist(this->centre, list[i]->centre);
127                if (n * (d2 - dmin2) < 0)
128                {
129                        node = list[i];
130                        dmin2 = d2;
131                }
132        }
133        return node;
134}
135
136// make sure we will be able to accomodate `node`
137void Node::move(const NodePtr node)   // this->leafCount may be 0
138{
139        double w = double(node->leafCount)/double(node->leafCount + this->leafCount);
140        Coord oldCentre = this->centre;
141        this->centre = proj(this->centre * (1-w) + node->centre * w);
142        this->leafCount += node->leafCount;
143        this->radius += arcdist(oldCentre, this->centre) + 1e-9;
144}
145
146void Node::remove(const NodePtr node)
147{
148        if (&node == NULL) return;
149        double w = double(node->leafCount) / this->leafCount;
150        Coord newCentre = proj(this->centre - node->centre * w);
151        this->leafCount -= node->leafCount;
152        this->radius += arcdist(newCentre, this->centre) + 1e-9;
153        this->centre = newCentre;
154        this->updateCount++;
155}
156
157void Node::inflate(const NodePtr node)
158{
159        double d = arcdist(this->centre, node->centre);
160        double r = node->radius;
161        if (this->radius < d + r)
162                this->radius = d + r + 1e-9;
163}
164
165/* recomputes the radius which currently might be much larger than necessary */
166void Node::update()
167{
168        Coord centre = ORIGIN;
169        int n = 0;
170        for (int i = 0; i < this->child.size(); i++) {
171                centre = centre + this->child[i]->centre * this->child[i]->leafCount;
172                n += this->child[i]->leafCount;
173        }
174        this->centre = proj(centre);
175        this->leafCount = n;
176
177        double R = 0;
178        for (int i = 0; i < this->child.size(); i++)
179        {
180                double d = arcdist(this->centre, this->child[i]->centre);
181                double r = this->child[i]->radius;
182                if (R < d + r) R = d + r;
183        }
184        this->radius = R + 1e-9;
185        this->updateCount = 0;
186        if (child.size())
187                level = child[0]->level + 1;
188}
189
190void Node::output(ostream& flux, int level, int color)
191{
192  if (level==this->level)
193  {
194    flux<<centre.x<<" , "<<centre.y<<" , "<<centre.z<<" , "<<radius<<endl ;
195  }
196  else
197  {
198    for (int i = 0; i < this->child.size(); i++) child[i]->output(flux,level,color) ;
199  }
200}
201
202
203/* void Node::append(NodePtr node);
204{
205        if (node->level == this->level -1)
206        {
207                // new node is one level lower (correct level)
208                this->child.append(node);
209                node->parent = this;
210        }
211        else if (node->level < this->level -1)
212        {
213                // if new node is on even lower level, recursively append to closest child
214                node->closest(this->child)->append(node);
215        }
216        else
217        {
218                cerr << "Error: Attempted node insertion with invalid level." << endl;
219                exit(1);
220        }
221}*/
222
223bool find_in_tree1(Node* node)
224{
225        if (node == node->tree->root) return true;
226        if (node->parent == NULL)
227        {
228                cerr << "Cannot find!" << endl;
229                return false;
230        }
231        return find_in_tree1(node->parent);
232}
233
234bool find_in_tree2(NodePtr node, NodePtr ref)
235{
236        for (int i = 0; i < ref->child.size(); i++)
237        {
238                if (node == ref->child[i])
239                {
240                        cerr << "find2: " << ref << " -> " << ref->child[i] << endl;
241                        return true;
242                }
243                else if (find_in_tree2(node, ref->child[i]))
244                {
245                        cerr << "find2: " << ref << " -> " << ref->child[i] << endl;
246                        return true;
247                }
248        }
249        return false;
250}
251
252
253/* This appends `this` to the node `node` */
254NodePtr insert(NodePtr thIs, NodePtr node)
255{
256        int la = thIs->level; // node to be inserted
257        int lb = node->level; // node where insertation
258        assert(la < lb); // node to be inserted must have lower level then parent
259        //if (thIs->parent) assert(find_in_tree1(thIs) == true);
260        NodePtr q = NULL;
261        NodePtr chd = NULL;
262        node->move(thIs);
263        if (la == lb - 1)
264        {
265                node->child.push_back(thIs);
266                thIs->parent = node;
267                if (node->child.size() > MAX_NODE_SZ) // with us as additional child `node` is now too large :(
268                        return (node->reinserted || node->parent == NULL) ?
269                                split(node) : reinsert(node);
270        }
271        else // la < lb - 1
272        {
273                chd = thIs->closest(node->child);
274                q = insert(thIs, chd);
275        }
276        if ((node->updateCount + 1) % UPDATE_EVERY == 0)
277                node->update();
278        else
279        {
280                if (q) node->remove(q);
281                node->inflate(chd);
282        }
283        return q;
284}
285
286typedef NodePtr pNode;
287
288/* move `frac` of our children to a new node which is returned */
289NodePtr reinsert(NodePtr thIs)
290{
291        thIs->tree->ref = thIs;
292        std::sort(thIs->child.begin(), thIs->child.end(), compareDist);
293        int out = (int) (frac*thIs->child.size());
294
295        /* make sure out is only so big that there are still MIN_NODE_SZ children after removing out */
296        if (thIs->child.size() - out < MIN_NODE_SZ) out = thIs->child.size() - MIN_NODE_SZ;
297
298        /* transfere out children from us to a new node q which will be returned */
299        NodePtr q = new Node;
300        q->tree = thIs->tree;
301        q->child.resize(out);
302        for (int i = thIs->child.size() - out; i < thIs->child.size(); i++)
303        {
304                thIs->tree->push_back(thIs->child[i]);
305                int k = i - (thIs->child.size() - out);
306                q->child[k] = thIs->child[i];
307                q->child[k]->parent = q;
308        }
309        thIs->child.resize(thIs->child.size() - out);
310        thIs->update();
311        q->update();
312        thIs->reinserted = true; // avoid infinite loop of reinserting the same node, by marking it as reinserted and stop if same node arrives at same place again
313        thIs->tree->ri = 1;
314        return q;
315}
316
317/* move around nodes that are far away from the centre of their parents in order reduce radia of the circles
318   leading to faster look-up times because of less redundancies between nodes.
319   TODO cite paper for Slim SS-tree */
320void slim2(NodePtr thIs, int level)
321{
322        bool out;
323        double distChild;
324
325#ifdef DEBUG
326//      assert(ref_cnt(thIs) >= thIs->child.size() + 1 /*parent*/ + 1 /*thIs*/);
327#endif
328        if (thIs->level==level)
329        {
330                out = false;
331                while (!out)
332                {
333                        /* remove child which is farthest away from the centre and try to reinsert it into the tree */
334                        double distMax = 0;
335                        int itMax = -1;
336                        for (int i = 0; i < thIs->child.size(); i++)
337                        {
338                                distChild = arcdist(thIs->centre, thIs->child[i]->centre) + thIs->child[i]->radius;
339                                if (distChild > distMax)
340                                {
341                                        distMax = distChild;
342                                        itMax = i;
343                                }
344                        }
345                        if (transferNode(thIs->tree->root, thIs, thIs->child[itMax]))
346                        {
347                                thIs->child.erase(thIs->child.begin()+itMax);
348                                out = false;
349                        }
350                        else
351                                out = true;
352
353                        if (thIs->child.size() < MIN_NODE_SZ) out = true;
354                }
355
356                if (thIs->child.size() < MIN_NODE_SZ  && thIs->level < thIs->tree->root->level)
357                {
358                        thIs->tree->decreaseLevelSize(thIs->level);
359                        for(int i = 0; i < thIs->child.size(); i++)
360                                thIs->tree->push_back(thIs->child[i]);
361                        thIs->child.resize(0);
362                }
363                else thIs->update();
364        }
365        else
366        {
367                int newChildCount = 0;
368                for (int i = 0; i < thIs->child.size(); i++)
369                {
370                        if (thIs == thIs->tree->root)
371                        {
372                                // keep at least one child for root
373                                if (i == thIs->child.size()-1 && newChildCount == 0)
374                                {
375                                        thIs->child[newChildCount] = thIs->child[i];
376                                        newChildCount++;
377                                        break;
378                                }
379                        }
380
381                        slim2(thIs->child[i], level);
382                        if (thIs->child[i]->child.size() != 0) // thIs->child[i] is not a leaf
383                        {
384                                thIs->child[newChildCount] = thIs->child[i];
385                                newChildCount++;
386                        } /* else FIXME sometimes this child must be deleted (otherwise leak) sometimes not (otherwise segfault)
387                                        maybe delete not here but when transfered
388                                delete thIs->child[i]; // if our child does not make any grand-children what good is it? -> remove!
389*/
390
391                }
392                thIs->child.resize(newChildCount);
393
394                if (thIs->child.size() < MIN_NODE_SZ && thIs->level < thIs->tree->root->level)
395                {
396                        thIs->tree->decreaseLevelSize(thIs->level);
397                        for (int i = 0; i < thIs->child.size(); i++)
398                                thIs->tree->push_front(thIs->child[i]);
399                        thIs->child.resize(0);
400                }
401                else thIs->update();
402        }
403}
404
405bool transferNode(NodePtr thIs, NodePtr parent, NodePtr node)
406{
407  if (parent == thIs) return false;
408
409        if (thIs->level == parent->level)
410        {
411                if (thIs->child.size() < MAX_NODE_SZ && thIs->child.size() >= MIN_NODE_SZ)
412                {
413                        insert(node, thIs);
414                        return true;
415                }
416                else
417                        return false;
418        }
419        else
420        {
421                for (int i = 0; i < thIs->child.size(); i++)
422                {
423                        if (arcdist(thIs->child[i]->centre, node->centre) + node->radius < thIs->child[i]->radius)
424                        {
425                                if (transferNode(thIs->child[i], parent, node))
426                                {
427                                        thIs->update();
428                                        return true;
429                                }
430                        }
431                }
432                return false;
433        }
434}
435
436
437
438NodePtr split(NodePtr thIs)
439{
440        thIs->tree->increaseLevelSize(thIs->level);
441        NodePtr p = new Node;
442        NodePtr q = new Node;
443        p->level = q->level = thIs->level;
444        p->reinserted = q->reinserted = false;
445        p->parent = q->parent = thIs->parent;
446        p->tree = q->tree = thIs->tree;
447
448
449        p->child.resize(MAX_NODE_SZ/2);
450        q->child.resize(MAX_NODE_SZ/2 + 1);
451        assert(thIs->child.size() == MAX_NODE_SZ+1);
452        thIs->tree->ref = q->child[0] = thIs->closest(thIs->child, FARTHEST); // farthest from centre
453        std::sort(thIs->child.begin(), thIs->child.end(), compareDist);
454        for (int i = 1; i < MAX_NODE_SZ+1; i++)
455                assert(thIs->child[i]->parent == thIs);
456        for (int i = 1; i < MAX_NODE_SZ/2 + 1; i++)
457                q->child[i] = thIs->child[i];
458        for (int i = MAX_NODE_SZ/2+1; i<MAX_NODE_SZ+1; i++)
459                p->child[i-MAX_NODE_SZ/2-1] = thIs->child[i];
460        for (int i = 0; i < MAX_NODE_SZ/2 + 1; i++)
461                q->child[i]->parent = q;
462        for (int i = MAX_NODE_SZ/2+1; i < MAX_NODE_SZ+1; i++)
463                p->child[i-MAX_NODE_SZ/2-1]->parent = p;
464        p->update();
465        q->update();
466
467        if (squaredist(thIs->centre, q->centre) < squaredist(thIs->centre, p->centre))
468                swap(p, q);
469
470        thIs->child = p->child; // now our children do not know we are their parents and believe p is their parent
471        for (int i = 0; i < thIs->child.size(); i++)
472                thIs->child[i]->parent = thIs;
473        thIs->reinserted = p->reinserted;
474        thIs->update();
475        delete p;
476
477        if (thIs == thIs->tree->root) // root split
478        {
479                // since we currently are root, make new root and make us and q its children
480                thIs->tree->newRoot(thIs->level + 1);
481                thIs->tree->root->child.push_back(thIs);  thIs->parent = thIs->tree->root;
482                thIs->tree->root->child.push_back(q);     q->parent    = thIs->tree->root;
483                thIs->tree->root->update();
484        }
485        else
486        {
487                thIs->tree->push_front(q);
488        }  // push_front?
489        return q;
490}
491
492/* Assuming we are a leaf push all leafs into our list of intersectors
493   that are descendant of node and whoes circle intersects ours.
494*/
495void Node::search(NodePtr node)
496{
497        assert(this->level == 0);
498        int Nchild = node->child.size();
499        if (this->intersects(node)) {
500                if (node->level == 0)
501                        this->intersectors.push_back(node);
502                else
503                        for (int i=0; i<Nchild; i++)
504                                search(node->child[i]);
505        }
506}
507
508/* FIXME this should not be in node.cpp and getNeighbours should not be part of the SS-tree
509   this is mapper specific */
510void findNeighbour(NodePtr thIs, NodePtr node, set<NodePtr >& neighbourList)
511{
512        if (thIs->level==0)
513        {
514                Elt* elt1= (Elt*)(thIs->data);
515                Elt* elt2= (Elt*)(node->data);
516                if (isNeighbour(*elt1, *elt2)) neighbourList.insert(thIs);
517        }
518        else
519        {
520                for(int i=0; i<thIs->child.size(); i++)
521                        if (thIs->child[i]->intersects(node)) findNeighbour(thIs->child[i], node, neighbourList);
522        }
523}
524
525bool Node::intersects(NodePtr node)
526{
527        double d = arcdist(this->centre, node->centre);
528        double r = this->radius;
529        double R = node->radius;
530        return (d < r + R + 1e-9) ? true : false;
531}
532
533bool Node::centreInside(Node &node)
534{
535        double d = arcdist(this->centre, node.centre);
536        double R = node.radius;
537        return (d < R + 1e-9) ? true : false;
538}
539
540bool Node::isInside(Node &node)
541{
542        double d = arcdist(this->centre, node.centre);
543        double r = this->radius;
544        double R = node.radius;
545        return (d + r < R + 1e-9) ? true : false;
546}
547
548int Node::incluCheck()
549{
550        if (this->level == 0) return 0;
551        int nOutside = 0;
552        int n = this->child.size();  // cout << "n = " << n << endl;
553        for (int i=0; i<n; i++)
554        {
555                if (!this->child[i]->isInside(*this))
556                {
557                        cout << "Node of level " << this->level << " does not contain its "
558                                << i << "th child\n";
559                        nOutside++;
560                }
561                nOutside += this->child[i]->incluCheck();
562        }
563        return nOutside;
564}
565
566void Node::printChildren()
567{
568        cout << "level " << this->level << ", centre ";
569        cout << "level " << this->level << ", centre " << this->centre << "\t r = " << this->radius << endl;
570        cout << this << " p: " << this->parent << endl;
571        int n = this->child.size();
572        for (int i=0; i<n; i++)
573        {
574                NodePtr child = this->child[i];
575                cout << "fils " << i << ": centre " << child->centre << "\t r = " << child->radius << endl;
576                cout << "dist to center " << arcdist(this->centre, child->centre) <<
577                        " d + R = " << arcdist(this->centre,child->centre)+child->radius << endl;
578        }
579}
580
581void Node::assignRoute(std::vector<int>::iterator& rank, int level)
582{
583        if (this->level==level)
584        {
585                route = *rank;
586                rank++;
587        }
588        else
589        {
590                for (int i = 0; i < child.size(); i++)
591                        child[i]->assignRoute(rank, level);
592        }
593}
594
595void Node::assignCircleAndPropagateUp(Coord *centres, double *radia, int level)
596{
597        if (this->level == level)
598        {
599                // assign
600                centre = centres[route];
601                radius = radia[route];
602                free_descendants(); // levels of sample tree beyond `level` will not be used any more
603                child.resize(0);
604                this->level = 0;
605        }
606        else
607        {
608                for (int i = 0; i < child.size(); i++)
609                        child[i]->assignCircleAndPropagateUp(centres, radia, level);
610                update(); // propagate up
611        }
612}
613
614/* Route node `node` within the subtree attached to us.
615 `level` is the level one which to assign
616*/
617// Each sample node has a rank randomly assigned to it, assign `node` from full tree
618void Node::routeNode(NodePtr node, int level)
619{
620        NodePtr closest;
621
622        double distMin2 = 0; // squared distance
623        closest = NULL;
624        if (tree->root == this)
625                findClosest(level, node, distMin2, closest);
626
627        if (closest != NULL && tree->root == this)
628                /* When is this point reached?
629                   if the preceeding findClosest was called and succesed to set closest
630                   findClosest sets closest if we are `level` or src is in our circle (=> belongs to child of ours)
631                   => reached if we are not `level` and node is not child of us
632                */
633                node->route = closest->route;
634        else  /* find closest was not successfull or we were not root */
635        {
636                if (this->level == level)
637                        node->route = this->route;
638                else /* not yet right level => go down one more */
639                        node->closest(this->child)->routeNode(node, level);
640        }
641}
642
643void Node::routeIntersection(vector<int>& routes, NodePtr node)
644{
645        if (level == 0)
646        {
647                routes.push_back(this->route);
648        }
649        else
650        {
651                for (int i = 0; i < child.size(); i++) {
652                        if (child[i]->intersects(node))
653                                child[i]->routeIntersection(routes, node);
654                }
655        }
656}
657
658void Node::routingIntersecting(vector<Node> *routingList, NodePtr node)
659{
660        if (level==0)
661        {
662                int rank = route;
663                routingList[rank].push_back(*node);
664        }
665        else
666        {
667                for (int i = 0; i < child.size(); i++) {
668                        if (child[i]->intersects(node))
669                                child[i]->routingIntersecting(routingList, node);
670                }
671        }
672}
673
674void Node::free_descendants()
675{
676        for (int i = 0; i < child.size(); i++)
677        {
678                child[i]->free_descendants();
679                if (child[i]->level) // do not attempt to delete leafs, they are delete through leafs vector
680                        delete child[i];
681        }
682}
683
684}
Note: See TracBrowser for help on using the repository browser.