Constrained tuning: Difference between revisions
Add KE back per discussion. Now weight and skewed are collectively denoted by X. p-norm -> q-norm since it's the dual norm (p is reserved for interval space norm) |
→Computation: update code |
||
| Line 30: | Line 30: | ||
== Computation == | == Computation == | ||
As a standard optimization problem, numerous algorithms exist to solve it, such as [[Wikipedia: Sequential quadratic programming|sequential quadratic programming]], to name one. [[Flora Canou]]'s [https://github.com/FloraCanou/temperament_evaluator/blob/ | As a standard optimization problem, numerous algorithms exist to solve it, such as [[Wikipedia: Sequential quadratic programming|sequential quadratic programming]], to name one. [[Flora Canou]]'s [https://github.com/FloraCanou/temperament_evaluator/blob/85b847a41ab0f6273ea43394147b1b8f8a13b8ea/te_optimizer_legacy.py tuning optimizer] is such an implementation in [https://www.python.org Python]. Note: it uses [https://scipy.org/ Scipy]. | ||
{{Databox| Code | | {{Databox| Code | | ||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
# © 2020-2023 Flora Canou | Version 0.26. | # © 2020-2023 Flora Canou | Version 0.26.2 | ||
# This work is licensed under the GNU General Public License version 3. | # This work is licensed under the GNU General Public License version 3. | ||
| Line 70: | Line 70: | ||
return np.eye (len (subgroup)) | return np.eye (len (subgroup)) | ||
elif self.order == 2: | elif self.order == 2: | ||
r = 1/(len (subgroup)*self.skew + 1/self.skew) | |||
kr = 1/(len (subgroup) + 1/self.skew**2) | |||
else: | else: | ||
raise NotImplementedError ("Weil skew only works with Euclidean norm as of now.") | raise NotImplementedError ("Weil skew only works with Euclidean norm as of now.") | ||
| Line 96: | Line 92: | ||
return main, subgroup | return main, subgroup | ||
def __error (gen, vals, | def __error (gen, vals, just_tuning_map, order): | ||
return linalg.norm (gen @ vals - | return linalg.norm (gen @ vals - just_tuning_map, ord = order) | ||
def optimizer_main (vals, subgroup = None, norm = Norm (), #"map" is a reserved word | def optimizer_main (vals, subgroup = None, norm = Norm (), #"map" is a reserved word | ||
| Line 103: | Line 99: | ||
vals, subgroup = __get_subgroup (vals, subgroup) | vals, subgroup = __get_subgroup (vals, subgroup) | ||
just_tuning_map = np.log2 (subgroup)*SCALAR | |||
vals_x = norm.weightskewed (vals, subgroup) | |||
just_tuning_map_x = norm.weightskewed (just_tuning_map, subgroup) | |||
if norm.order == 2 and cons_monzo_list is None: #simply using lstsq for better performance | if norm.order == 2 and cons_monzo_list is None: #simply using lstsq for better performance | ||
res = linalg.lstsq ( | res = linalg.lstsq (vals_x.T, just_tuning_map_x) | ||
gen = res[0] | gen = res[0] | ||
print ("Euclidean tuning without constraints, solved using lstsq. ") | print ("Euclidean tuning without constraints, solved using lstsq. ") | ||
else: | else: | ||
gen0 = [SCALAR]*vals.shape[0] #initial guess | gen0 = [SCALAR]*vals.shape[0] #initial guess | ||
cons = () if cons_monzo_list is None else {'type': 'eq', 'fun': lambda gen: (gen @ vals - | cons = () if cons_monzo_list is None else {'type': 'eq', 'fun': lambda gen: (gen @ vals - just_tuning_map) @ cons_monzo_list} | ||
res = optimize.minimize (__error, gen0, args = ( | res = optimize.minimize (__error, gen0, args = (vals_x, just_tuning_map_x, norm.order), method = "SLSQP", | ||
options = {'ftol': 1e-9}, constraints = cons) | options = {'ftol': 1e-9}, constraints = cons) | ||
print (res.message) | print (res.message) | ||
| Line 127: | Line 123: | ||
raise ZeroDivisionError ("destretch target is in the nullspace. ") | raise ZeroDivisionError ("destretch target is in the nullspace. ") | ||
else: | else: | ||
gen *= ( | gen *= (just_tuning_map @ des_monzo)/tempered_size | ||
tempered_tuning_map = gen @ vals | |||
mistuning_map = | mistuning_map = tempered_tuning_map - just_tuning_map | ||
if show: | if show: | ||
print (f"Generators: {gen} (¢)", | print (f"Generators: {gen} (¢)", | ||
f"Tuning map: { | f"Tuning map: {tempered_tuning_map} (¢)", | ||
f"Mistuning map: {mistuning_map} (¢)", sep = "\n") | f"Mistuning map: {mistuning_map} (¢)", sep = "\n") | ||
return gen, | return gen, tempered_tuning_map, mistuning_map | ||
optimiser_main = optimizer_main | optimiser_main = optimizer_main | ||