OPYCLEID updates: quantale-valued relations in transformational music analysis

Version 0.4.0 for Opycleid, the Python library for transformational music analysis is out ! You can download the source code from GitHub, or just install it with a simple ‘pip install opycleid’.

This version fixes and improves previous features, but more importantly I’ve added support for quantale-valued relations between sets, and categories thereof. I’ve alluded to this possibility in a previous post on binary relations and relational presheaves, so I’ve thought it would be nice to have a blog post explaining what it means and how it can be used in transformational music theory.

Previously, we have seen how we can use binary relations to connect musical elements, in particular in the case when we have one-to-many mappings. This is what happens for example when we look at the set of major and minor triads and we consider the binary relation that connects two triads if they have two pitch classes in common. In this case, a major triad, say C major, is connected to three other triads, namely C minor, A minor, and E minor.

In informal terms, quantales are mathematical objects which can be used to extend the idea of binary relations by allowing more than the two values of ‘connectedness’ 0 and 1. The formal definition of a quantale Q is the following: a join complete partial order Q with a monoid structure (Q,*) such that multiplication distributes over arbitrary joins, i.e., in which we have

x*(\bigvee\limits_{i \in I} y_i) = \bigvee\limits_{i \in I} x*y_i and (\bigvee\limits_{i \in I} y_i)*x = \bigvee\limits_{i \in I} y_i*x.

Let’s see some examples of quantales:

  • We have the boolean quantale Q=\{0,1\} in which the monoid multiplication is the logical AND, and the join is the logical OR. This is the quantale which underlies ordinary binary relations.
  • The Lawvere quantale is the set of real numbers including infinity, with reverse ordering, in which the join is given by min, and the monoid multiplication is given by the ordinary addition.
  • The multiplicative quantale is the interval [0,1] with normal ordering, in which the join is given by max, and the monoid multiplication is given by the ordinary multiplication of real numbers. It is isomorphic to the Lawvere quantale.
  • The interval quantale is the interval [0,1] with normal ordering, in which the join is given by max, and the monoid multiplication is given by min.
  • Any linear order can be a quantale: there exists a quantale isomorphism to a discrete subset of the interval quantale.

Now, for a given quantale Q we can form the category \mathbf{Rel}(Q) with finite sets as objects and Q-valued relations as morphisms, i.e., functions X \times Y \to Q, the composition of two morphisms \mathcal{R} \colon X \times Y \to Q and \mathcal{S} \colon Y \times Z \to Q being given by

(\mathcal{S} \circ \mathcal{R}) (x,z) = \bigvee\limits_{y \in Y} \mathcal{S}(y,z)*\mathcal{R}(x,y).

Let’s take an example to see how this works. Three sets are shown in the picture below, with two relations in \mathbf{Rel}(Q) (one between X and Y, the other one between Y and Z), where Q is the multiplicative quantale. The quantale values for each relation are given above the arrows. It helps to see the multiplicative quantale as giving some sort of cost value between elements, 1 representing no cost at all (or maximum connectedness), and 0 representing infinite cost (or zero connectness).

We want to determine the composite relation between X and Z. For that we examine the possible paths from X to Z for all possible elements of Y, and since we use the multiplicative quantale, we multiply the numbers along them. Thus we get one path from P to T with value 1.0*0.6=0.6, and another one with value 0.4*0.7=0.28. In informal terms, we multiply cost values to get the total cost for a given path. According to the formula above, we then collapse these two paths into a single one using the join operation, thus obtaining a path with value max(0.28,0.6)=0.6, which represents the relation in \mathbf{Rel}(Q) between X and Z. In informal terms again, among all possible paths we have kept the one with minimal cost value (or maximum connectedness).

Let’s now see an example in music theory, which will also serve to illustrate how we can use Opycleid. We will consider here the set of major, minor, and augmented triads, and we will consider first the binary relation \mathcal{D} that connects two triads if they have two pitch classes in common. Below is the graph of this binary relation.

