*John Demain, music director of the Madison Symphony Orchestra, conducts a dress rehearsal.*

A symphony orchestra is fundamentally an artistic endeavor, whose existence is sustained by ticket sales but whose ultimate goals are musical and educational. As 501(c)3 nonprofit organizations, these orchestras are not technically beholden to maximize profits or shareholder returns. However, these organizations do require income to fund operations, and thus cannot entirely neglect the need to drive ticket sales via appealing music programming and appropriately control costs. Overall, the orchestra and its musical direction leadership will wish to put on programs that are highly enjoyable to audiences and interesting for the musicians to play, subject to their financial constraints.

For the basis of our problem and model, we will use the Madison Symphony Orchestra (MSO), a relatively resource-constrained regional orchestra that nevertheless has the capability to perform large-scale, demanding pieces. The MSO puts on six performance programs per year, and must devote considerable attention to driving ticket sales, in addition to its artistic mission.

The goal of our project is to choose three programs’ worth of classical music, subject to cost constraints, that best achieve a mix of artistic objectives. Our problem is an IP (multiple-knapsack incorporating regularization and tradeoffs). Our dataset is a list of 47 classical music pieces, evaluated by the authors according to a suite of parameters chosen to best parameterize their musical and financial appeal.

Several of the foundational concepts for this model can be best explained via musical examples. A few links to carefully-chosen YouTube videos of different classical pieces have been included in the text below. Each link points to a particular video timestamp; clicking on each and listening for about ten seconds will give you a good example of what we're talking about in that section.

Listening to the linked music is not required to understand the report. However, we hope our readers are able to experience some of the music, in order to better relate to our decision framework and appreciate the outputs of the model!

The choice of optimal programming is inherently a subjective one. Orchestra music directors spend their entire careers cultivating experience with a wide variety of periods, composers, and pieces. They must also balance their personal preferences with audience wishes, musicians’ needs, and cost restrictions. One of the most vital tasks in creating a useful model of this problem was building a robust framework to translate qualitative knowledge about musical programming into quantifiable characteristics and relationships among pieces that could be represented mathematically.

Our framework is broken into financial and artistic parameters. The qualitative intuition and mathematical representation of each individual parameter are developed below in some detail, so the reader can first fully understand the quantities to be optimized.

Hardcore symphony-goers are likely to do their own research by listening ahead of time to pieces which will be performed in the future. However, most audience members have a more casual interest in the symphony, and will be most strongly attracted by the prospect of hearing at least one piece or composer they already know. Thus, more famous pieces and composers help boost ticket sales. However, non-famous pieces have other merits, and can be put on in combination with well-known pieces in order to reap both sets of benefits. (For an example, see the notes for this recent MSO program: two pieces by the famous composer Wolfgang Amadeus Mozart are paired with a lesser-known piece by a relatively obscure composer.)

Many pieces make use of a relatively standard group of instrumentalists, and the musicians employed full-time by the symphony are sufficient to perform most of the orchestra repertoire. However, some pieces offer major solo roles of one or more instruments, vocalists, or full choirs, in addition to the typical instrumentation. Orchestras will typically bring in external soloists to fill these roles. Hiring soloists or choirs imposes a cost, but pieces featuring additional musical forces may be very exciting to listen to or interesting to perform. For an extreme example, compare this photo of the choral and orchestral personnel for a performance of Gustav Mahler's extravagant *Symphony of a Thousand*:

versus the normal instrumental personnel of the MSO:

Some pieces are easier for audiences to enjoy and understand than others. Most orchestras prioritize bringing musical fulfilment to the greatest possible number of listeners, rather than catering only to the most musically-educated patrons. At the greatest extremes, Percy Grainger's *Gum-Suckers' March* is very enjoyable even for newcomers to classical music, whereas Johan J. Agrell's harpsichord sonatas are very challenging to appreciate.

Artistic merit is the most subjective of the four numeric parameters, and serves as an indicator of the following characteristics:

The piece uses only a portion of the orchestra's normal complement of musicians (low score)

The piece would be educational to audiences about an underrepresented time period, instrument, or compositional technique (high schore)

Artistic merit conveys ways in which pieces can provide value aside from being strictly crowd-pleasing. For example, Anton Webern’s Five Pieces for Orchestra is not necessarily immediately appealing to the ear, but music in this style is not frequently performed by orchestras and would provide audiences with an educational experience.

Classical pieces can be categorized by their thematic elements. Orchestras frequently try to schedule pieces together in programs that explore similar themes in different ways, to create interesting comparisons and contrasts for audiences, and provide a somewhat coherent “narrative” for the performance. However, excessive similarity between pieces is also undesirable and can lead to a monotone listening experience.

Time period, national origin, pictorial subject (e.g. "folksong", "animals", "dance"), and featured soloist(s) were the broad thematic categories included. Each of these categories contains a few subtypes, for a total of 21 different thematic elements.

An example of a compelling pairing might be:

*A Sea Symphony*, by Ralph Vaughan Williams*Interludes from Peter Grimes*, by Benjamin Britten

These two very different depictions of the sea by British composers from different time periods provide an interesting contrast of ideas.

An example of an uncoordinated pairing might be:

