Wedgie: Difference between revisions
- misinformation. Cleanup. Style |
→Conversion: complete |
||
| (5 intermediate revisions by 2 users not shown) | |||
| Line 6: | Line 6: | ||
== How to read a wedgie == | == How to read a wedgie == | ||
One way to characterize temperaments is by how many parts they split important intervals into – for example, the octave and the perfect fifth. The [[ploidacot]] system works under this principle, and the reader is encouraged to be familiarized with it. | |||
For any ''n''-prime subgroup of a rank-''n'' temperament, there exist a finite number (1 or more) of copies of that subgroup within the temperament. Think of these as "universes" that are connected exclusively by intervals of that subgroup and may be travelled between by using intervals outside the subgroup. For example, a temperament that is [[Ploidacot/Diploid dicot|diploid dicot]] – dividing the octave into two parts and also dividing the perfect fifth into two parts – will have a 2.3 wedgie entry of 4 (since there are four distinct copies of the 3-limit – the basic 3-limit, offset by a neutral third, offset by a semioctave, and offset by both). Each wedgie entry counts the number of copies of its corresponding subgroup. Because any temperament can be defined by splitting some interval and assigning the parts just interpretations, this is enough to uniquely characterize the temperament. | For any ''n''-prime subgroup of a rank-''n'' temperament, there exist a finite number (1 or more) of copies of that subgroup within the temperament. Think of these as "universes" that are connected exclusively by intervals of that subgroup and may be travelled between by using intervals outside the subgroup. For example, a temperament that is [[Ploidacot/Diploid dicot|diploid dicot]] – dividing the octave into two parts and also dividing the perfect fifth into two parts – will have a 2.3 wedgie entry of 4 (since there are four distinct copies of the 3-limit – the basic 3-limit, offset by a neutral third, offset by a semioctave, and offset by both). Each wedgie entry counts the number of copies of its corresponding subgroup. Because any temperament can be defined by splitting some interval and assigning the parts just interpretations, this is enough to uniquely characterize the temperament. | ||
| Line 41: | Line 41: | ||
== Form of a wedgie == | == Form of a wedgie == | ||
A wedgie is essentially a compressed ''r''-dimensional {{w|antisymmetric tensor}}. | |||
For rank-2 temperaments, this becomes an {{w|antisymmetric matrix}}. In particular, the notation being used previously, {{multival| ''x'' ''y'' ''z'' }}, is formally a shorthand for a matrix form, written | |||
$$ | $$ | ||
| Line 73: | 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 82: | Line 82: | ||
from scipy import linalg | from scipy import linalg | ||
def | def breeds2wedgie (breeds): | ||
combinations = itertools.combinations (range ( | """Takes a mapping, returns the corresponding wedgie. """ | ||
wedgie = np.array ([linalg.det (breeds[:, entry]) for entry in combinations]) | |||
r, d = breeds.shape # rank and dimensionality | |||
combinations = itertools.combinations (range (d), r) | |||
wedgie = np.array ([linalg.det (breeds[:, entry]) for entry in combinations], ndmin = r) | |||
# normalize for a positive first entry | # normalize for a positive first entry | ||
# unneeded if the mapping is in canonical form | # unneeded if the mapping is in canonical form | ||
if wedgie[0] < 0: | if wedgie.flat[0] < 0: | ||
wedgie *= -1 | wedgie *= -1 | ||
| Line 100: | 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 == | ||
| Line 107: | Line 175: | ||
Two [[vals]] can be combined into a wedgie representing the rank-2 temperament they both support using the wedge product. For example, wedging {{val| 5 8 12 }} and {{val| 7 11 16 }} (the patent vals for 5edo and 7edo) yields {{multival| (5×11 - 8×7) (5×16 - 12×7) (8×16 - 12×11) }}, which simplifies to {{multival| (55 - 56) (80 - 84) (128 - 132) }} and thus to {{multival| -1 -4 -4 }}. Note that we generally assume the first entry of the wedgie should be positive, for which we flip all the signs of it to obtain {{multival| 1 4 4 }}, which is the wedgie for 5 & 7, a.k.a. meantone. | Two [[vals]] can be combined into a wedgie representing the rank-2 temperament they both support using the wedge product. For example, wedging {{val| 5 8 12 }} and {{val| 7 11 16 }} (the patent vals for 5edo and 7edo) yields {{multival| (5×11 - 8×7) (5×16 - 12×7) (8×16 - 12×11) }}, which simplifies to {{multival| (55 - 56) (80 - 84) (128 - 132) }} and thus to {{multival| -1 -4 -4 }}. Note that we generally assume the first entry of the wedgie should be positive, for which we flip all the signs of it to obtain {{multival| 1 4 4 }}, which is the wedgie for 5 & 7, a.k.a. meantone. | ||
More than two vals can be combined into a higher-rank wedgie by an analogous method. | More than two vals can be combined into a higher-rank wedgie by an analogous method. This involves, in this case of converting multiples vals into only one comma, taking the maximal minors (determinants of a rectangular matrix's square subsets) of the collection and accounting for the prime that is not included in the subgroup (one-column-one-prime, as given). For example, the 7-limit wedgie for 5 & 6 & 7, {{multival|-2 1 0 -8}}, tempers out [[256/245]], the bapbo comma. | ||
== See also == | == See also == | ||
* [[Wedgie/Archived version]] | * [[Wedgie/Archived version]] | ||
* [[Dave Keenan & Douglas Blumeyer's guide to EA for RTT]] | |||
* [[Catalog of temperaments by wedgie]] | * [[Catalog of temperaments by wedgie]] | ||
* [[Ploidacot]] | * [[Ploidacot]] | ||