예제 #1
0
        /// <summary>
        /// O(n * k * logk)  // much faster than O(n logn) for k << n
        /// </summary>
        /// <param name="s"></param>
        /// <param name="p"></param>
        /// <param name="conf"></param>
        /// <returns></returns>
        public long UpdateKnn(IAlgorithm s, IP p, KnnConfiguration conf)
        {
            conf = conf ?? new KnnConfiguration();

            var sw = new Stopwatch();

            sw.Start();

            s.Knn.Clear();
            s.Knn.Origin = p;
            s.Knn.K      = conf.K;

            //var all = new List<IPDist>(); // naive version
            var sortedList2 = new SortedList2();  // better naive version

            var n = s.Points.Count;

            for (var i = 0; i < n; i++)
            {
                var p1 = s.Points[i];
                if (p.Equals(p1))
                {
                    continue;               // don't include origin
                }
                if (conf.SameTypeOnly && p.Type != p1.Type)
                {
                    continue;                                         // only same type used
                }
                var dist = p.Distance(p1.X, p1.Y);
                if (dist >= conf.MaxDistance)
                {
                    continue;
                }

                var pdist = new PDist {
                    Point = p1, Distance = dist
                };

                //all.Add(pdist); // naive version
                sortedList2.Add(pdist, conf.K);  // better naive version
            }

            //s.Knn.NNs = all.OrderBy(i => i.Distance).Take(conf.K).ToList(); // O(n logn)
            s.Knn.NNs = sortedList2.GetAll(); // O(n * k * logk) // better naive version

            sw.Stop();
            return(sw.ElapsedMilliseconds);
        }
예제 #2
0
        // O(n * m) where m is grid cells
        public long UpdateKnn(IAlgorithm s, IP p, KnnConfiguration conf)
        {
            if (conf == null)
            {
                conf = new KnnConfiguration();
            }

            var sw = new Stopwatch();

            sw.Start();
            var max = Math.Max(s.Rectangle.XGrid, s.Rectangle.YGrid);

            s.Knn.Clear();
            s.Knn.Origin = p;
            s.Knn.K      = conf.K;
            UpdateKnnGridStrategy(s, max, conf);

            sw.Stop();
            return(sw.ElapsedMilliseconds);
        }
        /// <summary>
        /// Missing mapping to P objects
        /// KdTree could be refactored to use P object instead of Math.Net
        ///
        /// O(k * log n)
        /// </summary>
        /// <param name="s"></param>
        /// <param name="origin"></param>
        /// <param name="k"></param>
        /// <param name="conf"></param>
        /// <returns></returns>
        public long UpdateKnn(IAlgorithm s, IP origin, KnnConfiguration conf)
        {
            if (conf == null)
            {
                conf = new KnnConfiguration();
            }
            if (conf.SameTypeOnly)
            {
                throw new NotImplementedException();
            }
            if (conf.MaxDistance.HasValue)
            {
                throw new NotImplementedException();
            }

            var sw = new Stopwatch();

            sw.Start();

            var vector = new DenseVector(new[] { origin.X, origin.Y });
            var nn     = Tree.FindNearestNNeighbors(vector, conf.K).ToList();

            s.Knn.Clear();
            s.Knn.Origin = origin;
            s.Knn.K      = conf.K;
            foreach (var i in nn)
            {
                var p = new P {
                    X = i[0], Y = i[1]
                };
                var dist = origin.Distance(p.X, p.Y);
                s.Knn.NNs.Add(new PDist {
                    Point = p, Distance = dist
                });
            }

            sw.Stop();
            return(sw.ElapsedMilliseconds);
        }
예제 #4
0
 public long UpdateKnn(IP p, KnnConfiguration configuration)
 {
     UpdateIndex(p);
     return(Strategy.UpdateKnn(this, p, configuration));
 }
