quadratic_assignment#
- scipy.optimize.quadratic_assignment(A, B, метод='faq', опции=None)[источник]#
Аппроксимирует решение квадратичной задачи назначения и задачи сопоставления графов.
Квадратичное назначение решает задачи следующего вида:
\[\begin{split}\min_P & \ {\ \text{trace}(A^T P B P^T)}\\ \mbox{s.t. } & {P \ \epsilon \ \mathcal{P}}\\\end{split}\]где \(\mathcal{P}\) является множеством всех матриц перестановок, \(A\) и \(B\) являются квадратными матрицами.
Сопоставление графов пытается максимизировать той же целевой функции. Этот алгоритм можно рассматривать как поиск выравнивания узлов двух графов, которое минимизирует количество индуцированных расхождений рёбер или, в случае взвешенных графов, сумму квадратов разностей весов рёбер.
Обратите внимание, что задача квадратичного назначения является NP-трудной. Результаты, приведённые здесь, являются приближениями и не гарантируют оптимальности.
- Параметры:
- A2-D массив, квадратный
Квадратная матрица \(A\) в целевой функции выше.
- B2-D массив, квадратный
Квадратная матрица \(B\) в целевой функции выше.
- методstr в {'faq', '2opt'} (по умолчанию: 'faq')
Алгоритм, используемый для решения задачи. ‘faq’ (по умолчанию) и ‘2opt’ доступны.
- опцииdict, optional
Словарь опций решателя. Все решатели поддерживают следующее:
- максимизироватьbool (по умолчанию: False)
Максимизирует целевую функцию, если
True.- partial_match2-D массив целых чисел, опционально (по умолчанию: None)
Исправляет часть сопоставления. Также известен как "начальное значение" [2].
Каждая строка partial_match задаёт пару сопоставленных узлов: узел
partial_match[i, 0]of A соответствует узлуpartial_match[i, 1]of B. Массив имеет форму(m, 2), гдеmне больше, чем количество узлов, \(n\).- rng
numpy.random.Generator, опционально Состояние генератора псевдослучайных чисел. Когда rng равно None, новый
numpy.random.Generatorсоздаётся с использованием энтропии из операционной системы. Типы, отличные отnumpy.random.Generatorпередаются вnumpy.random.default_rngдля создания экземпляраGenerator.Изменено в версии 1.15.0: В рамках SPEC-007 переход от использования
numpy.random.RandomStatetonumpy.random.Generatorпроисходит. Предоставление np.random.RandomState к этой функции теперь будет выдавать DeprecationWarning. В SciPy 1.17 его использование вызовет исключение. Кроме того, использование глобального состояния с помощью np.random.seed будет выдавать FutureWarning. В SciPy 1.17 глобальный генератор случайных чисел больше не будет использоваться. Использование целочисленного seed вызовет FutureWarning, в SciPy 1.17 она будет нормализована через np.random.default_rng вместо np.random.RandomState.
Для специфичных для метода опций см.
show_options('quadratic_assignment').
- Возвращает:
- resOptimizeResult
OptimizeResultсодержащий следующие поля.- col_indОдномерный массив
Индексы столбцов, соответствующие наилучшей найденной перестановке узлов B.
- funfloat
Целевое значение решения.
- nitint
Количество итераций, выполненных во время оптимизации.
Примечания
Метод по умолчанию ‘faq’ использует быстрый приближенный алгоритм QAP [1]; обычно он предлагает наилучшее сочетание скорости и точности. Метод ‘2opt’ может быть вычислительно затратным, но может быть полезной альтернативой или использоваться для уточнения решения, возвращённого другим методом.
Ссылки
[1]J.T. Vogelstein, J.M. Conroy, V. Lyzinski, L.J. Podrazik, S.G. Kratzer, E.T. Harley, D.E. Fishkind, R.J. Vogelstein, и C.E. Priebe, «Fast approximate quadratic programming for graph matching», PLOS one, vol. 10, no. 4, p. e0121002, 2015, DOI:10.1371/journal.pone.0121002
[2]D. Fishkind, S. Adali, H. Patsolic, L. Meng, D. Singh, V. Lyzinski, C. Priebe, “Seeded graph matching”, Pattern Recognit. 87 (2019): 203-215, DOI:10.1016/j.patcog.2018.09.014
[3]“2-opt,” Википедия. https://en.wikipedia.org/wiki/2-opt
Примеры
>>> import numpy as np >>> from scipy.optimize import quadratic_assignment >>> rng = np.random.default_rng() >>> A = np.array([[0, 80, 150, 170], [80, 0, 130, 100], ... [150, 130, 0, 120], [170, 100, 120, 0]]) >>> B = np.array([[0, 5, 2, 7], [0, 0, 3, 8], ... [0, 0, 0, 3], [0, 0, 0, 0]]) >>> res = quadratic_assignment(A, B, options={'rng': rng}) >>> print(res) fun: 3260 col_ind: [0 3 2 1] nit: 9
Чтобы увидеть взаимосвязь между возвращаемыми
col_indиfunиспользуйтеcol_indчтобы сформировать найденную наилучшую матрицу перестановок, затем вычислить целевую функцию \(f(P) = trace(A^T P B P^T )\).>>> perm = res['col_ind'] >>> P = np.eye(len(A), dtype=int)[perm] >>> fun = np.trace(A.T @ P @ B @ P.T) >>> print(fun) 3260
В качестве альтернативы, чтобы избежать явного построения матрицы перестановок, непосредственно переставьте строки и столбцы матрицы расстояний.
>>> fun = np.trace(A.T @ B[perm][:, perm]) >>> print(fun) 3260
Хотя в общем случае не гарантируется,
quadratic_assignmentслучайно нашел глобально оптимальное решение.>>> from itertools import permutations >>> perm_opt, fun_opt = None, np.inf >>> for perm in permutations([0, 1, 2, 3]): ... perm = np.array(perm) ... fun = np.trace(A.T @ B[perm][:, perm]) ... if fun < fun_opt: ... fun_opt, perm_opt = fun, perm >>> print(np.array_equal(perm_opt, res['col_ind'])) True
Вот пример, для которого метод по умолчанию, ‘faq’, не находит глобальный оптимум.
>>> A = np.array([[0, 5, 8, 6], [5, 0, 5, 1], ... [8, 5, 0, 2], [6, 1, 2, 0]]) >>> B = np.array([[0, 1, 8, 4], [1, 0, 5, 2], ... [8, 5, 0, 5], [4, 2, 5, 0]]) >>> res = quadratic_assignment(A, B, options={'rng': rng}) >>> print(res) fun: 178 col_ind: [1 0 3 2] nit: 13
Если важна точность, рассмотрите использование ‘2opt’ для уточнения решения.
>>> guess = np.array([np.arange(len(A)), res.col_ind]).T >>> res = quadratic_assignment(A, B, method="2opt", ... options = {'rng': rng, 'partial_guess': guess}) >>> print(res) fun: 176 col_ind: [1 2 3 0] nit: 17