05.31.07

Reproducing the entire Pitch Class Set catalog with Python

Posted in music theory, python at 3:13 pm by bmccosar

Allen Forte’s classic work, The Structure of Atonal Music, featured a catalog of all the possible prime forms for pitch class sets. That is, even though one can write [0,4,7], [2,6,9], or even [2,5,9], these are all essentially the same set.

In “prime form”, these sets are all the same — [0,3,7]. You can use this prime form to regenerate any of the previous sets I’ve mentioned through operations such as transposition, inversion, or both. I’ll demonstrate this below using the Python module I wrote, pcset.py. From interactive mode:

>>> from pcset import PitchClassSet as Pcs
>>> a, b, c = Pcs([0,4,7]), Pcs([2,6,9]), Pcs([2,5,9])
>>> a.prime(), b.prime(), c.prime()
(None, None, None)
>>> a.toList(), b.toList(), c.toList()
([0, 3, 7], [0, 3, 7], [0, 3, 7])

As you can see, all reduce to the same prime form. Now let’s get them back from the prime form, [0,3,7]:

>>> p = Pcs([0,3,7])
>>> p.TnI(7)
>>> p.toList()
[7, 4, 0]
>>> p.sort()
>>> p.toList()
[0, 4, 7]

Set “a” can be regenerated from inversion, then transposition by 7. Of course the order is reversed, which we can solve with sort(). Set “b” is similar:

>>> p = Pcs([0,3,7])
>>> p.TnI(9)
>>> p.toList()
[9, 6, 2]
>>> p.sort()
>>> p.toList()
[2, 6, 9]

And set “c” is actually easier than the first two, a mere transposition by 2:

>>> p = Pcs([0,3,7])
>>> p.transpose(2)
>>> p.toList()
[2, 5, 9]

It’s been around 34 years since this book was published. There’s a lot of information about musical set theory on the Web. Oddly, though, the common thread I’ve found is that people complain about the above relation, which seems simple and obvious. Specifically, they complain that the “major chords” and “minor chords” both fall into the same pitch class. If you’ll notice, [0,4,7] is a C major chord, while [2,5,9] is a D minor chord:

>>> a, b, c = Pcs([0,4,7]), Pcs([2,6,9]), Pcs([2,5,9])
>>> a.toString(), b.toString(flats=False), c.toString()
('C E G', 'D F# A', 'D F A')

However, this makes perfect sense to me — not only for the reasons in Forte’s book, but also from practical experience in working with these chords. Major and minor chords have a similar feel. They are not the same, but they are at least first cousins. Certainly they don’t sound like [0,1,6]!

Look at the interval patterns in a major or minor chord — always a perfect fifth, a major third, and a minor third. The difference is in the stacking.

>>> a.ivec(), b.ivec(), c.ivec()
([0, 0, 1, 1, 1, 0], [0, 0, 1, 1, 1, 0], [0, 0, 1, 1, 1, 0])

And the other odd thing about prime forms is that it greatly simplifies thinking about pitch class sets. Consider this: with 12 notes, and a yes/no option for each note, that corresponds to 2^12, or 4096 possible permutations.

However, many of these permutations correspond to the same prime forms. Surprisingly, all 4096 permutations collapse to merely 224 prime forms.

Forte put a lot of work into writing his table. It must have taken quite some time.

However, I’ve just written a Python program that does it in 4.5 seconds ;-)

Now, this doesn’t go into the elaborate classification scheme or Z properties or any of that. This program simply finds the 224 distinct prime forms and sorts them by cardinality. For example, there’s only one empty set prime form; there’s also only one single element prime form, [0], because you can generate any other single note through transposition.

Below, I’ve given the output of the program. If you want to try and run it yourself, you need the other two modules, pcset.py and pcops.py. Just copy and paste the programs into the appropriately named file, save to the same directory as setcatalog.py, and you’re ready to go. The complete listing for setcatalog.py is given after the output.

Read the rest of this entry »

Pitch class set operations: pcops.py

Posted in music theory, python at 8:04 am by bmccosar

Previously, I wrote a Python module to implement Pitch Class Sets, pcset.py. I have now extended that module with another: pcops.py, a module of operations for pitch class sets. These are some of the functions:

  • copy(A) — returns a new pitch class set, a copy of A.
  • complement(A) — returns a new pitch class set, the complement of A.
  • Comparison functions: exact_equality, set_equality, same_normal, is_transposition, is_inverse, same_prime.
  • Relationship functions: is_complement, is_prime_complement, is_subset, is_prime_subset.
  • Similarity relations: Rp, Rp_prime, R0, R1, R2, Zpair.

Basically, the term “prime” in the relationship or similarity functions extends the meaning of the base function. For example:

>>> from pcset import PitchClassSet as Pcs
>>> from pcops import *
>>> majorscale = Pcs("C D E F G A B C")
>>> g7 = Pcs("G B D F")
>>> b7 = Pcs("B D# F# A")
>>> is_subset(majorscale,g7)
True
>>> is_subset(majorscale,b7)
False
>>> is_prime_subset(majorscale,b7)
True

The notes in the G7 chord are a strict subset of the C major scale; the notes in B7 are not.  However, the “prime” version of the function checks if any transposition, inversion, or combination of the two operations on B7 will make it a subset of the C major scale. This is useful in analyzing the relationships between sets in prime form.

Here are the listings for two new modules. In order to get this to work, you need version 1.1 of pcset.py (and, optionally, of the test suite, test_pcset.py). Below, I’ve included not only pcops.py, but its unit testing suite as well (test_pcops.py):

Read the rest of this entry »

05.28.07

Pitch class sets, version 1.1

Posted in music theory, python at 6:24 pm by bmccosar

I have been studying Pitch Class Sets a bit more. Two books have been very helpful:

Having read these books, I find I understand the concepts a bit more thoroughly. So, I ended up revising my Python module, pcset.py, as well as its unit testing framework, test_pcset.py.

The complete script for pcset.py 1.1 is given below. Notable changes from version 1.0:

  • card() — An obvious function I overlooked; returns the cardinality of the set (number of members). This will turn out to be very important for a later module I’m building.
  • Ixy(x,y) — Inversion around an arbitary axis: x maps to y, and y maps to x. The standard inversion is a rotation around the axis from 0 to 6 — F becomes G, and G becomes F. This could also be written as Ixy(’F',’G') or Ixy(5,7).

The complete test code (test_pcset.py 1.1) is also given below; the new 1.1 functions are tested, and the code was refactored in the Empty Operations Test portion using setUp().

All the operations defined in the Pitch Class Set are unary, affecting only the pitch class itself. I am in the process of designing a new, separate module which will implement binary relations and functions (operations on two sets at once).

As a sidenote, if there are any expert Python programmers out there: I think it’d be more convenient if I could load my scripts somewhere else, as distinct files, instead of pasting them here. Sadly, being a musician, I’m aware of many facilities for posting audio — even for posting documents and images — but none for posting arbitrary code with the freedom I’m accustomed to. If you have any advice for me, please leave a comment.

Read the rest of this entry »

05.26.07

Today’s ordeal.

Posted in dandelife, family at 3:53 pm by bmccosar

Things aren’t well.  I’ve posted the full story on my Dandelife blog.  Basically, my wife is hit by severe allergic attacks for no reason we can discern, so we spent most of the day in the emergency room.

05.25.07

Musical Set Theory: exploration using pcset.py

Posted in music theory, python at 2:29 pm by bmccosar

This week, I completed my first version of the Pitch Class Set module I’ve been writing in Python, pcset.py. I can already see room for improvement. But first, let me go into a few resources I’ve been using (for those of you who want to explore further).

It was after I started reading Allen Forte’s book that I really began to understand the concepts I’d implemented. Further, his writing gave me guidance for some future directions. As far as my pcset.py module goes, I can see the following areas for improvement:

  • My definition of “left packing” is not exactly the same as his; I use binary coding, he uses a distance based coding that leaps from the farthest digit at highest priority to the closest digit at next priority. I’m not sure, but my intuition is that this doesn’t matter. I will have to research it further.
  • I’ve come to discover the significance of the interval class vector, and the relation of sets and subsets. There is room for new functions such as subset testing, Z testing, etc.
  • Because of my background in chemistry, I can see the relation of pitch class sets to point groups. In my world, the chromatic scale is an object with D12h symmetry; the operation Forte describes as “inversion” is actually an in-plane C2 rotation along an axis from tone 0 to tone 6; the point group “inversion” operation, i, is trivial in musical set theory — merely a C2 rotation around the z axis, or a six unit transposition. These are much easier to show graphically than describe in text, so I may be heading toward my first GUI in version 2.

At any rate, just playing around with pcset.py in the Python interactive mode can be worthwhile. If you’re interested, I’ve cut and pasted a few demos below. These are from an interactive session, and show a few cool discoveries and principles from the theory. (Just click the link below to see them). Read the rest of this entry »

05.23.07

Pitch class sets, version 1.0: part 2, the module.

Posted in music theory, python at 5:09 pm by bmccosar

Version 1.0 of pcset.py implements Pitch Class Sets, one of the key concepts of Musical Set Theory. I’ve already published the unit testing framework; here’s the actual module itself.

