Set Theory Library

I’ve been working on a large-scale software project that models many ideas from Musical Set Theory. This body of music theory has been shown to model an large segment of 20-century music and has had a profound influence on musical thinking in the last 50 years. Theorists and composers working in this field include Milton Babbitt, Robert Morris, David Lewin, John Rahn, Richard Hermann and Donald Martino. In addition to its value in analyzing and understanding the canon of 20th-century music, it has been proven to offer composers powerful new ways of organizing and expanding their musical ideas.

Using modern software engineering strategies and paradigms, I believe that the body of software I have been composing offers theorists and composers powerful and extensible means for modelling a large segment of the objects and operations of Musical Set theory. For convenience, I will refer to the entire library, or collection of classes, as the Musical Set Theory Library, abbreviated as MSTL. I think it best to jump in and look at some of the objects and classes (used here as the term in software engineering for a model of an abstract idea, such as a Row, as opposed to an instructional unit in an educational institution). I will provide only brief descriptions of the ideas from PC Set Theory, assuming the readers familiarity with the concepts or leaving them to discover them as desired using the additional reading resources provided.

Basic Elements of MSTL
PitchClassSet :: The PitchClassSet (PCSet) is a term defined in the literature as a class of pitch groups without regard to vertical or horizontal ordering or spacing. In mathematical terms, one could regard it as a Set, defined only by interval relationships within the 12-note chromatic scale. A common example would be the Major chord, where two instances, for example the C Major chord and D-flat Major chord, share no common notes, but consist of the same “sound” and are members of the same “class”. The PCSet extends this concept to any group of notes, such as the octatonic or pentatonic scale or the collection consisting of the notes D, A and E. Neither of these three collections is equivalent to the other, but subsets of each can be found in the other. A robust model of the PCSet will allow us to create instances of them and transpose, invert and analyze their relationship to other PCSets using a well-defined and rigorous interface.

PitchSet :: The PitchSet (PSet) is a more specific form of the PCSet. It consists of a set of pitches fixed in register or vertical space, but with no regard to horizontal or temporal ordering. A common definition and useful model would be a “closed-voicing, root position Major chord”, which retains its identity if transposed, but loses its identity if inverted in the classical sense of rotating the vertical ordering of the notes (root position, 1st inversion, etc), or if expanded to an open voicing. Using a well-defined interface, we can transpose, invert and perform other operations on them. In addition, we can inspect their nature as PCSets (see above). For example, it would be quite simple to determine of a PCSet was a Major chord regardless of its transposition or vertical distribution.

PitchClassSequence :: The PitchClassSequence  (PCSeq)is similar to the definition of PCSet; however, the concept of order is injected, such that an element of a PCSeq can be considered to come before of after another element in a PCSeq. In this class, we add operations on order such as R() (retrograde) and interpolation (injecting another PCSeq as a specific location into another PCSeq). Again, a well-designed interface will allow one to reduce a PCSeq into a PSet or PCSet.

PitchSequence :: The PitchSequence  (PSeq)is similar to the definition of PSet; however, the concept of order is injected, such that an element of a PSeq can be considered to come before of after another element in a PSeq. In this class, we add operations on order such as R() (retrograde) and interpolation (injecting another PSeq as a specific location into another PSeq). Again, a well-designed interface will allow one to create a PCSet or PSet from a PSeq using a single operation.

Row:: The Row (Row) is a specialized form of the PitchClassSequence . It has only a few additional properties. The contract of a 12-tone row is enforced. An attempt to create a Row with a length other than 12 or with a duplicated or omitted pc among the 12 pcs will throw an error and the row will not be created. In addition, a Row object cannot be modified after it is created. While, the Row object itself cannot be modified, all of the standard T,M,I,R operations will return a new Row object with those attributes.

CompositionMatrix:: The CompositionMatrix (CM) is an arrangement of (n x m) Pseq or PCSeq objects in horizontal or vertical space. This class offers many possibilities for extending MSTL to create larger compositional designs beyond the basic Sequence and Set types. CMs can be transposed, inverted, and reversed. There are two retrograde forms, one where the order of the component Sequences is preserved while the order of the CM columns is reversed, and one where the order of each Sequence cell is reversed. The content of the individual rows and columns can be any Sequence type. A canonical CM (by my own definition) is a CM where the row and/or columns create 12-note aggregates. The isCanonical() method allows callers to query this property for either rows, columns, or both.

Contour:: The Contour (Contour) is an ordered sequence of vertical (“y” dimension) in Pitch space ordered sequentially (“x” dimension), presumably in Time space. In a sense, this is an abstract description of a “melody”. While PitchSequence types map pitches into a flat, chromatic space, using Contours and Scales, we can map a melodic contour into any vertical pitch space, such as a Major scale, a Messiaen mode of limited transposition, or any customized set of pitches, into an abstract vertical and horizontal ordering.

