Composing with automorphisms: the code

Quick follow-up on this post about composing with automorphisms in the ‘Cube Dance’ graph. I’m putting here the Python code I wrote to get the examples in the YouTube videos. As expected, I’m using Opycleid to get most of the job done.

Note: I’m using version 0.3.2 of Opycleid

 

First, we import the M_{\mathcal{U}\mathcal{P}\mathcal{L}} monoid, along with some classes we will use later.

from opycleid.musicmonoids import UPL_Monoid
from opycleid.categoryaction import CatObject,CatMorphism,CategoryActionFunctor

mg = UPL_Monoid()
_,X = mg.get_object()

The variable mg now contains an instance of the M_{\mathcal{U}\mathcal{P}\mathcal{L}} monoid, so we’ll know look for its automorphisms.

auts = mg.get_automorphisms()
print(len(auts))
## >>> 12

As expected, there are twelve of them. We take the first one in the list, and print the image of the generators.

aut = auts[0]
for m in ["L","P","U"]:
    print(m,"->",aut.get_image_morphism(m))
## >>> L -> L
## >>> P -> P
## >>> U -> LUL

Next, we need to define an automorphism of the functor S \colon M_{\mathcal{U}\mathcal{P}\mathcal{L}} \to \mathbf{Rel}. We already have an automorphism N, so we need to define a natural transformation \eta \colon S \to SN. From the last post, this is defined by an appropriate permutation of the augmented triads, and by a choice of an image for a representative in each hexatonic system. The rest of the images are determined by using the naturality condition on \eta for the invertible morphisms \mathcal{P} and \mathcal{L}.

eta = CatMorphism("eta",X,X)
d={"C_aug":["G_aug"],
   "G_aug":["D_aug"],
   "D_aug":["F_aug"],
   "F_aug":["C_aug"]}
for x,y in zip(["C_M","Eb_M","Fs_M","A_M"],
               ["B_m","Fs_m","A_m","C_m"]):
    for m in ["L","LP","P","PL","PLP","id_."]:
        p = mg.apply_operation(m,x)[0]
        f = aut.get_image_morphism(m)
        z = mg.apply_operation(f,y)
        d[p]=z
eta.set_mapping(d)

You can print the full mapping with eta.get_mapping(). Then we define the automorphism of the functor S, and we verify that it is a valid one (i.e. if the automorphism of M_{\mathcal{U}\mathcal{P}\mathcal{L}} is indeed a valid one, and if eta is really a natural transformation).

N = CategoryActionFunctor(mg,mg,aut,{".":eta})
print("VALIDATION :",N.is_valid())
## >>> VALIDATION : True

Now we need to define a poly-Klumpenhouwer network (PK-Net) that we will transform using

from opycleid.knetanalysis import PKNet

A = CatObject("A",["pX1"])
B = CatObject("B",["pY1"])
C = CatObject("C",["pZ1"])

f = CatMorphism("f",U,V)
f.set_mapping({"pX1":["pY1"]})

g = CatMorphism("g",V,W)
g.set_mapping({"pY1":["pZ1"]})

my_pknet = PKNet(mg)
my_pknet.set_edges([f,g])
my_pknet.set_mappings({"f":"U","g":"U"},
                  {"pX1":["D_M"],
                   "pY1":["D_aug"],
                   "pZ1":["G_m"]
                  }
                 )

print(my_pknet)
## >>> A -- U --> B
## >>> [['D_M']] -> [['D_aug']]
## >>> B -- U --> C
## >>> [['D_aug']] -> [['G_m']]

Everything is ready, we can apply our automorphism on this PK-Net to get the whole chord progression.

for i in range(12):
    print("==================")
    my_pknet = my_pknet.global_transform(N)
    print(my_pknet)

# ==================
# A -- LUL --> B
# [['Cs_m']] -> [['F_aug']]
# B -- LUL --> C
# [['F_aug']] -> [['D_M']]
#
# ==================
# A -- U --> B
# [['Gs_M']] -> [['C_aug']]
# B -- U --> C
# [['C_aug']] -> [['Cs_m']]
#
# ==================
# A -- LUL --> B
# [['Eb_m']] -> [['G_aug']]
# B -- LUL --> C
# [['G_aug']] -> [['Gs_M']]
#
# ==================
# A -- U --> B
# [['Fs_M']] -> [['D_aug']]
# B -- U --> C
# [['D_aug']] -> [['Eb_m']]
#
# ==================
# A -- LUL --> B
# [['A_m']] -> [['F_aug']]
# B -- LUL --> C
# [['F_aug']] -> [['Fs_M']]
#
# ==================
# A -- U --> B
# [['C_M']] -> [['C_aug']]
# B -- U --> C
# [['C_aug']] -> [['A_m']]
#
# ==================
# A -- LUL --> B
# [['B_m']] -> [['G_aug']]
# B -- LUL --> C
# [['G_aug']] -> [['C_M']]
#
# ==================
# A -- U --> B
# [['Bb_M']] -> [['D_aug']]
# B -- U --> C
# [['D_aug']] -> [['B_m']]
#
# ==================
# A -- LUL --> B
# [['F_m']] -> [['F_aug']]
# B -- LUL --> C
# [['F_aug']] -> [['Bb_M']]
#
# ==================
# A -- U --> B
# [['E_M']] -> [['C_aug']]
# B -- U --> C
# [['C_aug']] -> [['F_m']]
#
# ==================
# A -- LUL --> B
# [['G_m']] -> [['G_aug']]
# B -- LUL --> C
# [['G_aug']] -> [['E_M']]
#
# ==================
# A -- U --> B
# [['D_M']] -> [['D_aug']]
# B -- U --> C
# [['D_aug']] -> [['G_m']]

Or equivalently, since in Opycleid morphisms of functors to \mathbf{Rel} can be composed:

T=N
for i in range(12):
    print("==================")
    print(my_pknet.global_transform(T))
    T=T*N

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s