*Israel in Egypt*, by Georg Frideric Handel*Rhapsody in Blue*, by George Gershwin

The combination of a restrained Classical-period retelling of the Israelites' biblical escape from Egypt with a wild Modern-period jazz odyssey isn't especially artistically compelling.

An example of an overcoordinated pairing might be:

*Violin Concerto in G minor*, by J. S. Bach*Violin Concerto in A minor*, by J. S. Bach

Both pieces are Bach violin concertos in minor keys in the polyphonic Baroque style, and even to the ears of the authors they are almost indistinguishable. Choosing both to appear in a single program instead of picking one doesn't contribute anything new to its artistic appeal, and can be majorly offputting for audience members who don't enjoy music of this style.

Within each program, pieces should be diverse in pace. A program composed entirely of slow pieces will put the audience to sleep, but a program of only fast pieces rapidly becomes exhausting to the ear.

With the above parameters in mind, the authors assembled a list of 47 classical music pieces from which the model would be able to select. The authors assigned parameter scores and thematic element binary flags based on their subjective experiences. An example entry from the datafile (with the set of thematic elements truncated) reads:

Title | Composer | Duration | Piece recog. | Composer recog. | Accessibility | Artistic merit | Classical | Sacred | English | Folksong |
---|---|---|---|---|---|---|---|---|---|---|

The Creation | Joseph Haydn | 108 | 5 | 5 | 5 | 8 | 1 | 1 | 1 | 0 |

Our assumptions for the following global parameters were based on examination of season schedules for the MSO, the Boston Symphony Orchestra, and the New York Philharmonic, as well as personal experience.

Parameter | Name | Value |
---|---|---|

Number of programs in the season | $\#_s$ | 3 |

Minimum program duration | $MinDuration$ | 80 mins |

Maximum program duration | $MaxDuration$ | 120 mins |

Minimum number of pieces per program | $MinPieces$ | 1 |

Maximum number of pieces per program | $MaxPieces$ | 5 |

Choir cost | $Cost[1]$ | 4 SEs* |

Woodwind soloist cost | $Cost[2]$ | 1 SE |

Brass soloist cost | $Cost[3]$ | 1 SE |

Keyboard soloist cost | $Cost[4]$ | 1 SE |

Strings soloist cost | $Cost[5]$ | 1 SE |

Vocal soloist cost | $Cost[6]$ | 1 SE |

Total season cost cam | $SeasonCostCap$ |

* soloist equivalents

For a dataset containing $p$ pieces and a season comprising $s$ programs, our decision variable is:

$X[\# _i,\# _j]$ $\in \{ 0,1\}, i \in s, j \in p$: Binary decision variable representing whether piece $j$ was selected for program $i$

We also have a helper variable that assists with enforcing the logical constraints on the use of soloists, considering a list of $a$ soloist types:

$Soloist_i[\#_i,\#_j] \in \{ 0,1\}, i \in a, j \in p$

Several box constraints enforce limitations on reasonable programming selections. These were developed to reflect typical programming practices as observed in past MSO, Boston Symphony Orchestra, and New York Philharmonic season schedules. Cost was measured in terms of “soloist-equivalents” (SEs); each season could cost no more than 4*k SEs, with k being the number of programs in the season.

$SoloCost_s \le SeasonCostCap$

$\sum_{p=1}^{\#_p} X[s,p] \le 1 \quad s\in \{ 0,1,.. \#_s\}$

$\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"] \le MaxDuration \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"] \ge MinDuration \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p] \ge MinPieces \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p] \le MaxPieces \quad p\in \{ 0,1,.. \#_p\}$

The objective function has the following form:

$r[1]\cdot PieceRec_s + r[2]\cdot CompRec_s + r[3]\cdot Access_s + r[4]\cdot Merit_s + r[5]\cdot ThemeSim_s + r[6]\cdot Temper_s + r[7]\cdot SoloCost_s + r[8]\cdot ThemeOverlap_s$

It is composed of the following components.

The first four terms of the objective function seek to maximize the sum of the numerical parameters (piece recognizability, composer recognizability, accessibility, and artistic merit). These terms are weighted by piece duration. If this weighting is removed, the model will choose as many short pieces as it can fit into each program, to maximize the number of scores added to the total. Weighting by piece length mitigates this unhelpful incentive.

$PieceRec_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"PieceRec"]$

$CompRec_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"CompRec"]$

$Access_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"Access"]$

$Merit_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"Merit"]$

There are two objective function terms working in opposition to achieve this goal: a positively-weighted 2-norm of each program’s thematic cohesiveness score, and a negatively-weighted sum of themes present across the season.

The term maximizing the 2-norm of thematic cohesiveness has the form:

$ThemeSim_s=\sum_{p=1}^{\#_p} \sum_{t=1}^{\#_t} (\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,t])^2$

It strongly incentivizes choices which produce many common themes within each program.

The term maximizing the negative sum of the total number of themes present during the season has the form:

$ThemeOverlap_s=\sum_{p=1}^{\#_p} \sum_{t=1}^{\#_t} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,t]$

This term tends to sparsify the collection of themes chosen for the season.

Taken together and with their weights carefully balanced against one another, the net effect of these terms is to incentivize relatively strong but not overwhelming sets of shared themes, as well as thematic diversity between programs. These are also weighted by duration to avoid the same over-incentivization of short pieces mentioned above.

This term sums the overall cost incurred throughout the season. It is calculated in response to the number of soloists demanded for each program. Pieces within the same program can share soloists, but soloists of the same type must be re-hired if the orchestra wishes to use them in subsequent programs. Cost is not weighted by duration, because soloist-sharing between pieces avoids the accidental incentive for maximizing number of short pieces.

To determine number of soloists required:

$Soloist_i[a,p]\le \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,SoloistType_a]\quad a\in \{ 0,1,.. \#_a\},\ p\in \{ 0,1,.. \#_p\}$

$Soloist_i[a,p]*M\ge \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,SoloistType_a]\quad a\in \{ 0,1,.. \#_a\},\ p\in \{ 0,1,.. \#_p\}$

Objective value term:

$SoloCost_s = \sum_{p=1}^{\#_p} \sum_{a=1}^{\#_a} Soloist_i[a,p]\cdot Cost[a]$

Within each program, each piece’s temperament score is summed. Programs’ combined temperament scores are subjected to a 1-norm, in order to incentivize balance (uptempo pieces with +1 temperament scores can be balanced by downtempo pieces with -1 temperament scores). This term is again weighted by duration.

$Temper_s\ge\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Temperament"]\cdot data[s,"Duration"]\cdot data[s,t]$

-$Temper_s\ge -\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Temperament"]\cdot data[s,"Duration"]\cdot data[s,t]$

$r[1]\cdot PieceRec_s + r[2]\cdot CompRec_s + r[3]\cdot Access_s + r[4]\cdot Merit_s + r[5]\cdot ThemeSim_s + r[6]\cdot Temper_s + r[7]\cdot SoloCost_s + r[8]\cdot ThemeOverlap_s$

$PieceRec_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"PieceRec"]$

$CompRec_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"CompRec"]$

$Access_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"Access"]$

$Merit_s=\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,"Merit"]$

