Я пытался прояснить свой вопрос. Старое отступление все еще можно найти в конце этого.
ПРОБЛЕМА : у меня есть n
на 3 матрицы A
(np.ndarray
) n
точек в три измерения. Мы говорим, что эти точки симметричны c относительно преобразования R
(матрица 3 на 3), если они неподвижны как неупорядоченное множество.
Это означает, что A
и A @ R.T
отличаются на 1. самое большее перестановка и 2. после исправления перестановки обе матрицы могут отличаться числовым параметром допуска: np.allclose(A, permuted(A @ R.T)) == True
(заранее я не знаю permuted()
, и это, безусловно, зависит от R
).
ВОПРОС : как мне создать следующую функцию:
def is_symmetric(A, R, atol=1e-5) -> bool:
# checks symmetry as defined above, considering both numerical noise
# and permutation of vectors.
(Некоторое обсуждение возможных путей и моих сомнений и попыток можно найти ниже.)
OLD DIGRESSION :
Я хочу проверить симметрию в наборе точек, представленных в виде векторов. Это означает проверку того, являются ли эти точки инвариантными относительно применения матричного преобразования в пространстве, например, вращения или зеркального отражения.
import numpy as np
R = np.array([[0, -1, 0], # 90° rotation around z as an example
[1, 0, 0],
[0, 0, 1]])
Дело в том, что Я принимаю перестановку векторов : пока какая-то начальная позиция преобразуется в другую, ранее существовавшую локацию, я в порядке. Это означает проверку преобразованных пар векторов от одного к другому.
Наивное решение будет зацикливаться на строках A @ R.T
(где A
- матрица, строки которой положения точек) и попытайтесь сопоставить преобразованный вектор для каждой начальной строки A
, который, по-видимому, растет квадратично с числом столбцов.
Другой возможностью будет предварительное упорядочение векторов ( скажем, по значениям их координат):
A = np.array([[1, 0, 0], # some points
[0, 1, 0],
[0, 0, 1],
[0.5, 0.5, 0]])
A = np.array(sorted(A, key=lambda v: (v[2], v[1], v[0]))) # sort by z, y, x values
# array([[1. , 0. , 0. ],
# [0.5, 0.5, 0. ],
# [0. , 1. , 0. ],
# [0. , 0. , 1. ]])
A_rotated = np.array(sorted(A @ R.T, key=lambda v: (v[2], v[1], v[0])))
# array([[-1. , 0. , 0. ], # no match
# [-0.5, 0.5, 0. ], # no match
# [ 0. , 1. , 0. ], # match
# [ 0. , 0. , 1. ]]) # match
(Этот подход делает два вида, поэтому O (n ln (n))?) Третья идея заключается в сравнении наборов , созданных из оригинальные и повернутые векторы. У меня есть ощущение, что это так же хорошо, как сравнивать отсортированные векторы.
Но остается одно: как справиться с приближенным сравнением? Я хочу принять два вектора v
и w
равными, если, например, np.allclose(v, w) == True
или эквивалент (т. Е. abs(v - w) < eps
или аналогичный):
np.allclose([1, 0, 0], [1, 0, 0])
# True
np.allclose([1, 0, 0], [1 + 1e-5, 0, 0], atol=1e-5)
# True
np.allclose([1, 0, 0], [1 + 1e-4, 0, 0], atol=1e-5)
# False
Так что вот вопрос : как (эффективно) сравнить два (неупорядоченных) набора векторов на равенство с учетом числового приближения (например, np.allclose
)?