Разделение соседних точек с учетом евклидова расстояния - PullRequest
0 голосов
/ 06 декабря 2010

Учитывая две точки P, Q и дельту, я определил отношение эквивалентности ~ =, где P ~ = Q, если EuclideanDistance(P,Q) <= дельта.Теперь, учитывая набор <em>S из n точек, в примере S = (A, B, C, D, E, F) и n = 6 (точки факта на самом делеконечные точки сегментов пренебрежимо малы), существует ли алгоритм, имеющий сложность лучше, чем O (n ^ 2) в среднем случае, чтобы найти разбиение множества (репрезентативный элемент подмножеств не имеет значения)?

Попытки найти теоретические определения этой проблемы до сих пор не увенчались успехом: кластеризация k-средних, поиск ближайшего соседа и другие, как мне кажется, другие проблемы.На рисунке показано, что мне нужно сделать в моем приложении.

Есть подсказка?Спасибо

alt text

РЕДАКТИРОВАТЬ : в то время как реальная проблема (кластерные точки вблизи заданного некоторого инварианта) должна решаться лучше, чем O (n ^ 2)) в среднем случае в моем определении проблемы есть серьезный недостаток: = ~ is не отношение эквивалентности из-за простого факта, что оно не учитывает транзитивное свойство .Я думаю, что это главная причина, по которой эту проблему нелегко решить и которая требует передовых методов.Очень скоро опубликует мое реальное решение: должно работать, когда все точки удовлетворяют условию = ~, как определено.Может потерпеть неудачу, когда полюса разделяют точки, не уважая отношения, но они связаны с центром тяжести кластерных точек.Это хорошо работает с моим входным пространством данных, может не с вашим.Кто-нибудь знает полное формальное решение этой проблемы (с решением)?

Ответы [ 5 ]

1 голос
/ 06 декабря 2010

Один из способов переформулировать проблему заключается в следующем: при заданном наборе n 2D точек для каждой точки p найдите набор точек, содержащихся в окружности диаметром delta с центром в p.

Наивный линейный поиск дает алгоритм O(n^2), на который вы ссылаетесь.

Мне кажется, что это лучшее, что можно сделать в худшем случае .Когда все точки в наборе содержатся в окружности диаметром <= <code>delta, каждый из n запросов должен будет возвращать O(n) точек, что создает общую сложность O(n^2).

Однако,нужно уметь работать лучше на более разумных наборах данных.Взгляните на this (особенно раздел о разделении пространства) и KD-деревьев .Последний должен дать вам алгоритм под O(n^2) в разумных случаях.

Возможно, существует другой способ взглянуть на проблему, который даст лучшую сложность;Я не могу думать ни о чем из головы.

0 голосов
/ 10 декабря 2010

Следующий метод C #, вместе с классом KdTree, методы Join () (перечисляют все коллекции, переданные в качестве аргумента) и методы Shuffled () (возвращают перемешанную версию переданной коллекции), решают проблему моего вопроса.Могут быть некоторые ошибочные случаи (см. РЕДАКТИРОВАТЬ в вопросе), когда referenceVectors - это те же векторы, что и vectorsToRelocate, как я делаю в своей проблеме.Должно быть perfect , если у вас действительно есть эталонные векторы, так что этот метод вам действительно нравится.: D

public static Dictionary<Vector2D, Vector2D> FindRelocationMap(
    IEnumerable<Vector2D> referenceVectors,
    IEnumerable<Vector2D> vectorsToRelocate)
{
    Dictionary<Vector2D, Vector2D> ret = new Dictionary<Vector2D, Vector2D>();

    // Preliminary filling
    IEnumerable<Vector2D> allVectors =
        Utils.Join(referenceVectors, vectorsToRelocate);
    foreach (Vector2D vector in allVectors)
        ret[vector] = vector;

    KdTree<Vector2D> kdTree = new KdTree<Vector2D>(
        delegate(Vector2D vector) { return vector.X; },
        delegate(Vector2D vector) { return vector.Y; });
    kdTree.InsertAll(Utils.Shuffled(ret.Keys));

    HashSet<Vector2D> relocatedVectors = new HashSet<Vector2D>();
    foreach (Vector2D vector in referenceVectors)
    {
        if (relocatedVectors.Contains(vector))
            continue;

        relocatedVectors.Add(vector);

        IEnumerable<Vector2D> neighbors =
            kdTree.FindNeighborsRange(vector, Tolerances.EUCLID_DIST_TOLERANCE);

        foreach (Vector2D neighbor in neighbors)
        {
            ret[neighbor] = vector;
            relocatedVectors.Add(neighbor);
        }
    }

    return ret;
}
0 голосов
/ 07 декабря 2010

Это реализация C # KdTree, которая должна решить «Найти всех соседей точки P в пределах дельта ». Он интенсивно использует методы функционального программирования (да, я люблю Python). Это проверено , но у меня все еще есть сомнения в понимании _TreeFindNearest(). Код (или псевдокод) для решения проблемы «Разделить набор из n точек с отношением ~ = лучше, чем O (n ^ 2) в среднем случае» размещен в другом ответе.

