Constrained tuning: Difference between revisions

Fix the wrong definition that went unnoticed for months
Update the code
Line 23: Line 23:
As a standard optimization problem, numerous algorithms exist to solve for this tuning, such as [[Wikipedia: Sequential quadratic programming|sequential quadratic programming]], to name one.  
As a standard optimization problem, numerous algorithms exist to solve for this tuning, such as [[Wikipedia: Sequential quadratic programming|sequential quadratic programming]], to name one.  


The following [https://www.python.org Python] code is an excerpt from [[Flora Canou]]'s [https://github.com/FloraCanou/te_temperament_measures/blob/c72b7a9ab603f5f46fef8465c3c5355c2caf19bc/tuning_optimizer.py tuning optimizer]. Note: it depends on [https://scipy.org/ Scipy].  
The following [https://www.python.org Python] code is an excerpt from [[Flora Canou]]'s [https://github.com/FloraCanou/te_temperament_measures/blob/54c9ec58acf0ad5adc7c1d96f2deaf1d2a503702/tuning_optimizer.py tuning optimizer]. Note: it depends on [https://scipy.org/ Scipy].  
 
{{Todo|inline=1| update | comment=The code was based on the wrong definition. }}


{{Databox| Code |
{{Databox| Code |
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
# © 2020-2021 Flora Canou | Version 0.5
# © 2020-2021 Flora Canou | Version 0.8
# 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 39: Line 37:
SCALAR = 1200 #could be in octave, but for precision reason
SCALAR = 1200 #could be in octave, but for precision reason


def weighted (matrix, subgroup):
def weighted (matrix, subgroup, type = "tenney"):
     tenney_weighter = np.diag (1/np.log2 (subgroup))
     if not type in {"tenney", "frobenius"}:
     return matrix @ tenney_weighter
        type = "tenney"
 
    if type == "tenney":
        weighter = np.diag (1/np.log2 (subgroup))
    elif type == "frobenius":
        weighter = np.eye (len (subgroup))
     return matrix @ weighter


def error (gen, map, jip, order = 2):
def error (gen, map, jip, order = 2):
     return linalg.norm (gen @ map - jip, ord = order)
     return linalg.norm (gen @ map - jip, ord = order)


def optimizer_main (map, subgroup = [], order = 2, cons_monzo_list = np.array ([]), stretch_monzo = np.array ([]), show = True):
def optimizer_main (map, subgroup = [], order = 2, weighter = "tenney", cons_monzo_list = np.array ([]), stretch_monzo = np.array ([]), show = True):
     if len (subgroup) == 0:
     if len (subgroup) == 0:
         subgroup = PRIME_LIST[:map.shape[1]]
         subgroup = PRIME_LIST[:map.shape[1]]
     jip = np.log2 (subgroup)*SCALAR
     jip = np.log2 (subgroup)*SCALAR
     map_w = weighted (map, subgroup)
     map_w = weighted (map, subgroup, type = weighter)
     jip_w = weighted (jip, subgroup)
     jip_w = weighted (jip, subgroup, type = weighter)
     if order == 2 and not cons_monzo_list.size: #te with no constraints, simply use lstsq for better performance
     if order == 2 and not cons_monzo_list.size: #te with no constraints, simply use lstsq for better performance
         res = linalg.lstsq (map_w.T, jip_w)
         res = linalg.lstsq (map_w.T, jip_w)
         gen = res[0]
         gen = res[0]
         print ("TE tuning without constraints, solved using lstsq. ")
         print ("L2 tuning without constraints, solved using lstsq. ")
     else:
     else:
         gen0 = [SCALAR]*map.shape[0] #initial guess
         gen0 = [SCALAR]*map.shape[0] #initial guess
         cons = {'type': 'eq', 'fun': lambda gen: (gen @ map_w - jip_w) @ cons_monzo_list} if cons_monzo_list.size else ()
         cons = {'type': 'eq', 'fun': lambda gen: (gen @ map - jip) @ cons_monzo_list} if cons_monzo_list.size else ()
         res = optimize.minimize (error, gen0, args = (map_w, jip_w, order), method = "SLSQP", constraints = cons)
         res = optimize.minimize (error, gen0, args = (map_w, jip_w, order), method = "SLSQP", constraints = cons)
         print (res.message)
         print (res.message)