public PointSet GetANN(Point p, int K, int maxSearch, DimWeight dw)
        {
            this.p = p;
            this.K = K;
            this.maxSearch = maxSearch;
            this.dw = dw;
            searched = new PointSetHash();
            pc = new PointCompare(dw, p);
            heap = new MaxHeap<Point>(pc);
            
            childHolds = new List<bool>();
            mutexes = new List<Mutex>();
            threadIds = new Dictionary<int, int>();
            threads = new List<Thread>();
            returned = new List<bool>();
            nReturned = 0;

            for (int currNum = 0; currNum < NTrees; currNum++)
            {
                mutexes.Add(new Mutex());
                childHolds.Add(false);
                returned.Add(false);
                mutexes[currNum].WaitOne();
                Thread t = new Thread(new ThreadStart(searchStuff));
                threadIds.Add(t.ManagedThreadId, currNum);
                threads.Add(t);
                t.Start();
            }

            while (nReturned < NTrees)
            {
                for (int i = 0; i < NTrees; i++)
                {
                    if (!returned[i])
                    {
                        performAction(i);
                    }
                }
            }

            cleanupThreads();

            PointSet ps = new PointSet(p.NumDim);
            while (heap.Count > 0)
            {
                ps.AddPoint(heap.ExtractDominating());
            }

            return ps;
        }
        public PointSet GetANNWeighted(Point p, int K, int maxSearch, DimWeight dw)
        {
            this.p = p;
            this.K = K;
            this.maxSearch = maxSearch;
            this.dw = dw;
            searched = new PointSetHash();
            pc = new PointCompare(dw, p);
            heap = new MaxHeap<Point>(pc);

            childHolds = new List<bool>();
            mutexes = new List<Mutex>();
            flaggedId = new HashSet<int>();
            threadIds = new Dictionary<int, int>();
            threads = new List<Thread>();
            returned = new List<bool>();
            nReturned = 0;

            for (int currNum = 0; currNum < NTrees; currNum++)
            {
                mutexes.Add(new Mutex());
                childHolds.Add(false);
                returned.Add(false);
                mutexes[currNum].WaitOne();
                Thread t = new Thread(new ThreadStart(searchStuffWeighted));
                threadIds.Add(t.ManagedThreadId, currNum);
                threads.Add(t);
                t.Start();
            }

            while (nReturned < NTrees)
            {
                int id = treeweights.GetRandomId();
                bool res = performAction(treeweights.GetRandomId());
                if (id >= returned.Count() || (!res && returned[id]))
                    break;
            }

            cleanupThreads();

            PointSet ps = new PointSet(p.NumDim);
            while (heap.Count > 0)
            {
                ps.AddPoint(heap.ExtractDominating());
            }

            return ps;
        }
        public void SearchDownThreaded(Point p, int K, int maxSearch, DimWeight dw, PointSetHash searched,
                                       MaxHeap <Point> heap, PointCompare pc, List <Boolean> b, List <Mutex> m, int id)
        {
            if (this == null || this.point == null || searched.NPoints >= maxSearch)
            {
                return;
            }

            if (isLeaf)
            {
                while (b[id])
                {
                    ;
                }
                m[id].WaitOne();
                b[id] = true;

                if (!searched.CheckContains(point) && searched.NPoints < maxSearch)
                {
                    CheckPoint(K, heap, pc);
                    searched.AddPoint(point);
                }

                m[id].ReleaseMutex();
            }
            else
            {
                bool leftSearched;
                if (p.Values[splitDim] < point.Values[splitDim])
                {
                    leftChild.SearchDownThreaded(p, K, maxSearch, dw, searched, heap, pc, b, m, id);
                    leftSearched = true;
                }
                else
                {
                    rightChild.SearchDownThreaded(p, K, maxSearch, dw, searched, heap, pc, b, m, id);
                    leftSearched = false;
                }

                // Check this point
                while (b[id])
                {
                    ;
                }
                m[id].WaitOne();
                b[id] = true;

                bool exceeded = maxSearch <= searched.NPoints;

                if (!searched.CheckContains(point) && searched.NPoints < maxSearch)
                {
                    CheckPoint(K, heap, pc);
                    searched.AddPoint(point);
                }

                // Check if a better point possibly exists in the other subtree
                var pval = new List <Double>(p.Values);
                pval[splitDim] = point.Values[splitDim];
                Point planecheck  = new Point(pval);
                bool  expandOther = pc.Compare(heap.GetMin(), planecheck) >= 0;

                m[id].ReleaseMutex();

                if (expandOther)
                {
                    if (leftSearched && rightChild != null)
                    {
                        rightChild.SearchDownThreaded(p, K, maxSearch, dw, searched, heap, pc, b, m, id);
                    }
                    else if (!leftSearched && leftChild != null)
                    {
                        leftChild.SearchDownThreaded(p, K, maxSearch, dw, searched, heap, pc, b, m, id);
                    }
                }
            }
        }