/*
Stripped C# 2.0 port of ``kdtree'', a library for working with kd-trees.
Copyright (C) 2007-2009 John Tsiombikas <nuclear@siggraph.org>
Copyright (C) 2010 Francesco Pretto <ceztko@gmail.com>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace ITR.Data.NET
{
    public class KdTree<T>
    {
        #region Fields

        private Node _Root;
        private int _Count;
        private int _Dimension;
        private CoordinateGetter<T>[] _GetCoordinate;

        #endregion // Fields

        #region Constructors

        public KdTree(params CoordinateGetter<T>[] coordinateGetters)
        {
            _Dimension = coordinateGetters.Length;
            _GetCoordinate = coordinateGetters;
        }

        #endregion // Constructors

        #region Public methods

        public void Insert(T location)
        {
            _TreeInsert(ref _Root, 0, location);
            _Count++;
        }

        public void InsertAll(IEnumerable<T> locations)
        {
            foreach (T location in locations)
                Insert(location);
        }

        public IEnumerable<T> FindNeighborsRange(T location, double range)
        {
            return _TreeFindNeighborsRange(_Root, 0, location, range);
        }

        #endregion // Public methods

        #region Tree traversal

        private void _TreeInsert(ref Node current, int currentPlane, T location)
        {
            if (current == null)
            {
                current = new Node(location);
                return;
            }

            int nextPlane = (currentPlane + 1) % _Dimension;

            if (_GetCoordinate[currentPlane](location) <
                    _GetCoordinate[currentPlane](current.Location))
                _TreeInsert(ref current._Left, nextPlane, location);
            else
                _TreeInsert(ref current._Right, nextPlane, location);
        }

        private IEnumerable<T> _TreeFindNeighborsRange(Node current, int currentPlane,
            T referenceLocation, double range)
        {
            if (current == null)
                yield break;

            double squaredDistance = 0;
            for (int it = 0; it < _Dimension; it++)
            {
                double referenceCoordinate = _GetCoordinate[it](referenceLocation);
                double currentCoordinate = _GetCoordinate[it](current.Location);
                squaredDistance +=
                    (referenceCoordinate - currentCoordinate)
                    * (referenceCoordinate - currentCoordinate);
            }

            if (squaredDistance <= range * range)
                yield return current.Location;

            double coordinateRelativeDistance =
                _GetCoordinate[currentPlane](referenceLocation)
                    - _GetCoordinate[currentPlane](current.Location);
            Direction nextDirection = coordinateRelativeDistance <= 0.0
                ? Direction.LEFT : Direction.RIGHT;
            int nextPlane = (currentPlane + 1) % _Dimension;
            IEnumerable<T> subTreeNeighbors =
                _TreeFindNeighborsRange(current[nextDirection], nextPlane,
                    referenceLocation, range);
            foreach (T location in subTreeNeighbors)
                yield return location;

            if (Math.Abs(coordinateRelativeDistance) <= range)
            {
                subTreeNeighbors =
                    _TreeFindNeighborsRange(current.GetOtherChild(nextDirection),
                        nextPlane, referenceLocation, range);
                foreach (T location in subTreeNeighbors)
                    yield return location;
            }
        }

        #endregion // Tree traversal

        #region Node class

        public class Node
        {
            #region Fields

            private T _Location;
            internal Node _Left;
            internal Node _Right;

            #endregion // Fields

            #region Constructors

            internal Node(T nodeValue)
            {
                _Location = nodeValue;
                _Left = null;
                _Right = null;
            }

            #endregion // Contructors

            #region Children Indexers

            public Node this[Direction direction]
            {
                get { return direction == Direction.LEFT ? _Left : Right; }
            }

            public Node GetOtherChild(Direction direction)
            {
                return direction == Direction.LEFT ? _Right : _Left;
            }

            #endregion // Children Indexers

            #region Properties

            public T Location
            {
                get { return _Location; }
            }

            public Node Left
            {
                get { return _Left; }
            }

            public Node Right
            {
                get { return _Right; }
            }

            #endregion // Properties
        }

        #endregion // Node class

        #region Properties

        public int Count
        {
            get { return _Count; }
            set { _Count = value; }
        }

        public Node Root
        {
            get { return _Root; }
            set { _Root = value; }
        }

        #endregion // Properties
    }

    #region Enums, delegates

    public enum Direction
    {
        LEFT = 0,
        RIGHT
    }

    public delegate double CoordinateGetter<T>(T location);

    #endregion // Enums, delegates
}
0 голосов
/ 07 декабря 2010

Для каждой точки рассчитайте расстояние D (n) от начала координат, это операция O (n).

Используйте алгоритм O (n ^ 2), чтобы найти совпадения, где D (a-b) <дельта, <em>пропуск D (a) -D (b)> дельта.

Результат в среднем должен быть лучше, чем O (n ^ 2) из-за пропущенного (надеюсь большого) числа.

0 голосов
/ 06 декабря 2010

Определенно проблема для Quadtree .

Вы также можете попробовать отсортировать по каждому координату и поиграть с этими двумя списками (сортировка n*log(n), и вы можете проверить только те точки, которыеудовлетворяет dx <= delta && dy <= delta. Кроме того, вы можете поместить их в отсортированный список с двумя уровнями указателей: один для анализа на OX и другой для OY.

...