Benefits of Robust Design
It is simple to create routines to perform the basic operations of Pitch Class Theory, such as transposition, inversion, retrograde, etc. in most any  modern programming language. Likewise, comparison and analysis algorithms, such as Normal Form and IC Vector, are mostly simple arithmetic operations. However, at a certain point, one might find a jumble of “spaghetti code”, where a program would need to be altered in several places to do something very basic. Worse yet, one could uncover a bug in an operation that would require an extensive rewrite of their program. Using this framework in conjunction with concise domain-specific languages, such as Groovy, it is possible to write short, expressive programs, or scripts, which can accomplish complex calculation in a very short space. Using a mix Object-oriented and Functional programming paradigms, much redundancy can be eliminated. Even if well-designed, composers can get frustrated quickly by viewing and interpreting textual output. Extensions of this library offer powerful methods of generating output to common notational formats such as LilyPond and MusicXML, which can be imported directly into many modern notation packages. I will even demonstrate how the library can be integrated into the Open-source Overtone live performance system.

Technical Implementation
The basic objects of PC Set Theory are implemented as classes using the Java programming language. Java is a powerful Object Oriented language with wide support in many fields of technology including mathematics, web applications, networking, science and graphical imaging. In addition, it is available for nearly every modern platform including Mac, Windows and Linux. Libraries such as MSTL are instantly portable across all platforms with no modification required. Using an Object-Oriented interface is essential for modelling objects and concepts of PC Set Theory. The weaknesses of a functional or procedural approach surface immediately when attempting to manipulate and extend Pitch Class Set objects. Without an object to contain the properties and operations, the user will very soon be bogged down in a tangle of function calls and conversion routines to perform the simplest of operations. To illustrate this point, we will create a new PSeq created from the first 5 elements of the retrograde of a transposed inversion of another set using two lines of code. The fragment includes the creation of the original set, so the actual transformation is done on a single line (the third line simply prints the result and could be combined on the same line, but separated for clarity). The original set is simply a permuted diatonic scale beginning on middle C: C D E A B F C’. One need not know the details of Java or Groovy to appreciate the simplicity of this approach.

Ex.1 (Groovy)

def mySeq = Pseq(“60 62 67 64 69 71 65 72”)
def newSet = mySeq .T(1).I().R().subSequence( 0, 4 )
println( newSet.toString() )

Output:
[0, 7, 1, 3]

As illustrated, operations can be chained together in a single unit. To illustrate further the power of this programming model, let’s calculate the Normal Form of the transformation above, again, using two lines of code.

Ex. 2

def mySeq = new Pseq(“60 62 67 64 69 71 65 72”)
def normalFormSet = PcSet( mySeq .T(1).I().R().subSequence( 0, 4 ).getMembers() ).getNormalForm()
println( normalFormSet .toString() );

Output:

[0, 1, 3, 7]

Here, we were able to create a Pitch Class Set from a Pitch Sequence in one line. These are quite different types of objects. The PitchClassSet type has no notion of order, whereas the PitchSequence type preserves pitch elements without reducing them to their mod 12 values.

In our last example, we will show two lines of code that prove that the all-interval tetrachord [0137] (I call it the Phrygian-Lydian Tetrachord) is equivalent (under T[n] or I) to a transposed inversion [3,4,7,9] of the other all-interval tetrachord [0146] under M[5].

Ex. 3

def allIntSet = new PitchClassSet( [0,1,3,7] )
def otherAllIntSet = new PitchClassSet( [3,4,7,9] )
println( “It is ${allIntSet.M(5).equivalent( otherAllIntSet )} that ${allIntSet} is equivalent to ${otherAllIntSet} under M[5]” )

Output:
true

Uneven Combinatorial Matrices

Up to this point, most of the MSTL operations were somewhat trivial, limited mostly to querying properties of a set or sequence, such as its normal form, etc. Here, we will explore some more complex operations which composers can employ in laying larger compositional designs. In 12-tone or aggregate-based music, composers are often interested in finding contrapuntal possibilities of a Row. Pioneering 12-tone composers, such as Schönberg, Berg, and Webern of the Second Viennese School, explored simple combinatorial patterns, such as hexachordal and trichordal combinations of rows such that each row and column formed a 12-note aggregate. Here is a simple example, using the row from Schönberg’s Violin Concerto, Op. 36:

<9 a 3 b 4 6 0 1 7 8 2 5>