예제 #5
0
        // K nearest neighbor
        protected void UpdateKnnGridStrategy(IAlgorithm s, int max, KnnConfiguration conf)
        {
            var g      = s.GridContainer;
            var nn     = s.Knn;
            var square = s.Rectangle.Square;

            var currRing = new List <IPDist>();
            var nextRing = new List <IPDist>();

            for (var i = 1; i <= max; i++)
            {
                var temp = new List <IPDist>();
                foreach (var p in nextRing)
                {
                    if (p.Distance < i * square)
                    {
                        currRing.Add(p);
                    }
                    else
                    {
                        temp.Add(p);
                    }
                }

                nextRing.Clear();
                nextRing.AddRange(temp);

                var list = g.GetRing(nn.Origin, i);

                // First 9 squares, dont include origin
                if (i == 1)
                {
                    list.AddRange(g.GetSet(nn.Origin).Where(a => !a.Equals(nn.Origin)).ToList());
                }

                // Only NN on same type if set
                if (conf.SameTypeOnly)
                {
                    list = list.Where(a => a.Type == nn.Origin.Type).ToList();
                }

                var dataWasAdded = false;
                foreach (var p in list)
                {
                    var dist = nn.Origin.Distance(p.X, p.Y);
                    if (dist >= conf.MaxDistance)
                    {
                        continue;                          // not within max distance
                    }
                    if (dist < i * square)
                    {
                        currRing.Add(new PDist {
                            Point = p, Distance = dist
                        });
                    }
                    else
                    {
                        nextRing.Add(new PDist {
                            Point = p, Distance = dist
                        });
                    }

                    dataWasAdded = true;
                }

                if (conf.MaxDistance.HasValue && !dataWasAdded)
                {
                    break;                                            // max distance used and no new data was added, then we are done
                }
                if (currRing.Count >= nn.K)
                {
                    break;                         // enough neighbors? then done
                }
            }


            if (currRing.Count < nn.K)
            {
                // Only NN on same type if set
                currRing.AddRange(conf.SameTypeOnly
                                      ? nextRing.Where(a => a.Point.Type == nn.Origin.Type).ToList()
                                      : nextRing);

                if (conf.MaxDistance.HasValue)
                {
                    currRing = currRing.Where(i => i.Distance < conf.MaxDistance.Value).ToList();
                }
            }

            currRing.Sort();
            nn.NNs = currRing.Count > nn.K ? currRing.Take(nn.K).ToList() : currRing.ToList();
        }