If you followed this blog and the previous post, you’ll have noticed that this graph and the associated binary relations include the neo-Riemannian transformations P, R, and L (although now undifferentiated), along with elements of the famous ‘Cube Dance‘ graph.

We can define this in Opycleid and study the monoid it generates as shown below.


import numpy as np
from opycleid.categoryaction import CatObject, CatMorphism, CategoryAction

X = CatObject(".",["C_M","Cs_M","D_M","Eb_M","E_M","F_M","Fs_M","G_M","Gs_M","A_M","Bb_M","B_M","C_m","Cs_m","D_m","Eb_m","E_m","F_m","Fs_m","G_m","Gs_m","A_m","Bb_m","B_m","Ab_aug","F_aug","D_aug","B_aug"])
H=np.empty((28,28),dtype=bool)
for i in range(28):
    for j in range(28):
        H[i,j] = False
for i in range(12):
    # M-m
    H[12+np.mod(i,12),i]=True
    H[i,12+np.mod(i,12)]=True

    H[12+np.mod(i+4,12),i]=True
    H[i,12+np.mod(i+4,12)]=True

    H[12+np.mod(i+9,12),i]=True
    H[i,12+np.mod(i+9,12)]=True

    # M-aug
    H[24+np.mod(i,4),i]=True
    H[i,24+np.mod(i,4)]=True
    
    # m-aug
    H[24+np.mod(i+3,4),12+i]=True
    H[12+i,24+np.mod(i+3,4)]=True
    
d = CatMorphism("D",X,X,mapping=H)
mg = CategoryAction(objects=[X],generators=[d],generate=True)
print(len(mg.morphisms))
>> 6

We thus get a monoid of six elements generated by \mathcal{D} and subject to the relation \mathcal{D}^6=\mathcal{D}^5. We can use this monoid to get the possible operations between, say C major and D minor (i.e. the binary relations in the monoid that relate these two chords).

for m in mg.get_operation("C_M","D_m"):
    print(m)

>> DDD
>> DDDD
>> DDDDD

As we have seen previously, this encodes information about the possible paths from C major to D minor. For example, that the binary relation \mathcal{D}^3 relates C major and D minor indicates that we have a path of length 3 in the above graph: C major – A minor – F major – D minor.

As I mentionned above, the binary relation \mathcal{D} includes the neo-Riemannian transformations P and L, the connection between major and minor triads and augmented triads, and also the neo-Riemannian transformations R. In the first two cases, the remaining differing pitch class moves by a semitone, but in the case of the transformation R it moves by a whole tone. In analogy to what we discussed above, we may want to consider this kind of move as having a ‘higher cost’ or ‘diminished connectedness’ as opposed to the smooth voice-leading by semitones. So we define a linear order quantale Q with three elements, which we represent graphically as follows.

It has three values, 0, 1/2, and 1, and as we have seen above, the join is given by max, and the quantale monoid multiplication is given by min. In Opycleid, this is implemented as a class Lin3Q.

from opycleid.q_categoryaction import Lin3Q

a=Lin3Q(0.5)
b=Lin3Q(1.0)
c=Lin3Q(0.0)
## '+' is overriden to denote the quantale join
print(a+b)
>> 1.0
## '*' is overriden to denote the quantale monoid multiplication
print(a*b)
>> 0.5
print(b*c+a)
>> 0.5

Let’s now redefine our binary relation \mathcal{D} as a relation \mathcal{D}' in \mathbf{Rel}(Q) which differentiates between semitone and wholetone movements. Now, if two chords have two pitch classes in common and the third one moves by a semitone, \mathcal{D}' takes the value 1. If the third one moves by a whole tone, \mathcal{D}' takes the value 1/2. In all other cases, it takes the value 0 (absence of connection). Here is the graph of this relation, color-coded according to the above picture.

Beware ! Contrary to what I’ve presented in the previous posts, this does not represent two different binary relations, but a single quantale-valued relation where the quantale values are indicated by different colors.

Let’s now study with Opycleid the monoid it generates.