Each hexachord is a 6-18 Set Class, which maps into its complement at T[7][M[11] (or simply T[7]I). As a result, this row can be combined with itself at that transformation.

T[0]P :<9 a 3 b 4 6>|<0 1 7 8 2 5>
T[7]IP:<2 1 8 0 7 5>|<b a 4 3 9 6>

Each row of the design, by its nature, is a 12-note aggregate. However, in this design, each column also forms an aggregate, creating another musical organizational unit. Schönberg employs this feature to create contrapuntal arrays of rows, offering the opportunity to increase the contrapuntal texture.

This, and many other combinations used by these composers, relied on even divisions of 12 to create their compositional designs (Composition Matrix or CM). Disregarding the trivial case where each row and column contains 1 pc, there are 4 possibilities for evenly-divided designs:

Rows Columns Cell
2 2 Hexachord
3 3 Tetrachord
4 4 Trichord
6 6 Dyad

 

However, these combinations form a only tiny fraction of the ways rows can be combined to form 12-note aggregates.

 

Of course, any row exhibits trivial hexachordal combinatoriality at RP:

<9 a 3 b 4 6>|<0 1 7 8 2 5>
<5 2 8 7 1 0>|<6 4 b 3 a 9>

Using Schönberg’s original row, I will show how MSTL can calculate an exhaustivel number of ways of combining 12-tone rows to create interesting compositional designs.

Shown below is a 3 x 3 design or rows, with each cell containing at least 1 pc:

T[9]P   : <9 a>             |<3 b 4 6 0>  |<1 7 8 2 5>
RT[4]MP : <0 3>             |<9 2 8 1 7 5>|<6 a b 4> 
T[8]IP  : <8 7 2 6 1 b 5 4> |<a>          |<9 3 0>

The row and column sizes are show in the table below;

2  5  5
2  6  4
8  1  3

In this arrangement, while each column and row contains 12 elements by its very design, there are no columns or rows with the same “shape”. This combination can be easily formed by taking the last pc from a Row and using it as the first pc of the next row and column using any transformation.

The library routine for generating these combinations is not limited to 3×3 row combinations. Listed below are some interesting 4×4 combinations:

<9 a 3>|<b 4 6>|<0 1 7>|<8 2 5>
<5 2 8>|<7 1 0>|<6 4 b>|<3 a 9>
<0 b 6>|<a 5 3>|<9 8 2>|<1 7 4>
<4 7 1>|<2 8 9>|<3 5 a>|<6 b 0>
<9 a 3>|<b 4 6>   |<0 1 7>   |<8 2 5>
<5 2 8>|<7 1 0>   |<6 4 b>   |<3 a 9>
<0 b 6>|<a 5 3 9> |<8 2>     |<1 7 4>
<4 7 1>|<2 8>     |<9 3 5 a> |<6 b 0>
<9 a 3>|<b 4 6>    |<0 1 7>       |<8 2 5>
<5 2 8>|<7 1 0>    |<6 4 b>       |<3 a 9>
<0 b 6>|<a 5 3 9 8>|<2>           |<1 7 4>
<4 7 1>|<2>        |<8 9 3 5 a>   |<6 b 0>

A close inspection will show an underlying property of these designs, which is that each is formed from two pairs of (trivially combinatorial) retrograde forms.

However, there are many arrangement exhibiting a wider variety of transformations:

<9 a 3>  |<b 4 6>      |<0 1 7>    |<8 2 5>
<b 2 8 1>|<7 0>        |<6 4 5>    |<9 a 3>
<0 5 6>  |<a>          |<b 9 3 8 2>|<7 1 4>
<4 7>    |<1 2 8 9 3 5>|<a>        |<6 b 0>
Empty CM cells

Up to this point, each cell in the CM contained at least one element. However, a vastly larger number of arrangements can be found if cells can contain zero elements. This would create a gap between the pitches in the horizontal dimension, most often expressed in the time domain. In addition to offering more combinations, this offers the possibility of more interesting contrapuntal and textural combinations. The number of empty cells are controllable by the user. This can be useful to eliminate quasi-trivial arrangements, such as:

<9 a 3 b 4 6 0 1 7 8 2>|<>                      |<5>                   
<>                     |<5>                     |<a b 3 4 2 8 1 7 0 6 9>
<5>                    |<8 2 3 9 a 4 6 b 7 0 1> |<>

In MSTL, rows can contain no more than one empty cell. The capability to search rows with more than on e empty cell may be added in future releases, but I have found that it extended exponentially the number of possibilities searched while not adding much value to the results. The routine was able to find 929 3-row combinations in about 10 seconds.

Information on how to use MSTL, along with full source-code, is available at https://bitbucket.org/paul_marquardt/set-theory