예제 #6
0
        /// <summary>
        /// Run fast and slow version with same  test data and display the running time
        /// </summary>
        static void Run()
        {
            // Config, test data showing ability to use negative positions
            var rect = new Rectangle
            {
                XMin        = -200,
                XMax        = 200,
                YMin        = -100,
                YMax        = 100,
                MaxDistance = 20,
            };

            rect.Validate();

            var conf = new KnnConfiguration
            {
                K            = 100,
                SameTypeOnly = false,
                MaxDistance  = null
            };

            // Random points
            IPoints points = new Points();
            var     rand   = new Random();

            for (var i = 0; i < 500000; i++)
            {
                var x = rect.XMin + rand.NextDouble() * rect.Width;
                var y = rect.YMin + rand.NextDouble() * rect.Height;
                points.Data.Add(new P
                {
                    X = x,
                    Y = y,
                });
            }
            points.Round(3);

            // Init algo
            IAlgorithm algo = new Algorithm(points, rect, StrategyType.Grid);

            // Use algo

            var origin = new P {
                X = 0, Y = 0
            };
            var duration = algo.UpdateKnn(origin, conf);

            // Print result
            WL(string.Format("{0} msec. {1}:", algo.Strategy.Name, duration));
            WL("K Nearest Neighbors:");
            WL(string.Format("Origin: {0}", origin));
            WL(string.Format("Distance sum: {0}", algo.Knn.GetDistanceSum()));
            algo.Knn.NNs.OrderBy(i => i.Distance).ToList().ForEach(WL);


            // Update strategy
            algo.SetAlgorithmStrategy(new NaiveStrategy());
            //algo.SetAlgorithmStrategy(new KdTreeStrategy(points.Data));

            // Use algo
            duration = algo.UpdateKnn(origin, conf);

            // Print result
            WL(string.Format("\n{0} msec. {1}:", algo.Strategy.Name, duration));
            WL("K Nearest Neighbors:");
            WL(string.Format("Distance sum: {0}", algo.Knn.GetDistanceSum()));
            algo.Knn.NNs.OrderBy(i => i.Distance).ToList().ForEach(WL);
        }
        // Example of usage:
        // Get 3 nearest ->             /AreaGMC/gmc.svc/Knn/lat=8_5;lon=10_25;k=3
        // Get 3 nearest type 1 ->      /AreaGMC/gmc.svc/Knn/lat=8_5;lon=10_25;k=3;type=1
        // Get nearest within 1 km ->   /AreaGMC/gmc.svc/Knn/lat=8_5;lon=10_25;k=1000000;dist=1
        public JsonKnnReply Knn(string s)
        {
            var sw = new Stopwatch();

            sw.Start();

            var invalid = new JsonKnnReply {
            };

            if (string.IsNullOrEmpty(s))
            {
                invalid.EMsg = "param is empty";
                return(invalid);
            }

            var arr = s.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

            if (arr.Length < 3)
            {
                invalid.EMsg = string.Format("param length is not valid: {0}", arr.Length);
                return(invalid);
            }

            var nvc = new NameValueCollection();

            foreach (var a in arr)
            {
                var kv = a.Split(new[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                if (kv.Length != 2)
                {
                    continue;
                }

                nvc.Add(kv[0], kv[1]);
            }

            foreach (var key in Ajax.KnnReq)
            {
                if (nvc[key] != null)
                {
                    continue;
                }

                invalid.EMsg = string.Format("param {0} is missing", key);
                return(invalid);
            }

            try
            {
                var y    = nvc[Ajax.lat].Replace("_", ".").ToDouble();
                var x    = nvc[Ajax.lon].Replace("_", ".").ToDouble();
                var k    = int.Parse(nvc[Ajax.k]);
                var type = nvc[Ajax.type] == null ? -1 : int.Parse(nvc[Ajax.type]);

                double?dist = null;
                if (!string.IsNullOrEmpty(nvc[Ajax.dist]))
                {
                    dist = nvc[Ajax.dist].Replace("_", ".").ToDouble();
                }

                // knn algo
                var algo = MemoryDatabase.Data as IKnnAlgorithm;
                if (algo == null)
                {
                    invalid.EMsg = "algorithm is not available";
                    return(invalid);
                }

                // Use algo
                var origin = new SingleDetectLibrary.Code.Data.P {
                    X = x, Y = y, Type = type
                };
                var knnSameTypeOnly = type != -1;

                var conf = new KnnConfiguration {
                    K = k, SameTypeOnly = knnSameTypeOnly, MaxDistance = dist
                };
                var duration = algo.UpdateKnn(origin, conf);

                var nns    = algo.Knn.NNs.Select(p => p as PDist).ToList();
                var gmsNns = new List <GmcPDist>();
                foreach (var i in nns)
                {
                    //i.Distance = Math.Round(i.Distance, 7);
                    var pdist = new GmcPDist
                    {
                        Id       = i.Point.Uid.ToString(),
                        Point    = i.Point,
                        Distance = Math.Round(i.Distance, 7)
                    };
                    gmsNns.Add(pdist);
                }

                var result =
                    new JsonKnnReply
                {
                    Data = string.Format("Distance in km, x: {0}; y: {1}; k: {2}; sameTypeOnly: {3}, algo msec: {4}",
                                         x.DoubleToString(), y.DoubleToString(), k, knnSameTypeOnly, duration),
                    Nns = gmsNns, // cannot be interface, thus casting

                    Msec = Sw(sw),
                };

                return(result);
            }
            catch (Exception ex)
            {
                invalid.EMsg = string.Format("Parsing error param: {0}",
                                             ex.Message);
                return(invalid);
            }
        }