Пример #1
0
 // Method rsearch translated from 352.range.c of Gonnet & Baeza-Yates
 public static void RangeSearch <T>(HPoint lowk, HPoint uppk, KDNode <T> t, int lev, int k, List <KDNode <T> > v)
 {
     if (t == null)
     {
         return;
     }
     if (lowk.Coord[lev] <= t.key.Coord[lev])
     {
         RangeSearch(lowk, uppk, t.left, (lev + 1) % k, k, v);
     }
     if (!t.deleted)
     {
         int j = 0;
         while (j < k && lowk.Coord[j] <= t.key.Coord[j] && uppk.Coord[j] >= t.key.Coord[j])
         {
             j++;
         }
         if (j == k)
         {
             v.Add(t);
         }
     }
     if (uppk.Coord[lev] > t.key.Coord[lev])
     {
         RangeSearch(lowk, uppk, t.right, (lev + 1) % k, k, v);
     }
 }
Пример #2
0
 private KDNode(HPoint key, T val)
 {
     this.key     = key;
     this.value   = val;
     this.left    = null;
     this.right   = null;
     this.deleted = false;
 }
Пример #3
0
        /// <summary>
        ///Find KD-tree node whose key is identical to key. Uses algorithm
        ///translated from 352.srch.c of Gonnet & Baeza-Yates.
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <returns>Element associated to key</returns>
        /// <exception cref="KeySizeException">if key.Length mismatches K</exception>
        public T Search(double[] key)
        {
            if (key.Length != this.m_K)
            {
                throw new KeySizeException();
            }
            KDNode <T> kd = KDNode <T> .Search(new HPoint(key), this.m_root, this.m_K);

            return(kd == null ? default(T) : kd.Value);
        }
Пример #4
0
        public static KDNode <T> Create <T>(HPoint key, IEditor <T> editor)
        {
            KDNode <T> t = new KDNode <T>(key, editor.Edit(default(T)));

            if (Equals(t.value, default(T)))
            {
                t.deleted = true;
            }
            return(t);
        }
Пример #5
0
 public static bool Delete <T>(KDNode <T> t)
 {
     lock (t) {
         if (!t.deleted)
         {
             t.deleted = true;
             return(true);
         }
     }
     return(false);
 }
Пример #6
0
        /// <summary>
        /// Edit a node in a KD-tree
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <param name="editor">object to edit the value at that key</param>
        /// <exception cref="KeySizeException">if key.Length mismatches K</exception>
        /// <exception cref="KeyDuplicateException">if key already in tree</exception>
        public void Edit(double[] key, IEditor <T> editor)
        {
            if (key.Length != this.m_K)
            {
                throw new KeySizeException();
            }
            lock (this) {
                // the first insert has to be lock
                if (null == this.m_root)
                {
                    this.m_root = KDNode <T> .Create(new HPoint(key), editor);

                    this.m_count = this.m_root.Deleted ? 0 : 1;
                    return;
                }
            }
            this.m_count += KDNode <T> .Edit(new HPoint(key), editor, this.m_root, 0, this.m_K);
        }
Пример #7
0
        private NearestNeighborList <KDNode <T> > getNbrs(double[] key, int n, Predicate <T> checker)
        {
            if (key.Length != this.m_K)
            {
                throw new KeySizeException();
            }
            NearestNeighborList <KDNode <T> > nnl = new NearestNeighborList <KDNode <T> >(n);
            // initial call is with infinite hyper-rectangle and max distance
            HRect  hr           = HRect.InfiniteHRect(key.Length);
            double max_dist_sqd = Double.MaxValue;
            HPoint keyp         = new HPoint(key);

            if (this.m_count > 0)
            {
                long timeout = (this.m_timeout > 0) ? (CurrentTimeMillis() + this.m_timeout) : 0;
                KDNode <T> .NearestNeighbors(this.m_root, keyp, hr, max_dist_sqd, 0, this.m_K, nnl, checker, timeout);
            }
            return(nnl);
        }
Пример #8
0
        /// <summary>
        /// Find KD-tree nodes whose keys are <I>n</I> nearest neighbors to key. Uses
        /// algorithm above. Neighbors are returned in ascending order of distance to
        /// key.
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <param name="n">how many neighbors to find</param>
        /// <param name="checker">an optional object to filter matches</param>
        /// <returns>objects at node nearest to key, or null on failure</returns>
        /// <exception cref="KeySizeException">if key.Length mismatches K</exception>
        public List <T> Nearest(double[] key, int n, Predicate <T> checker)
        {
            if (n <= 0)
            {
                return(new List <T>());
            }
            NearestNeighborList <KDNode <T> > nnl = this.getNbrs(key, n, checker);

            n = nnl.Count;
            List <T> nbrs = new List <T>();

            for (int i = 0; i < n; ++i)
            {
                KDNode <T> kd = nnl.RemoveHighest();
                nbrs.Add(kd.Value);
            }
            //nbrs.Reverse();
            return(nbrs);
        }