I’ve written the following methods. You define Pitch Class Sets by either a string (”C E G B”) or a list ([0,1,6]). Once this is done, you can access the following methods:

  • Obvious functions: toString(), toList(), and sort().
  • invert() — Inverts the set.
  • transpose(n) — Transposes the notes by n; positive values up, negative down.
  • TnI(n) — For some reason, this seems to be notated backwards in the literature. It’s not what you’d think from left-to-right reading; it’s actually first, an inversion, and second, a transposition by n.
  • zerobase() — Transposes the set so the first note is zero.
  • normalize() — Puts the set in “normal form.”
  • prime() — Puts the set in “prime form.”
  • ivec() — Returns the “Interval Class Vector” for the set.
  • com() — Returns a list of values n for which TnI(n) creates a new combination of the existing notes. In other words, if com(yourset) returns [4], then you can create a new permutation of your set by applying the operation TnI(4) — the notes will change position in the set, but they will be the same notes as before.

OK, enough of that. If you’re interested, copy the module, try it out yourself, and let me know how things went. I’ve put the whole listing here, after the conveniently placed “more” tag:

Read the rest of this entry »

Pitch class sets, version 1.0: part 1, the test suite.

Posted in music theory, python at 4:53 pm by bmccosar

I have finished coding the Pitch Class Sets module which I prototyped earlier.  By and large I have based my algorithms and tests on Jay Tomlin’s Musical Set Theory page.

The most important thing I’ve learned, strangely, is the importance of unit testing in the software design process.  Before, it’s use was obscure to me; now that I’ve used it, I see how it works and what the big deal is.  So, here, in this first article, I’m posting the unit test code, test_pcset.py.

I think that the importance of unit testing is that it makes you brave.  A couple of times, I was coding rapidly, and my code worked, but was crappy and patched together.  Unit testing helped in the following ways:

  • When I discovered a bug, I wrote a test to make sure I didn’t reintroduce the bug again.
  • If I had a cumbersome algorithm or interface, it soon became obvious, as writing the test code was aggravating.
  • When I went back and “refactored” the code (erased the crap and replaced it with a better planned implementation, having learned from my experience), unit testing assured me I was getting the same sort of behavior I’d had before I “fixed” the code.
  • At the same time, it allowed me to let the code go when I was finished.  Instead of being a perfectionist and rewriting forever, I felt free to move on once the tests passed.

Also, my respect for the Python language has only increased.  This is undoubtedly the fastest I have ever launched and completed any project, even one so obscure as this.  A few times, it seemed like I was reading English off of Tomlin’s web page and translating it directly to Python in the other window.  That’s never happened before.  I’ve always had to fight the battle of syntax and obscure functions.  Well, no more.

Here’s the complete listing for test_pcset.py, hidden away safely behind a “more” tag.  If you have a look at the unit tests, they also tell you how to use the module itself (which I’m publishing next).

Read the rest of this entry »

05.22.07

Mersenne primes: the final word

Posted in python at 5:02 pm by bmccosar

Before I leave the subject of Mersenne primes, I’m going to look at the last amazing result.  Last night, just to see if it would work, I ran the fifth version of mersenne.py and set the exponential limit to 12,000.

Seven hours and 31 minutes later, it had found the first 23 Mersenne primes — ending with 2^11213 - 1, a 3,376 digit monster.  All this from a simple 65-line Python script.  No additional modules, no crazy Makefile chains, no Autoconf — a program that uses only standard libraries and should run anywhere there’s a Python interpreter.

For the record, here’s the output.  It’s unbelievably long, so I’ve concealed it from view on the main page using the “more” tag.  Click the following link if you want to look at some really, really, really long numbers.

Read the rest of this entry »

05.21.07

Mersenne primes (#5): OMG

Posted in python at 7:09 pm by bmccosar

Now we come to the Python program that amazed me.

The problem with version 4 was that my choice of setting the search limit via a floating point value choked the program prematurely — Python long integers, it turns out, are as technically beyond Python floats as a spaceship is beyond a potato cannon.

I changed the code so that the limit is not the actual Mersenne prime value, but the exponent of the Mersenne function — in other words, for Mn = 2^n - 1, I’m limiting n, not Mn.

Here’s the revised code for mersenne5.py (in “more” tag hyperspace, of course):

Read the rest of this entry »

Mersenne primes (#4): the Lucas-Lehmer test

Posted in python at 6:31 pm by bmccosar

In my previous article, I discovered the traditional brute force method of gnawing through a list of prime factors wasn’t going to make it much farther than the 9th Mersenne prime. Going any farther beyond the region of 10^20 would seem impossible with this simple algorithm; I needed a better one.

Version 4 of this mersenne.py takes advantage of a unique test that’s only available for this specific type of prime number — the Lucas-Lehmer test. The results were nothing short of incredible. Here’s the code, with a brand new method. Since it’s sort of long, I’ve hidden it behind ye olde “more” tag:

Read the rest of this entry »

« Older entries