Такое поведение scipy.spatial.Delaunay
может быть связано с неточностью арифметики с плавающей запятой.
Как вы, возможно, знаете, scipy.spatial.Delaunay
использует библиотеку C qhull
для расчета триангуляции Делоне. Qhull
, в свою очередь, является реализацией алгоритма Quickhull
, который подробно описан авторами в этой статье (1). Вы также можете знать, что арифметика с плавающей точкой, используемая в компьютерах, выполняется с использованием стандарта IEEE 754 (об этом вы можете прочитать, например, в Wikipedia ). Согласно стандарту, каждое конечное число проще всего описывается тремя целыми числами: s
= знак (ноль или один), c
= значение и (или «коэффициент»), q
= показатель степени. Количество битов, используемых для представления этих целых чисел, зависит от типа данных. Итак, очевидно, что плотность распределения чисел с плавающей запятой по числовой оси не постоянна - чем больше числа, тем более свободно они распределены. Это можно увидеть даже с помощью калькулятора Google - вы можете вычесть 3333333333333333 из 3333333333333334 и получить 0 . Это происходит потому, что 3333333333333333 и 3333333333333334 оба округлены до одного и того же числа с плавающей запятой.
Теперь, зная об ошибках округления, мы могли бы прочитать главу 4 статьи (1), озаглавленную Копирование с неточностью . В этой главе описан алгоритм работы с ошибками округления:
Quickhull partitions a point and determines its horizon facets by computing
whether the point is above or below a hyperplane. We have assumed that
computations return consistent results ... With floating-point arithmetic, we
cannot prevent errors from occurring, but we can repair the damage after
processing a point. We use brute force: if adjacent facets are nonconvex, one of
the facets is merged into a neighbor. Quickhull merges the facet that minimizes
the maximum distance of a vertex to the neighbor.
Так вот, что может случиться - Quickhull
не может различить 2 соседние точки, поэтому он объединяет две грани, таким образом, удаляя одну из них. Чтобы устранить эти ошибки, вы можете, например, попытаться переместить начало координат:
co = points[0]
points = points - co
edges1 = delaunay_edges(points)
edges2 = delaunay_edges_matplotlib(points)
print numpy.unique(edges1)
>>> [0 1 2 3 4]
print numpy.unique(edges2)
>>> [0 1 2 3 4]
Это перемещает вычисления в область, где числа с плавающей запятой достаточно плотные.