Пример #9
0
 // Method srch translated from 352.srch.c of Gonnet & Baeza-Yates
 public static KDNode <T> Search <T>(HPoint key, KDNode <T> t, int K)
 {
     for (int lev = 0; t != null; lev = (lev + 1) % K)
     {
         if (!t.deleted && key.Equals(t.key))
         {
             return(t);
         }
         else if (key.Coord[lev] > t.key.Coord[lev])
         {
             t = t.right;
         }
         else
         {
             t = t.left;
         }
     }
     return(null);
 }
Пример #10
0
        // Method ins translated from 352.ins.c of Gonnet & Baeza-Yates
        public static int Edit <T>(HPoint key, IEditor <T> editor, KDNode <T> t, int lev, int k)
        {
            KDNode <T> next_node;
            int        nextLev = (lev + 1) % k;

            lock (t) {
                if (key.Equals(t.key))
                {
                    bool wasDeleted = t.deleted;
                    t.value   = editor.Edit(t.deleted ? default(T) : t.value);
                    t.deleted = (t.value == null);
                    if (t.deleted == wasDeleted)
                    {
                        return(0);
                    }
                    else if (wasDeleted)
                    {
                        return(-1);
                    }
                    return(1);
                }
                else if (key.Coord[lev] > t.key.Coord[lev])
                {
                    next_node = t.right;
                    if (next_node == null)
                    {
                        t.right = Create(key, editor);
                        return(t.right.deleted ? 0 : 1);
                    }
                }
                else
                {
                    next_node = t.left;
                    if (next_node == null)
                    {
                        t.left = Create(key, editor);
                        return(t.left.deleted ? 0 : 1);
                    }
                }
            }
            return(Edit(key, editor, next_node, nextLev, k));
        }
Пример #11
0
        private List <T> nearestDistance(double[] key, double dist, DistanceMetric metric)
        {
            NearestNeighborList <KDNode <T> > nnl = this.getNbrs(key);
            int      n    = nnl.Count;
            List <T> nbrs = new List <T>();

            for (int i = 0; i < n; ++i)
            {
                KDNode <T> kd = nnl.RemoveHighest();
                HPoint     p  = kd.Key;
                //HACK metric.Distance(kd.Key.Coord, key) < dist changed to - metric.Distance(kd.Key.Coord, key) <= dist
                if (metric.Distance(kd.Key.Coord, key) <= dist)
                {
                    nbrs.Add(kd.Value);
                }
            }
            //HACK Verificar se o reverse é necessario
            //nbrs.Reverse();
            return(nbrs);
        }
Пример #12
0
        /// <summary>
        /// Range search in a KD-tree. Uses algorithm translated from 352.range.c of
        /// Gonnet & Baeza-Yates.
        /// </summary>
        /// <param name="lowk">lower-bounds for key</param>
        /// <param name="uppk">upper-bounds for key</param>
        /// <returns>array of Objects whose keys fall in range [lowk,uppk]</returns>
        /// <exception cref="KeySizeException">on mismatch among lowk.Length, uppk.Length, or K</exception>
        public List <T> Range(double[] lowk, double[] uppk)
        {
            if (lowk.Length != uppk.Length)
            {
                throw new KeySizeException();
            }
            else if (lowk.Length != this.m_K)
            {
                throw new KeySizeException();
            }
            else
            {
                List <KDNode <T> > found = new List <KDNode <T> >();
                KDNode <T> .RangeSearch(new HPoint(lowk), new HPoint(uppk), this.m_root, 0, this.m_K, found);

                List <T> o = new List <T>();
                foreach (KDNode <T> node in found)
                {
                    o.Add(node.Value);
                }
                return(o);
            }
        }
Пример #13
0
        /// <summary>
        /// Delete a node from a KD-tree. Instead of actually deleting node and
        /// rebuilding tree, marks node as deleted. Hence, it is up to the caller to
        /// rebuild the tree as needed for efficiency.
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <param name="optional">if false and node not found, throw an exception</param>
        /// <exception cref="KeyMissingException">if no node in tree has key</exception>
        /// <exception cref="KeySizeException">if key.Length mismatches K</exception>
        public void Delete(double[] key, bool optional)
        {
            if (key.Length != this.m_K)
            {
                throw new KeySizeException();
            }
            KDNode <T> t = KDNode <T> .Search(new HPoint(key), this.m_root, this.m_K);

            if (t == null)
            {
                if (optional == false)
                {
                    throw new KeyMissingException();
                }
            }
            else
            {
                if (KDNode <T> .Delete(t))
                {
                    this.m_count--;
                }
            }
        }