$ThemeSim_s=\sum_{p=1}^{\#_p} \sum_{t=1}^{\#_t} (\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,t])^2$

$SoloCost_s = \sum_{p=1}^{\#_p} \sum_{a=1}^{\#_a} Soloist_i[a,p]\cdot Cost[a]$

$ThemeOverlap_s=\sum_{p=1}^{\#_p} \sum_{t=1}^{\#_t} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"]\cdot data[s,t]$

$X[\# _s,\# _p]$ $\in \{ 0,1\}$

$Soloist_i[\#_a,\#_p] \in \{ 0,1\}$

$Temper_s\ge\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Temperment"]\cdot data[s,"Duration"]\cdot data[s,t]$

-$Temper_s\ge -\sum_{p=1}^{\#_p} \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Temperment"]\cdot data[s,"Duration"]\cdot data[s,t]$

$Soloist_i[a,p]\le \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,SoloistType_a]\quad a\in \{ 0,1,.. \#_a\},\ p\in \{ 0,1,.. \#_p\}$

$Soloist_i[a,p]*M\ge \sum_{s=1}^{\#_s} X[s,p]\cdot data[s,SoloistType_a]\quad a\in \{ 0,1,.. \#_a\},\ p\in \{ 0,1,.. \#_p\}$

$SoloCost_s \le SeasonCostCap$

$\sum_{p=1}^{\#_p} X[s,p] \le 1 \quad s\in \{ 0,1,.. \#_s\}$

$\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"] \le MaxDuration \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p]\cdot data[s,"Duration"] \ge MinDuration \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p] \ge MinPieces \quad p\in \{ 0,1,.. \#_p\}$

$\sum_{s=1}^{\#_s} X[s,p] \le MaxPieces \quad p\in \{ 0,1,.. \#_p\}$

$\#_a = Count of Artist Types$

$\#_p = Number of Programs in a Season$

$\#_s = Number of Songs in Dataset$

$Cost[a] = Cost of Type a Artist \quad a\in \{ 0,1,.. \#_a\}$

$r[n] = Regularizer for Constraint \quad n\in \{ 0,1,.. \#_c\}$

$SeasonCostCap = Cost Limit to Soloists Over the Season$

$MaxDuration = Maximum Duration of a Program$

$MinDuration = Minimum Duration of a Program$

$MaxPieces = M = Maximum Number of Pieces in a Program$

$MinPieces = Minimum Number of Pieces in a Program$

Algorithmically generating recommendations that are “optimal” according to subjective human preferences is challenging. Fundamentally, the outputs of this model must pass the “sniff test.” A human with some amount of musical background should be able to examine the music choices and groupings and find them sensible. However, overzealous shepherding of the model via parameter choices would effectively set the outcome before the model is even run. Thus, it was important to discover a primary set of trade-off weights that produce interesting results, and then systematically vary those weights to discover more about the value ranges for those weights that produce sensical or nonsensical results.

To speed up the process of identifying unsuitable model results, a handful of *diagnostic pieces* were added to the dataset. These pieces have a spectrum of unfavorable characteristics that should render them unfit for performance under most circumstances. Their appearance in the model's results is a signal that the model may need to be recalibrated, or that the chosen tradeoff-weight set represents highly unusual circumstances. The diagnostic pieces are as follows:

Title | Composer | Concept | Problem indicated |
---|---|---|---|

Toccata and Fugue in D minor |
J. S. Bach | This is a work for solo organ. Despite being famous and enjoyable, it is an unsuitable choice for a full orchestra. |
Artistic merit may be underweighted |

Symphony No. 8 in E flat Major (Symphony of a Thousand) |
Gustav Mahler | An extremely exciting work that requires immense and costly resources to perform. |
Cost may be underweighted |

Symphony No. 5 in C minor |
Ludwig von Beethoven | One of the most famous classical pieces of all time; intentionally assigned no thematic elements for diagnostic purposes |
Thematic cohesiveness may be underweighted |

There are no diagnostic pieces to flag insufficient recognizability of pieces or composers. Our data list is biased strongly towards pieces and composers with which the authors were already familiar, implying an overrepresentation of well-known music.

Selecting a way to balance objectives is a not a straightforward task. Two options were reviewed to create effective balance. The first option proposed was objective regularization. Objective regularization has the strength of being linear and low-complexity, but has the disadvantage of needing linear inputs to have constant regularizers that have the same balancing effect on different samples.

Another approach presented by Bonnin and Dietmar creates soft constraints for playlist generation. Bonnin and Dietmar stated that this approach works by “iteratively enhancing a randomly chosen playlist through a local search procedure. The quality and suitability of the resulting playlist can be assessed by counting the number of satisfied constraints.” [1] This approach could be very useful because it sets a standard for quality and can generate more possible programs from alternative starting conditions. These different results could then be looked through by a human programmer offering great use for this optimization model. On the other hand, the soft constraints require an additional binary variable and two constraints or each soft constraint, which could make the IP run more slowly.

The regularization approach was tried first. Its slow execution speed indicated that the Bonnin-Dietmar soft constraint approach would be even more computationally intractable barring significant time investment into model relaxations and optimizations. Therefore, we proceeded instead with regularization.

Through experimentation with the code below, we arrived at the following set of tradeoff parameters as producing reasonable results:

$r[n] = Regularizer for Constraint = \left[0.1, 0.1, 0.1, 0.1, 0.0025, -10, -16, -0.15 \right]$

This vector served as a starting point for further sensitivity analysis.

In [30]:

```
### LOAD DATA
using NamedArrays
# Load data from the csv file
rawdata = readcsv("Music List-Final6.csv")
# Data type breakdown
headers = 2 # String-type header entries (piece title and composer)
num_scored_items = 4 # Number of data categories with numeric scores
num_themes = 21 # Number of thematic categories
num_soloists = 6 # Number of soloist types (which also count as themes; included in 23 in previous line)
# Load data into NamedArray `piecedata`
(rcount,ccount) = size(rawdata) # Total size of data block
parameters = String.(rawdata[1,1+headers:ccount]) # Pull parameter names from file
piecenames = String.(rawdata[2:rcount,1]) # Pull piece names from file
piecedata = NamedArray{Int}(rawdata[2:rcount,1+headers:ccount]) # Convert data into NamedArray
setnames!(piecedata,parameters,2) # Set column titles as parameters
setnames!(piecedata,piecenames,1) # Set row titles as piece names
setdimnames!(piecedata,[:Pieces,:Parameters]) # Finalize `piecedata` NamedArray
# Assign lists containing related parameter types
scored_items = parameters[2:5]
themes = parameters[6:27] # 1:26 are themes; 27:29 are temperaments
psoloists = parameters[21:26] # Theme flags that indicate the need for soloists of various types
# Pull out other useful constants from the data block size
n = length(piecenames) # number of pieces in the dataset
soloist_types = length(psoloists); # number of soloist types
```

In [31]:

```
### PARAMETERS
k = 3 # number of programs
minduration = 80 # minimum program duration, in minutes
maxduration = 120 # maximum program duration, in minutes
maxpieces = 5 # maximum number of pieces per program
minpieces = 1 # maximum number of pieces per program
season_cost_cap = k*4 # season budget, in units of [# of soloists]
soloist_type_costs = [4; 1; 1; 1; 1; 1];# costs of each soloist types; first entry (chorus) and last entry (vocalist) are more expensive
```

Out[31]:

In [32]:

```
### SOLVER
using JuMP, Gurobi
m = Model(solver = GurobiSolver(OutputFlag=0))
### VARIABLE DECLARATION
@variable(m, x[1:n,1:k], Bin) # x[i,j] = 1 IFF piece i is used in program j
@variable(m, temperament[1:k]) # For enforcing 1-norm on temperament diversity
@variable(m, norm_2_themes[1:k] >= 0) # thematic cohesiveness score
@variable(m, norm1_temperament[1:k] >= 0) # tempo diversity score
@variable(m, is_soloist[1:soloist_types, 1:k], Bin) # is_soloist[i,j] = 1 IFF a soloist of type i is used in program j
@variable(m, soloist_cost[1:k] >= 0) # cost per program
@variable(m, themes_chosen[1:k, 1:num_themes] >= 0) # matrix storing all themes found in pieces chosen for each program
#-------------------------------------------------------------------------------------------------------------
### CONSTRAINTS
## Box constraints
@constraint(m, utilized[i in 1:n], sum(x[i,:]) <= 1) # Pieces may be used at most once during the season
@constraint(m, maxdur[i in 1:k], sum(x[:,i].*piecedata[:,"Duration (min)"]) <= maxduration) # show duration is <= max
@constraint(m, mindur[i in 1:k], sum(x[:,i].*piecedata[:,"Duration (min)"]) >= minduration) # show duration is >= min
@constraint(m, maxnum[i in 1:k], sum(x[:,i]) <= maxpieces) # Cap on number of pieces per performance
@constraint(m, minnum[i in 1:k], sum(x[:,i]) >= minpieces) # Floor on number of pieces per performance
@constraint(m, sum(soloist_cost) <= season_cost_cap) # Maximum total expense for the season
## Track the distribution of thematic elements possessed by pieces chosen for each program
for i in 1:k
for j=1:num_themes
@constraint(m,themes_chosen[i,j] .== ((x[1:n,i].*piecedata[1:n,"Duration (min)"])'*piecedata[1:n,themes[j]]))
end
end
## Thematic Cohesiveness
# Each program's music should share enough themes that grouping the pieces together makes artistic sense, but
# programs shouldn't be excessively thematically homogeneous
# Applying 2-norm to number of shared themes among pieces in each program
for z in 1:k
@constraint(m, norm_2_themes[z]==
sum(
sum(x[i,z]*piecedata[i,themes[j]]*piecedata[i,"Duration (min)"] for i in 1:n)^2 # i represents song number. Sum count of aligning categories
for j in 1:(length(themes)-3)) # sum the square of each trait's count. This emphasizes theme
)
end
## Piece Temperament Diversity
# Want a mix of upbeat and downbeat pieces within each program
# Upbeat: +1 to temperament
# Downbeat: -1 to temperament
# Mixed: +0 to temperament
# Applying 1-norm to overall program temperament score (sum of individual piece temperaments within a program)
for z in 1:k
@constraint(m, sum(x[i,z]*piecedata[i,27]*piecedata[i,"Duration (min)"] for i in 1:n) <= temperament[z])
@constraint(m, -temperament[z] <= sum(x[i,z]*piecedata[i,27]*piecedata[i,"Duration (min)"] for i in 1:n))
end
## Cost
# If a soloist is required, then the orchestra must pay to bring one in
# Soloists can be shared among pieces within a program, but not among multiple programs
# Using big-M trick (M = maximum # of pieces per program) to convert from logical to algebraic constraint
for z=1:k
for y = 1:soloist_types
@constraint(m, is_soloist[y,z] <= sum(x[i,z]*piecedata[i,psoloists[y]] for i in 1:n))
@constraint(m, is_soloist[y,z] * maxpieces >= sum(x[i,z] * piecedata[i,psoloists[y]] for i in 1:n))
end
end
# Track cost of resources demanded by all pieces chosen for all programs
for i=1:k
@constraint(m, soloist_cost[i] == sum(is_soloist[t,i]*soloist_type_costs[t] for t in 1:length(soloist_type_costs)))
end
#--------------------------------------------------------------------------------------------------------------
## SOLVER
# Assert tradeoff weights
reg_weights = [0.1, 0.1, 0.1, 0.1, 0.0025, -10, -16, -0.15]
@objective(m, Max,
sum(reg_weights[1]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Piece recognizability"] for i in 1:n))#added quality due to this trait
+ sum(reg_weights[2]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Composer recognizability"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[3]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Accessibility"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[4]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Artistic merit"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[5]*(norm_2_themes)) # cohesiventess of themes using 2-norm
+ sum(reg_weights[6]*sum(temperament)) # cohesiveness of temperaments using 1-norm
+ sum(reg_weights[7]*sum(soloist_cost)) # total season cost
+ reg_weights[8]*sum(sum(themes_chosen))) # total number of themes
@time(solve(m))#print solver time
println("Weights of Iteration: ", reg_weights)
xl = getvalue(x)
norm_2_themesl=getvalue(norm_2_themes)
temperamentl=getvalue(temperament)
soloist_costl=getvalue(soloist_cost)
themes_chosenl=getvalue(themes_chosen)
results=xl
c=[sum(reg_weights[1]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Piece recognizability"] for i in 1:n)),#added quality due to this trait
sum(reg_weights[2]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Composer recognizability"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[3]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Accessibility"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[4]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Artistic merit"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[5]*(norm_2_themesl)),# cohesiventess of themes using 2-norm
sum(reg_weights[6]*sum(temperamentl)),# cohesiveness of temperaments using 1-norm
sum(reg_weights[7]*sum(soloist_costl)),# total season cost
sum(reg_weights[8]*sum(sum(themes_chosenl)))]# total number of themes
final_themes = themes_chosenl#getvalue(themes_chosen)
total_cost = soloist_costl#getvalue(soloist_cost)
#this should all be straight forward otherwise printing wouldn't be
println("Split Objectives: ",c)
println("Soloists: ", soloist_costl)
println("IsSoloist: ", getvalue(is_soloist))
println("Season cost: ", sum(total_cost))
for i in 1:k
println("\n=======\n")
println("Program ", i, ":")
for j in 1:n
if results[j,i] > 0.9
println(" ",piecenames[j])
end
end
println("Duration: ", sum(results[:,i].*piecedata[:,"Duration (min)"])," minutes\n")
sorted=sort(final_themes[i,:],rev=true)
used=zeros(3)
for iter in 1:3
block=0
for z in 1:num_themes
if final_themes[i,z]==sorted[iter]
if (used[1]!=z) & (used[2] != z) & (block==0)
print("Theme ",iter,": ")
print(themes[z])
println(", Valued at ",sorted[iter])
used[iter]=z
block=1#end loop
end
end
end
end
end
```

The model outputs the three programs shown above. Let's examine some interesting features of its selections:

The thematic cohesiveness scores for the three programs show three very different patterns. Cohesiveness is weighted by duration, so the "valued at" score indicator gives clues as to how prevalent each of the program's top three themes is.

Program 3 consists of a single long piece, so its cohesiveness score is very high.

Program 2 has one theme shared among all pieces, one theme shared among (most likely) all but one piece, and one theme only shared by one or two pieces. This is a desirable distribution, with a good mix of diversity and interesting juxtaposition of ideas.

Program 1 has very low cohesiveness scores overall. This is likely due to the choice of *Symphony No. 5 in C minor*; as noted in the "Diagnostics" section, we intentionally did not mark any thematic elements for this piece. Its presence here indicates that we should be cautious--but the reasonable cohesiveness results exhibited in the other two programs reassures us that overall our parameters lie within acceptable bounds.

*The Messiah* by Georg Frideric Handel is often performed in real life as a standalone massive orchestral and choral work. The *Hallelujah Chorus* is a well-known excerpt from this piece. It alone takes up 5 of the 6 soloist-equivalents expended for the season, and doesn't score particularly well on composer recognizability (5) or accessibility (4). However, our model tends to like long pieces, because many objective terms are weighted by piece duration, to avoid a jumble of short pieces. *The Messiah* is exactly 120 minutes long, our set cap on the duration of music permitted for a single performance. Its length, fame, and high artistic merit score overcome its detriments.

This incarnation of the model gives the orchestra a budget of $4*(number of programs)$, or 12 for this implementation. However, in this case a solution is found with a total expenditure of only 6 SEs. A potential reason is that cost and artistic merit do not necessarily scale proportionally; there are many highly worthwhile pieces that don't require additional resources to perform which the model can choose.

The "Split Objectives" printout at the top of the listing gives the final objective score outcome for each of the objective function terms (in order: piece recognizability, composer recognizability, accessibility, artistic merit, thematic cohesiveness, temperament diversity, cost, and thematic overdiversity penalizer). The "Split Objectives" will often help diagnose unexpected model behavior. Here, we see that the first five terms are all competing on about an equal footing; term six is zero, since the model has managed to achieve perfect temperamental balance; cost is not too important; and the overdiversity penalizer is weaker than the other terms, but still large enough to exert an influence on the thematic cohesiveness term.

Our baseline set of tradeoff parameters reasonably approximates the objective priorities of a regional, moderately resource-constrained orchestra like the MSO. However, an interesting extension of this initial result is to examine the effect of the orchestra's financial situation on its choices. Let us imagine a spectrum with the New York Philharmonic at one extreme (internationally renowned, large audiences, profitable endowment), and the Nashville Symphony Orchestra at the other (very small, borderline financial insolvency).

In order to change the organization's prioritization of financial concerns versus artistic ones, we group the objectives into financial and artistic buckets and apply a financial-preference weight to all of the financial objectives, on top of their normal regularization parameters. Then we solve the problem to optimality repeatedly, increasing the degree of financial prioritization each time.

In [33]:

```
## SOLVER
# Objective contributor groups
financial_objectives = [1, 2, 7]
artistic_objectives = [3, 4, 5, 6, 8]
graph_values=zeros(7,2)#each col is fin vs art
for h = 1:7
reg_weights_init = [0.1, 0.1, 0.1, 0.1, 0.0025, -10, -16, -0.15]#Initialize each loop to fix glitch #These may be good [800, 200, 60, 50, 0.4, 0.04, 0.08, 0.5] or old=[.1, .1, 2.0, 3.0, 5.0, -0.5, -5.0, 0]
fin_pref = 0.001 * 10^(h-1) #Group priority level for financial objectives
reg_weights = reg_weights_init # (Re-)Initialize regularization weights
for g in financial_objectives
reg_weights[g] = reg_weights_init[g] * fin_pref
end
season_cost_cap = k*(7-h)# season budget, in units of [# of soloists]
@constraint(m, sum(soloist_cost) <= season_cost_cap) # Maximum total expense for the season
@objective(m, Max,
sum(reg_weights[1]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Piece recognizability"] for i in 1:n))#added quality due to this trait
+ sum(reg_weights[2]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Composer recognizability"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[3]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Accessibility"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[4]*sum(x[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Artistic merit"] for i in 1:n))#added quality dued to this trait
+ sum(reg_weights[5]*(norm_2_themes)) # cohesiventess of themes using 2-norm
+ sum(reg_weights[6]*sum(temperament)) # cohesiveness of temperaments using 1-norm
+ sum(reg_weights[7]*sum(soloist_cost)) # total season cost
+ reg_weights[8]*sum(sum(themes_chosen))) # total number of themes
println("Iteration ", h)
@time(solve(m))#print solver time
println("Financial Preference: ",fin_pref)
println("Weights of Iteration: ", reg_weights)
xl = getvalue(x)
norm_2_themesl=getvalue(norm_2_themes)
temperamentl=getvalue(temperament)
soloist_costl=getvalue(soloist_cost)
themes_chosenl=getvalue(themes_chosen)
results=xl
c=[sum(reg_weights[1]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Piece recognizability"] for i in 1:n)),#added quality due to this trait
sum(reg_weights[2]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Composer recognizability"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[3]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Accessibility"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[4]*sum(xl[i,:].*piecedata[i,"Duration (min)"].*piecedata[i,"Artistic merit"] for i in 1:n)),#added quality dued to this trait
sum(reg_weights[5]*(norm_2_themesl)),# cohesiventess of themes using 2-norm
sum(reg_weights[6]*sum(temperamentl)),# cohesiveness of temperaments using 1-norm
sum(reg_weights[7]*sum(soloist_costl)),# total season cost
sum(reg_weights[8]*sum(sum(themes_chosenl)))]# total number of themes
graph_values[h,1]=sum(c[financial_objectives]/fin_pref)
graph_values[h,2]=sum(c[artistic_objectives])
final_themes = themes_chosenl#getvalue(themes_chosen)
total_cost = soloist_costl#getvalue(soloist_cost)
#this should all be straight forward otherwise printing wouldn't be
println("Split Objectives: ",c)
println("Soloists: ", soloist_costl)
println("Season cost: ", sum(total_cost))
for i in 1:k
println("\n=======\n")
println("Program ", i, ":")
for j in 1:n
if results[j,i] > 0.9
println(" ",piecenames[j])
end
end
println("Duration: ", sum(results[:,i].*piecedata[:,"Duration (min)"])," minutes\n")
sorted=sort(final_themes[i,:],rev=true)
used=zeros(3)
for iter in 1:3
block=0
for z in 1:num_themes
if final_themes[i,z]==sorted[iter]
if (used[1]!=z) & (used[2] != z) & (block==0)
print("Theme ",iter,": ")
print(themes[z])
println(", Valued at ",sorted[iter])
used[iter]=z
block=1#end loop
end
end
end
end
end
println("\n========================================\n")
end
println(graph_values)
```

First, let's examine the text output above.

As might be expected, programs become less artistically ambitious as the financial constraint scales up in priority. Iterations 1 and 2 are dominated by *The Messiah* and *Israel in Egypt*, both spectacular large-scale choral and orchestral works which cost 5 and 7 SEs, respectively. Programs contain fewer pieces each, and thematic cohesiveness scores are very high. From Iteration 1's "Split Objectives" line, we see that thematic cohesiveness (entry 5) and the number-of-themes penalty term (entry 8) are both very active and pulling hard against one another; this may explain the model's sticky preference for both of these long pieces, which produce good results on cohesiveness without creating an overabundance of total themes present. Overall, the model's recommended strategy in the "flush with cash" regime is to go for big, bold, expensive pieces that also score well on other artistic goals.

By Iteration 6, the opposite behavior is observed. Cohesiveness scores are very low (as low as 29 for Program 3), and the model favors a larger number of short, cheap pieces. Iteration 6's "Split Objectives" line reveals that the three cost factors (entries 1, 2, and 7) dominate all other factors by one or two orders of magnitude. The positively-weighted financial factors (piece recognizability and composer recognizability) even dominate over the negatively-weighted cost score, implying (as will be seen below) that the orchestra may take a small gamble on increasing costs slightly in order to capture major benefits in audience appeal. Overall, when funds are tight, the model recommends conservative programming featuring simpler and shorter pieces.

In Iteration 5, for the first time the model chooses a season with a cost of zero. In qualitative terms, we might classify this as the beginning of the "financial trouble zone". Notice some interesting appearances and disappearances as we move across that line:

*Toccata and Fugue in D minor*appears for the first time. Despite being artistically ill-suited to an orchestra performance, it scores high in both recognizability parameters while also having a cost of zero (hypothetically driving up ticket sales without increasing costs).*The Messiah*, an apparent recurring favorite of the model in Iterations 1, 2, and 4, disappears for good starting at Iteration 5 (due to its soloist cost of 5 SEs).The number of pieces per program increases overall: from (1, 3, 4) to (3, 4, 5). Cost is not weighted by piece duration, so as cost becomes more of a driving factor the model reverts to its natural tendency to cram in as many short pieces as possible. Many short pieces are also cheap to perform, whereas most of the very long works in the list have nonzero soloist requirements.

Thematic cohesiveness scores drop dramatically. This is also a natural result of the greater priority on financial considerations; in Iteration 5 the orchestra is much more creatively constrained.

An unexpected result is that Mahler's *Symphony No. 8 in E flat Major* (the Symphony of a Thousand) makes a sudden appearance in Iteration 3, but disappears again immediately thereafter. Recall from above that this piece is both extremely costly and highly artistically meritorious. It seems that this vertex becomes briefly optimal for a small region of financial preference (since these characteristics oppose one another), but the preference is not stable. Perhaps most surprising is that it does not make an appearance for very small values of the financial preference factor. This may be due to the fact that it does not possess very many themes, and thematic cohesiveness is a strongly prevailing factor in Iteration 2 (notice that the fifth entry in Iteration 2's "Split Objectives" printout is 373, nearly 1.5 times larger than its next competitor).

Iteration 5 constrains its total season cost to zero, but for Iteration 6 the model actually hires one soloist--a violinist, who plays for both the *Violin Concerto in E minor* and *Verklarte Nacht*. Because of the soloist-sharing feature of the cost term, this move allows the model to snag two well-scoring pieces for the price of one SE. This appears to be made possible by the dominance of the two recognizability scores over the cost score--the model computed that the cost increase would be offset in the objective by the ability to stage two pieces that score well in recognition.

In [52]:

```
using PyPlot
figure()
plot(1:7,graph_values[:,1], "r", markersize=1)
plot(1:7,graph_values[:,2], "b", markersize=1)
xlabel("Iteration")
ylabel("Relative Objective Influence")
title("Financial Efficiency versus Artistic Appeal")
legend(["Financial Efficacy", "Artistic Appeal"])
```

Out[52]:

This chart shows the evolution of the Artistic Appeal composite score and the Financial Efficacy composite score for the selected seasons in each iteration. Financial Efficacy is divided by the financial preference factor, so that both scores will exhibit comparable values.

The immediately striking feature here, which was not obvious from the text output above, is the Artistic score spike in Iteration 7. Careful examination will also reveal a slight decrease in the Financial Efficacy score. The source of this behavior is not clear; this will be discussed more in the Future Work section.

The crossover point between Iterations 4 and 5 is also readily apparent here. Even the unusual Artistry spike in Iteration 7 is not enough to bring the orchestra back to its Iteration 1-4 glory days of unfettered artistry-focused decisionmaking.

In [36]:

```
h=[0.001 * 10.^(1:7-1)]
figure()
plot(graph_values[:,1], graph_values[:,2], "r", markersize=1)
#plot(1:7,graph_values[:,2], "b", markersize=1)
xlabel("Relative Financial Objective Weight")
ylabel("Relative Artistic Objective Weight")
title("Tradeoff Curve: Financial versus Artistic Priorities")
```

Out[36]:

Our Pareto front is concave because our objective function is a maximization rather than a minimization. Nevertheless, it behaves more or less as all tradeoff curves do; more extreme sacrifices are required to make progress far from the $y = - x$ line.

Careful characterization of orchestra preferences and goals has allowed us to create a functional model for selecting season programming for a symphony orchestra. Our model balances eight organizational artistic and financial objectives and creates optimal overall music selections as well as the best possible combinations of pieces within discrete programs. The programs generated by the model overall pass the "sniff test"--even in fairly extreme cost-versus-artistry cases, the results it produces seem reasonable.

Outside of the direct use of the program for generating a season schedule, this optimizer could be used to characterize particular orchestras' decision-making methods. Using data on past season schedules for a given orchestra, the model could be inverted to solve for the approximate effective coefficients the orchestra uses. The coefficient metric that is used in our model could then give researchers better tools to compare symphonies programming, and cultural differences in general priorities, across time and space. This can be done by first making many top popular scheduled songs of a time which includes all songs used in a season by a particular symphony. Next, we could write an optimization algorithm that determines the set of coefficients that most closely generates the symphonies actual season. Not only would this be informing for the symphony programmers, but audiences may be interested in motivations of their symphony.

Additionally, with an expanded dataset the model could help orchestras explore music outside of their typical wheelhouse without sacrificing their typical priorities. Historically, the most well-known composers have disproportionately dominated all symphony programming in the US. “50% of the repertoire performed (in minutes) during [the 20th century in the United States] was by 28 composers.” [2] Much of the decision-making process is, of course, intuitive and experience-based, but the ability to quickly generate many examples of potential programs and seasons that advance your organization's general priorities may serve as a useful source of inspiration.

One significant weakness in the robustness of the results produced here is the dataset. Because the data was produced significantly by the authors listing pieces they already knew, the dataset is highly biased to reflect the authors' musical preferences (the Romantic Period is severely overrepresented, and the Baroque period is underrepresented). A further analysis should expand this dataset and render it more representative of the classical repertoire as a whole. To deal with the slowdown from the corresponding increase in number of decision variables, pruning heuristics should be developed in order to rapidly discard apparently-unfit pieces.

Finally, the odd behavior in Iteration 7 above deserves a mention. More work should be done in characterizing the response of the model to extreme financial-vs-artistic preference values. In particular, examining a wider range of base $reg_{coeff}$ values would likely reveal a pattern to this oddity that may give clues as to its source.

Bonnin, Geoffray, and Dietmar Jannach. “Automated Generation of Music Playlists: Survey and Experiments.” ACM Computing Surveys, vol. 47, no. 2, 2014, pp. 1–35., doi:10.1145/2652481.

Thuerauf, Jeffrey P. “Orchestra Programming A Survey of American Symphony Orchestra Programming for the 2003-04 Season.” Musike, vol. 1, 30 Sept. 2008.