bundles / scipy 2.0.0.dev0+git20260907.41eeb59 / scipy / optimize / _qap / quadratic_assignment
function
scipy.optimize._qap:quadratic_assignment
source: build-install/usr/lib/python3.14/site-packages/scipy/optimize/_qap.py:11
Signature
def quadratic_assignment(A, B, method = faq, options = None)Summary
Approximates solution to the quadratic assignment problem and the graph matching problem.
Extended Summary
Quadratic assignment solves problems of the following form:
\min_P & \ {\ \text{trace}(A^T P B P^T)}\\
\mbox{s.t. } & {P \ \epsilon \ \mathcal{P}}\\where is the set of all permutation matrices, and and are square matrices.
Graph matching tries to maximize the same objective function. This algorithm can be thought of as finding the alignment of the nodes of two graphs that minimizes the number of induced edge disagreements, or, in the case of weighted graphs, the sum of squared edge weight differences.
Note that the quadratic assignment problem is NP-hard. The results given here are approximations and are not guaranteed to be optimal.
Parameters
A: 2-D array, squareThe square matrix in the objective function above.
B: 2-D array, squareThe square matrix in the objective function above.
method: str in {'faq', '2opt'} (default: 'faq')The algorithm used to solve the problem. 'faq' (default) and '2opt' are available.
options: dict, optionalA dictionary of solver options. All solvers support the following:
maximize
Maximizes the objective function if
True.partial_match
Fixes part of the matching. Also known as a "seed" [2].
Each row of
partial_matchspecifies a pair of matched nodes: nodepartial_match[i, 0]ofAis matched to nodepartial_match[i, 1]ofB. The array has shape(m, 2), wheremis not greater than the number of nodes, .rng
Pseudorandom number generator state. When
rngis None, a new numpy.random.Generator is created using entropy from the operating system. Types other than numpy.random.Generator are passed to numpy.random.default_rng to instantiate aGenerator.
For method-specific options, see show_options('quadratic_assignment').
Returns
res: OptimizeResultOptimizeResult containing the following fields.
col_ind
Column indices corresponding to the best permutation found of the nodes of
B.fun
The objective value of the solution.
nit
The number of iterations performed during optimization.
Notes
The default method 'faq' uses the Fast Approximate QAP algorithm [1]; it typically offers the best combination of speed and accuracy. Method '2opt' can be computationally expensive, but may be a useful alternative, or it can be used to refine the solution returned by another method.
Examples
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
The see the relationship between the returned ``col_ind`` and ``fun``,
use ``col_ind`` to form the best permutation matrix found, then evaluate
the objective function :math:`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)✓
3260Alternatively, to avoid constructing the permutation matrix explicitly, directly permute the rows and columns of the distance matrix.
fun = np.trace(A.T @ B[perm][:, perm]) print(fun)✓
3260Although not guaranteed in general, ``quadratic_assignment`` happens to have found the globally optimal solution.
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']))✓
TrueHere is an example for which the default method, :ref:`'faq' <optimize.qap-faq>`, does not find the global optimum.
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
If accuracy is important, consider using :ref:`'2opt' <optimize.qap-2opt>`
to refine the solution.
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
Aliases
scipy.optimize.quadratic_assignment