Пример #14
0
 public KDTree(int k, long timeout)
 {
     this.m_timeout = timeout;
     this.m_K       = k;
     this.m_root    = null;
 }
Пример #15
0
        // Method Nearest Neighbor from Andrew Moore's thesis. Numbered
        // comments are direct quotes from there. NearestNeighborList solution
        // courtesy of Bjoern Heckel.
        public static void NearestNeighbors <T>(KDNode <T> kd, HPoint target, HRect hr, double max_dist_sqd, int lev,
                                                int K, NearestNeighborList <KDNode <T> > nnl, Predicate <T> checker,
                                                long timeout)
        {
            // 1. if kd is empty then set dist-sqd to infinity and exit.
            if (kd == null)
            {
                return;
            }
            if ((timeout > 0) && (timeout < DateTime.Now.TimeOfDay.TotalMilliseconds))
            {
                return;
            }
            // 2. s := split field of kd
            int s = lev % K;
            // 3. pivot := dom-elt field of kd
            HPoint pivot           = kd.key;
            double pivot_to_target = HPoint.SqrDist(pivot, target);
            // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
            // The cut plane is through pivot and perpendicular to the s
            // dimension.
            HRect left_hr  = hr; // optimize by not cloning
            HRect right_hr = (HRect)hr.Clone();

            left_hr.Max.Coord[s]  = pivot.Coord[s];
            right_hr.Min.Coord[s] = pivot.Coord[s];
            // 5. target-in-left := target_s <= pivot_s
            bool       target_in_left = target.Coord[s] < pivot.Coord[s];
            KDNode <T> nearer_kd;
            HRect      nearer_hr;
            KDNode <T> further_kd;
            HRect      further_hr;

            // 6. if target-in-left then
            // 6.1. nearer-kd := left field of kd and nearer-hr := left-hr
            // 6.2. further-kd := right field of kd and further-hr := right-hr
            if (target_in_left)
            {
                nearer_kd  = kd.left;
                nearer_hr  = left_hr;
                further_kd = kd.right;
                further_hr = right_hr;
            }
            //
            // 7. if not target-in-left then
            // 7.1. nearer-kd := right field of kd and nearer-hr := right-hr
            // 7.2. further-kd := left field of kd and further-hr := left-hr
            else
            {
                nearer_kd  = kd.right;
                nearer_hr  = right_hr;
                further_kd = kd.left;
                further_hr = left_hr;
            }
            // 8. Recursively call Nearest Neighbor with paramters
            // (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
            // results in nearest and dist-sqd
            NearestNeighbors(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl, checker, timeout);
            // KDNode<T> nearest = nnl.getHighest();
            double dist_sqd;

            if (!nnl.IsCapacityReached())
            {
                dist_sqd = Double.MaxValue;
            }
            else
            {
                dist_sqd = nnl.MaxPriority;
            }
            // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
            max_dist_sqd = Math.Min(max_dist_sqd, dist_sqd);
            // 10. A nearer point could only lie in further-kd if there were some
            // part of further-hr within distance max-dist-sqd of
            // target.
            HPoint closest = further_hr.Closest(target);

            if (HPoint.SqrDist(closest, target) < max_dist_sqd)
            {
                // 10.1 if (pivot-target)^2 < dist-sqd then
                if (pivot_to_target < dist_sqd)
                {
                    // 10.1.1 nearest := (pivot, range-elt field of kd)
                    // nearest = kd;
                    // 10.1.2 dist-sqd = (pivot-target)^2
                    dist_sqd = pivot_to_target;
                    // add to nnl
                    if (!kd.deleted && ((checker == null) || checker.Invoke(kd.value)))
                    {
                        nnl.Insert(kd, dist_sqd);
                    }
                    // 10.1.3 max-dist-sqd = dist-sqd
                    // max_dist_sqd = dist_sqd;
                    if (nnl.IsCapacityReached())
                    {
                        max_dist_sqd = nnl.MaxPriority;
                    }
                    else
                    {
                        max_dist_sqd = Double.MaxValue;
                    }
                }
                // 10.2 Recursively call Nearest Neighbor with parameters
                // (further-kd, target, further-hr, max-dist_sqd),
                // storing results in temp-nearest and temp-dist-sqd
                NearestNeighbors(further_kd, target, further_hr, max_dist_sqd, lev + 1, K, nnl, checker, timeout);
            }
        }