Wedgie: Difference between revisions
→How to read a wedgie: make it explicit that readers are expected to learn another system first |
→Conversion: complete |
||
| Line 75: | Line 75: | ||
== Conversion == | == Conversion == | ||
=== Mapping matrix to wedgie === | === Mapping matrix to wedgie === | ||
The wedgie may be found from the mapping by taking the {{w|determinant}}s of the mapping's column slices that correspond to all the combinations of formal primes. | The wedgie may be found from the mapping by taking the {{w|determinant}}s of the mapping's column slices that correspond to all the combinations of formal primes. Below is a minimalistic [https://www.python.org/ Python] script that finds the wedgie from a mapping matrix, using [https://scipy.org/ SciPy]. | ||
Below is a [https://www.python.org/ Python] script that finds the wedgie from a mapping matrix, using [https://scipy.org/ | |||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
| Line 84: | Line 82: | ||
from scipy import linalg | from scipy import linalg | ||
def | def breeds2wedgie (breeds): | ||
"""Takes a mapping, returns the corresponding wedgie. """ | |||
r, d = breeds.shape # rank and dimensionality | r, d = breeds.shape # rank and dimensionality | ||
combinations = itertools.combinations (range (d), r) | combinations = itertools.combinations (range (d), r) | ||
| Line 103: | Line 103: | ||
=== Wedgie to mapping matrix === | === Wedgie to mapping matrix === | ||
Converting, or ''decomposing'', a wedgie to a mapping matrix is much more complicated. [[Gene Ward Smith]]'s provided an algorithm, explained in [[Dave Keenan & Douglas Blumeyer's guide to EA for RTT #Gene's algorithm]], and implemented in Python by [[Flora Canou]] as part of the [https://github.com/FloraCanou/temperament_evaluator Temperament Evaluator] since v1.21.0. Below is an adaptation. It requires [https://numpy.org/ NumPy] and [https://www.sympy.org/en/index.html SymPy]. | |||
<syntaxhighlight lang="python"> | |||
import itertools, math | |||
import numpy as np | |||
from sympy.matrices import Matrix, normalforms | |||
def wedgie2breeds (wedgie): | |||
""" | |||
Takes a wedgie, returns the corresponding mapping if decomposable, | |||
or None otherwise. Gene Ward Smith's algorithm. | |||
""" | |||
def inversion_count (a): | |||
""" | |||
Returns the number of inversions in an array, | |||
which equals the number of swaps required to sort it. | |||
https://stackoverflow.com/a/20990301 | |||
""" | |||
length = len (a) | |||
count = 0 | |||
for i in range (length - 1): | |||
for j in range (i + 1, length): | |||
if a[i] > a[j]: | |||
count += 1 | |||
return count | |||
def hnf (a): | |||
"""Normalizes a matrix row-style to the Hermite normal form. """ | |||
return np.flip (np.array ( | |||
normalforms.hermite_normal_form (Matrix (np.flip (a).T)).T, dtype = int)) | |||
# check contorsion | |||
if np.gcd.reduce (wedgie.flat) != 1: | |||
return None | |||
# find the rank r and dimensionality d | |||
r = wedgie.ndim | |||
length = len (wedgie.flat) | |||
for d in itertools.count (start = r): | |||
length_current = math.comb (d, r) | |||
if length_current == length: | |||
break | |||
elif length_current > length: | |||
raise ValueError ("invalid length for the rank. ") | |||
# gene's b and c, converted to tuples | |||
# so that they will reset themselves on the beginning of each loop | |||
combinations = tuple (itertools.combinations (range (d), r)) | |||
subcombinations = tuple (itertools.combinations (range (d), r - 1)) | |||
# main algorithm | |||
breeds = np.zeros ((len (subcombinations), d), dtype = int) | |||
for i, si in enumerate (subcombinations): | |||
for j in range (d): | |||
if j in si: | |||
continue | |||
appended_index = (*si, j) | |||
sign = 1 if inversion_count (appended_index) % 2 == 0 else -1 | |||
k = combinations.index (tuple (sorted (appended_index))) | |||
breeds[i][j] = sign*wedgie.flat[k] | |||
breeds = hnf (breeds) | |||
return breeds if breeds.shape == (r, d) else None | |||
</syntaxhighlight> | |||
== Derivation from edo joins == | == Derivation from edo joins == | ||