import numpy as np
from opycleid.categoryaction import CatObject
from opycleid.q_categoryaction import Lin3Q,QMorphism,CategoryQAction

X = CatObject(".",["C_M","Cs_M","D_M","Eb_M","E_M","F_M","Fs_M","G_M","Gs_M","A_M","Bb_M","B_M","C_m","Cs_m","D_m","Eb_m","E_m","F_m","Fs_m","G_m","Gs_m","A_m","Bb_m","B_m","Ab_aug","F_aug","D_aug","B_aug"])
H=np.empty((28,28),dtype=Lin3Q)
for i in range(28):
    for j in range(28):
        H[i,j] = Lin3Q.Zero()
for i in range(12):
    # M->m
    H[12+np.mod(i,12),i]=Lin3Q(1.0)
    H[i,12+np.mod(i,12)]=Lin3Q(1.0)

    H[12+np.mod(i+4,12),i]=Lin3Q(1.0)
    H[i,12+np.mod(i+4,12)]=Lin3Q(1.0)

    H[12+np.mod(i+9,12),i]=Lin3Q(0.5)
    H[i,12+np.mod(i+9,12)]=Lin3Q(0.5)

    H[24+np.mod(i,4),i]=Lin3Q(1.0)
    H[i,24+np.mod(i,4)]=Lin3Q(1.0)
    
    H[24+np.mod(i+3,4),12+i]=Lin3Q(1.0)
    H[12+i,24+np.mod(i+3,4)]=Lin3Q(1.0)
    
d = QMorphism("D'",X,X,qtype=Lin3Q,mapping=H)
mg = CategoryQAction(qtype=Lin3Q,objects=[X],generators=[d],generate=True)
print(len(mg.morphisms))
>> 7

Already we can see a difference: we now have a monoid of seven elements subject to the relation \mathcal{D}'^7=\mathcal{D}'^5. We can take our previous example with C major and D minor and examine what are the morphisms in this monoid which relate these two chords, and importantly what are the associated quantale values.

print("Morphism       | Value\n----------------------")
for m in mg.get_operation("C_M","D_m"):
    print(m.ljust(15)+"|",[v for k,v in mg.apply_operation(m,"C_M") if k=="D_m"])

>> Morphism       | Value
>> ----------------------
>> D'D'D'         | [0.5]
>> D'D'D'D'       | [0.5]
>> D'D'D'D'D'     | [1.0]
>> D'D'D'D'D'D'   | [0.5]

As before, this encodes information about the possible paths from C major to D minor, but with added information. Thus, the binary relation \mathcal{D}'^3 relates C major and D minor with quantale value 1/2, indicating that for all paths of length 3 relating these two chords, there will be at least one step in which we have movement of a pitch class by a whole tone (check it for C major – A minor – F major – D minor for example). This is the same information we get about paths of length 4 for \mathcal{D}'^4. But for \mathcal{D}'^5, why do we have a quantale value of 1 ?

There are many paths of length 5 from C major and D minor, and I’m showing two in the figure below.

The top path proceeds only by semitone movement: its quantale value is therefore 1. In the bottom path, we have two steps which proceed by whole tone movement, so its quantale value is the minimum value taken along this path, i.e. 1/2. But we collapse these two paths according to the quantale join, which is the max, and therefore keep only the value with maximum connectedness, in this case 1, hence the result found above. Thus, the fact that \mathcal{D}'^5 has value 1 between C major and D minor tells us: “you can go from this chord to that chord in five steps using only semitone movements. There are other possible paths, but there is one with maximum connectedness”. You will have noticed that it doesn’t say anything about one path in particular (you could have had C major – A flat augmented – D flat minor – A major – F augmented – D minor as well).

Thus quantale-valued relations provide us with information about the connectedness, or cost, of paths. In our example above, we have made the (subjective !) choice of considering that a whole tone movement has a lesser connectedness than a semitone movement, but I’m certain that other applications can be found in harmony, or even in rhythmic analysis. You could even define relational networks with quantale values !

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