[Snippets/interpolatable] Use Hungarian algorithm from munkres or scipy when available

Fixes https://github.com/fonttools/fonttools/issues/815
This commit is contained in:
Behdad Esfahbod 2017-01-19 07:18:42 -08:00
parent a141ddc400
commit 179b8b5794

View File

@ -77,36 +77,36 @@ def _matching_cost(G, matching):
def min_cost_perfect_bipartite_matching(G): def min_cost_perfect_bipartite_matching(G):
n = len(G) n = len(G)
if n <= 8: try:
# brute-force from scipy.optimize import linear_sum_assignment
permutations = itertools.permutations(range(n)) rows, cols = linear_sum_assignment(G)
best = list(next(permutations)) # This branch untested
best_cost = _matching_cost(G, best) assert rows == list(range(n))
for p in permutations: return cols, _matching_cost(G, cols)
cost = _matching_cost(G, p) except ImportError:
if cost < best_cost: pass
best, best_cost = list(p), cost
return best, best_cost
else:
# Set up current matching and inverse try:
matching = list(range(n)) # identity matching from munkres import Munkres
matching_cost = _matching_cost(G, matching) cols = [None] * n
reverse = list(matching) for row,col in Munkres().compute(G):
cols[row] = col
return cols, _matching_cost(G, cols)
except ImportError:
pass
return matching, matching_cost if n > 6:
# TODO implement real matching here raise Exception("Install Python module 'munkres' or 'scipy >= 0.17.0'")
# Set up cover # Otherwise just brute-force
cover0 = [max(c for c in row) for row in G] permutations = itertools.permutations(range(n))
cover1 = [0] * n best = list(next(permutations))
cover_weight = sum(cover0) best_cost = _matching_cost(G, best)
for p in permutations:
while cover_weight < matching_cost: cost = _matching_cost(G, p)
break if cost < best_cost:
NotImplemented best, best_cost = list(p), cost
return best, best_cost
return matching, matching_cost
def test(glyphsets, glyphs=None, names=None): def test(glyphsets, glyphs=None, names=None):