Generator embedding optimization/Coinciding-damage method

Revision as of 22:56, 27 October 2026 by Sintel (talk | contribs) (Split three)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The third and final specific optimization power we'll take a look at in this article is [math]\displaystyle{ p = ∞ }[/math], for minimax tuning schemes.

The method for minimax tuning schemes is similar to the zero-damage method used for miniaverage tuning schemes, where [math]\displaystyle{ p = 1 }[/math]. However, there are two key differences:

  1. Instead of gathering only the points created where target-intervals' damage graphs coincide with zero damage, we also gather any points where target-intervals's damage graphs coincide with nonzero damage.
  2. Where the [math]\displaystyle{ p=1 }[/math] method is not capable of tie-breaking when the basic mini-[math]\displaystyle{ p }[/math]-mean is a range of tunings rather than a single unique optimum tuning, this [math]\displaystyle{ p=∞ }[/math] method is capable of tie-breaking, to find the true single unique optimum tuning.

History

This method was originally developed by Keenan Pepper in 2012,[note 1], in a 142-line long Python file called tiptop.py.

Keenan developed his algorithm specifically for the minimax-S tuning scheme (historically known as "TOP"), the original and quintessential all-interval tuning scheme. The all-interval use case is discussed below in the "For all-interval tuning schemes" section.

Specifically, Keenan's method was developed for its tie-breaking abilities, at a time where the power-limit method's ability to tie-break was unknown or not popular.

Keenan's method was modified in 2021-2023 by Douglas Blumeyer in order to accommodate ordinary tunings—those with target-interval sets where the optimization power is [math]\displaystyle{ ∞ }[/math] and the norm power may be anything or possibly absent—and this is what will be discussed immediately below. Douglas's modifications also included support for held-intervals, and for alternative complexities, both of which are discussed in sections below, and also an improvement that both simplifies it conceptually and allows it to identify optimum tunings more quickly. Dave Keenan further modified Keenan's method during this time so that it can find exact solutions in the form of generator embeddings, which is also reflected in all the explanations below.

The explanation of how this method works is mostly by Douglas Blumeyer, but Dave Keenan and Keenan Pepper himself both helped tremendously with refining it. (Douglas takes credit for any shortcomings, however. In particular, he apologizes: he didn’t have time to make it shorter.)

Coinciding-damage points

Points for finding damage minimaxes

Damage minimaxes are always found at points in tuning damage space where individual target-interval hyper-V damage graphs intersect, or cross, to form a point.

This doesn't mean that every such point will be a damage minimax. It only means that every damage minimax will be such a point.

Now, the reason why a damage minimax point must be a point of intersection of target-interval damage graphs like this is because a minimax can only occur at a point on the max damage graph where it changes slope, and the max damage graph can only change slope where damage graphs cross. In other words, whenever damage graphs cross, then on one side of the crossing, one is on top, while on the other side, the other is on top.

(For the duration of this explanation, we'll be illustrating things in 2D tuning damage space, because it's simplest. We'll wait until the end to generalize these ideas to higher dimensions.)

But many times when damage graphs cross, while this is still true about which target-interval's damage is on top switching, they were all sloping with the same sign, i.e. all up, or all down:

 

And minimax points will never happen at these sorts of crossings. So we have to be more specific.

A minimax point cannot be just any point where the max damage graph changes slope. It must be at a point where the sign of the slope changes between positive and negative. This will create what we call a "local minimum", the sort of thing that could be our mini-max, or minimum maximum. ("Local minimum" is a technical term, but the "local" part of it turns out not to be relevant to this problem, and it may cause more confusion to attempt to explain why not, so we'll just ignore it.)

We might call this sort of point a [math]\displaystyle{ -+ }[/math] point, in reference to the signs of the slopes to either side. And by analogy, the other kinds would be [math]\displaystyle{ -- }[/math] or [math]\displaystyle{ ++ }[/math] points.

 

When damage graphs cross while sloping in opposite directions, like this [math]\displaystyle{ -+ }[/math] point, then when we move in either direction away from such a coinciding-damage point, at least one of these target-intervals' damages will be going up. And by the nature of the maximum, all it takes is one of their damages going up in order for their max damage to go up.

And so if we look at it the other way around, it means that from any direction coming in toward this point, the maximum damage is going down, and that once we reach this point, there's nowhere lower to go. That's what we mean by a "minimum."

As for the "local" part of "local minimum", this only means that there might be other minima like this one. In order to deal with that part of the term better, we'll have to start looking not only at two target-intervals' damages at a time, but all of them at once.

 

When we zoom out and consider all the crossings among all our target-intervals, not just these two, we can see all sorts of different crossings. We have some [math]\displaystyle{ -- }[/math] points and [math]\displaystyle{ ++ }[/math] on the periphery, and some [math]\displaystyle{ -+ }[/math] points in the middle. Notice that we included among those the zero-damage points on the floor, which aren't exactly crossings, per se, but they are closely related, as we'll see soon enough; they sort of make their own local minima all by themselves. (This isn't even all of the crossings, by the way; it's hard to tell, but the slopes of the red and green lines on the left are such that eventually they'll cross, but way, way off the left side of this view.)

Notice that most of the points are [math]\displaystyle{ -+ }[/math] type points (9 of them, including the zero-damage ones). Fewer of them are the mere change-of-slope types, the [math]\displaystyle{ -- }[/math] or [math]\displaystyle{ ++ }[/math] type (5 of them, including the one off-screen to the left). However, of these 9 important [math]\displaystyle{ -+ }[/math] points, only one of them is the actual minimax! In other words, for every other [math]\displaystyle{ -+ }[/math] point, when we consider all the other target-intervals too, we find that at least one of their damage graphs passes above it. The minimax point is the only [math]\displaystyle{ -+ }[/math] that's on top.

So our minimax tuning is found at a point where:

  • We have a crossing of target-interval damage graphs,
  • But not just any one of those: it has to be a [math]\displaystyle{ -+ }[/math] type crossing,
  • But not just any one of those: it has to be the one that's on top.*

Now, it might seem inefficient to check 14 points, the ones that only meet the first bullet's criterion, just to find the one we want that meets all three bullet's criteria. But actually, for a computer, 14 points is easy peasy. If we compared that with how many points it would check while following the general method for solving this, that could be thousands of times more, and it still would only be finding an approximate solution; the general method has a weaker understanding of the nature of the problem it's solving. In fact, this diagram shows a very simple 3-limit temperament with only 4 target-intervals, and the typical case is going to be 7-limit or higher with a dozen or more target-intervals, which gets exponentially more complex. But even then it may still be fewer points for the computer to check overall, even though many of them are not going to work out.

And you might wonder: but why don't we just scan along the max graph and pick the [math]\displaystyle{ -+ }[/math] point? Well, the problem is: we don't have a function for the max damage graph, other than defining it in terms of all the other target-interval damage graphs. So it turns out that checking all of these crossing points is a more efficient way for a computer to find this point, than doing it the way that might seem more obvious to a human observer.

*

Once we start learning about tie-breaking, we'll see that this is not always exactly the case. But it's fine for now.

Points for finding damage miniaverages

In our explanation of the zero-damage method for [math]\displaystyle{ p=1 }[/math], we saw a similar thing in action for damage miniaverages. But these can only be found at a strict subset of such coinciding-damage points. Specifically, a damage miniaverage is found somewhere among the subset of coinciding-damage points wherever a sufficient count of individual target-intervals' hyper-V-shaped damage graphs intersect along the zero-damage floor of the world, in other words, along their creases.

We won't find miniaverages at any of the other coinciding-damage points, at various heights above the zero-damage floor wherever enough hyper-V's intersect to form a point. We do find minimaxes there, because (to review the previous section) in any direction away from such a point, at least one of the damages will be going up, and all it takes is one damage to go up to cause the max damage to go up. But the same fact is not true of average damage.

In 2D we can see plainly that we don't create any local minimum, or even any change of slope, in our average graph at just any crossing of two damage graphs. On one side of their intersection, one is going up and the other is going down. On the other side of their intersection, the same one is still going up and the same other one is still going down! The average is changing at the same rate.

 

So the only points where we can say for certain that in any direction no intersecting target-interval's damage has anywhere further down to go are the places where enough creases cross to make a point where they're already along the zero-damage floor. So these are the only points worth looking for a damage miniaverage:

 

Zero-damage coincidings

So: both types of points are coinciding-damage points. In fact, it may be helpful for some readers to think of the zero-damage method and its zero-damage point set as the (coinciding-)zero-damage method and its (coinciding-)zero-damage point set. It simply uses only a specialized subset of coinciding-damage points.

Because both types of points are coinciding-damage points, both types are possible candidates for damage minimax tunings. We can see that zero-damage coincidings are just as valid for getting local minima in the max damage graph:

 

As we'll see in the next subsection, when intersecting on the zero-damage floor, we actually need one fewer target-interval to create a point. So [math]\displaystyle{ \textbf{i}_2 }[/math] isn't even really necessary here. We just thought it'd be more confusing to leave it off than it would be to keep it in, even though this means we have to accept that the target-intervals are multiples of each other, e.g. we could think of [math]\displaystyle{ \textbf{i}_1 }[/math] and [math]\displaystyle{ \textbf{i}_2 }[/math] here as [math]\displaystyle{ \frac32 }[/math] and [math]\displaystyle{ \frac94 }[/math], respectively, with prime-count vectors [-1 1⟩ and [-2 2⟩, though it's not like that's a problem or anything. In 3D tuning damage space we wouldn't have this multiples problem; there's a lot more natural and arbitrary looking angles that creases can be made to intersect. But in 3D we'd still have the one-fewer-necessary-on-the-floor problem, which is a bigger problem. And in general it's best to demonstrate ideas as simply as possible, so we stuck with 2D.

But this also creates the terminological problem whereby in 2D, a single target-interval damage graph bouncing off the floor is wanted as a "coinciding-damage" point. In this case, we can reassure ourselves by imagining that the unison is always sort of in our target-interval set, and its graph is always the flat plane on the floor, since it can never be damaged. So in a way, the target-interval's damage coincides with the unison, and/or the unison is thought of as the "missing" interval, the one fewer that are required for an intersection here.

We may observe that the latter kind of point, the coinciding-zero-damage points—those where damage graphs intersect on the zero-damage floor—may seem to be less likely candidates for minimax tunings, considering that by the nature of being on the zero-damage floor, where no target-interval's damage could possibly be any lower, there's almost certainly some target-interval with higher damage (whose damage is still increasing in one direction or another). And this can clearly be seen on the diagram we included a bit earlier. However, as we'll find in the later section about tie-breaking, and hinted at in an asterisked comment earlier, these points are often important for tie-breaking between tunings which are otherwise tied with each other when it comes to those higher-up damages (i.e. at least one direction, a higher-up damage is neither going up nor going down, such as along an intersection of two damage graphs whose creases are parallel).

Generalizing to higher dimensions: Counts of target-intervals required to make the points

Another difference between the specific zero-damage points and general coinciding-damage points is that zero-damage points require one fewer target-interval damage graph to intersect in order to produce them. That's because a hyper-V's crease along the zero-damage floor has one fewer dimension than the hyper-V itself.

Perhaps this idea is best understood by explaining separately, for specific familiar dimensions of tuning damage space:

  • In 3D tuning damage space, for every hyper-V, the main part of each of its two "wings" is a plane, and we know that it takes two intersecting planes to reduce us to a line, and three intersecting planes to reduce that line further to a single point. But each hyper-V's crease is already a line, so it only takes two intersecting hyper-V creases to reduce us to a point.
  • In 2D tuning damage space, each wing of a hyper-V is a line, and it takes two intersecting lines to make a point. But each hyper-V's crease is already a single point, so we don't even need any intersections here to find points of possible minimax interest!

 

In general, the number of target-intervals whose graphs will intersect at a point—i.e., their damages will coincide—is equal to the dimension of the tuning damage space. So in 3D tuning damage, we need three hyper-V's to intersect. Think of it this way: a 3D point has a coordinate in the format [math]\displaystyle{ (x,y,z) }[/math], and we need one plane, one target-interval, for each element of that coordinate. But for intersections among creases along the floor, we only need one less than the dimensionality of the tuning damage space to specify a point; that's because we already know that one of the coordinates is 0.

The dimension of the tuning damage space will be equal to the count of generators plus one, or in other words, [math]\displaystyle{ r + 1 }[/math], where [math]\displaystyle{ r }[/math] is the rank. This is because tuning damage space has one dimension along the floor for each generator's tuning, and one additional dimension up off the floor for the damage amounts.

Points vs. lines; tuning space vs. tuning damage space

Throughout the discussion of this method, we may sometimes refer to "points" and "tunings" almost interchangeably. We'll attempt to dispel some potential confusion.

In tuning damage space, a tuning corresponds with a vertical line, perpendicular to the zero damage floor. Any point on this line identifies this same tuning. If we took an aerial view on tuning damage space, looking straight down on it—as we do in the topographic, contour style graphs these lines would look like points. Basically in this view, the only dimensions are for the generators, and the extra dimension for damage is collapsed. In other words, we go from tuning damage space back to simply tuning space.

So a 2D tuning damage space collapses to a 1D tuning space: a single line, a continuum of the single generator's size. And a 3D tuning damage space collapses to a 2D tuning space, with one generators' size per axis.

So what's tricky about this method in this regard is that to some extent we care about points in tuning damage space, because it's points where key intersections between tuning damage graphs come up. But when two such points fall on the same vertical line, they've identified the same exact tuning, and are thus redundant. So we should be careful to say these are the same tuning, not the same point, but occasionally it may make sense to call them the same point even if they're offset vertically in tuning damage space, because in tuning space they would be the same point.

It might seem wise to draw the vertical tuning lines that correspond with these points, but in general we've found that this is more noise than it's worth.

How to gather coinciding-damage points

For a general coinciding-damage point

The first step is to iterate over every combination of [math]\displaystyle{ r + 1 }[/math] target-intervals, and for each of those combinations, look at all permutations of their relative directions. The rank [math]\displaystyle{ r }[/math] is the same as generator count in the basic case (later on we'll see how sometimes in this method it's different). And by "direction" we mean in the sense of "undirected value", i.e. are they greater than or less than unison.

Each of these relative direction permutations of target-interval combinations (we can call these "ReDPOTICs", for short) corresponds with a coinciding-damage point, which means a different candidate generator tuning map [math]\displaystyle{ 𝒈 }[/math]. The candidate [math]\displaystyle{ 𝒈 }[/math] which causes the least damage to the target-intervals (according to the [math]\displaystyle{ ∞ }[/math]-mean, i.e. the max statistic) will be elected as our minimax tuning.

Let's look at an example. Suppose our target-intervals are [math]\displaystyle{ \frac32 }[/math], [math]\displaystyle{ \frac54 }[/math], and [math]\displaystyle{ \frac53 }[/math]. And suppose we are working with a rank-1 temperament, i.e. with one generator.

So our combinations of intervals would be: [math]\displaystyle{ \{ \{ \frac32, \frac54 \}, \{ \frac32, \frac53 \} , \{ \frac54, \frac53 \} \} }[/math].

And each of these three combinations has two relative direction permutations: one where both intervals have the same direction, and one where both intervals have different directions. For the first combination, that is, we'd look at both [math]\displaystyle{ \{ \frac32, \frac54 \} }[/math] and at [math]\displaystyle{ \{ \frac32, \frac45 \} }[/math]. As you can see, in the latter case, we've made one of the two intervals subunison (less than [math]\displaystyle{ \frac11 }[/math]). To be clear, we're checking only permutations of relative direction here, by which we mean that there's no need to check the case where both intervals are subunison, or the case where which one of the two intervals is subunison and which one of them stays superunison is swapped.

We can see why we only worry about relative direction by explaining what we're going to do with these permutations of target-interval combinations: find the interval that is their product. The two permutations we've chosen above multiply to [math]\displaystyle{ \frac32 × \frac54 = \frac{15}{8} }[/math] and [math]\displaystyle{ \frac32 × \frac45 = \frac65 }[/math]. Had we chosen the other two permutations, they'd've multiplied to [math]\displaystyle{ \frac23 × \frac45 = \frac{8}{15} }[/math] and [math]\displaystyle{ \frac23 × \frac54 = \frac56 }[/math]. These second two intervals are simply the reciprocals of the first two results, and so in terms of tuning they are equivalent (technically speaking, we only care about undirected intervals, i.e. neither [math]\displaystyle{ \frac{15}{8} }[/math] nor [math]\displaystyle{ \frac{8}{15} }[/math] but rather [math]\displaystyle{ 8:15 }[/math].

As for why we care about the intervals that are the products of these ReDPOTICs, we'll look into that in just a moment. In short, it has to do with our originally stated plan: to find places where target-intervals have coinciding amounts of damage. (If you're feeling bold, you might try to work out how this product could relate to that already; if not, don't worry, we'll eventually explain it all in detail.)

Keenan came up with a clever way to achieve this only-caring-about-relative-direction permutations effect: simply restrict the first element in each combination to the positive direction. This effortlessly eliminates exactly half of the possible permutations, namely, the ones that are reciprocals of all the others. Done.

For a zero-damage point

Gathering the zero-damage points is much more straightforward. We don't need to build a ReDPOTIC. We don't need to worry about ReD (relative direction), or permutations of (PO) anything. We only need to worry about TIC (target-interval combinations).

But remember, these aren't combinations of the same count of target-intervals. They have one less target-interval each. So let's call them "smaller target-interval combinations", or STICs.

For each STIC, then, we simply want each combination of [math]\displaystyle{ r }[/math] of our target-intervals. For our example, with [math]\displaystyle{ r=1 }[/math], that'd simply be [math]\displaystyle{ \{ \{ \frac32 \}, \{ \frac54 \} , \{ \frac53 \} \} }[/math].

How to build constraint matrices

Once we've gathered all of our coinciding-damage points, both the general kind from ReDPOTICs and the zero-damage kind from STICs, we're ready to prepare constraint matrices. When we apply these to our familiar inequalities, we can convert them to solvable equalities. More on that in the next section, where we work through an example.

These constraint matrices are not themselves directly about optimizing tunings; they're simply about identifying tunings that meet these ReDPOTIC and STIC descriptions. Many of these tunings, as we saw in an earlier section, are completely awful! But that's just how it goes. The optimum tuning is among these, but many other tunings technically fit the description we use to find them.

Let's call these matrices [math]\displaystyle{ K }[/math], for "konstraint" ("C" is taken for a more widely important matrix in RTT, the comma basis).

For a general coinciding-damage point

With each of our general coinciding points, we can build a constraint matrix from its ReDPOTIC. Perhaps for some readers the approach could be best summed up near instantaneously by listing what these constraint matrices would be for the example we're going with so far:


[math]\displaystyle{ \begin{array} {c} \scriptsize 3/2 \\ \scriptsize 5/4 \\ \scriptsize 5/3 \end{array} \left[ \begin{array} {c} +1 \\ +1 \\ 0 \end{array} \right] , \left[ \begin{array} {c} +1 \\ {-1} \\ 0 \end{array} \right] , \left[ \begin{array} {c} +1 \\ 0 \\ +1 \end{array} \right] , \left[ \begin{array} {c} +1 \\ 0 \\ {-1} \end{array} \right] , \left[ \begin{array} {c} 0 \\ +1 \\ +1 \end{array} \right] , \left[ \begin{array} {c} 0 \\ +1 \\ {-1} \end{array} \right] }[/math]


Each constraint matrix is a [math]\displaystyle{ (k, r) }[/math]-shaped matrix, i.e. with one column for each generator and one row for each target. Every entry in these constraint matrices will have either a [math]\displaystyle{ 0 }[/math], [math]\displaystyle{ +1 }[/math], or [math]\displaystyle{ -1 }[/math].

  • If the value is [math]\displaystyle{ 0 }[/math], it means that target-interval is not included in the combination.
  • If the value is [math]\displaystyle{ +1 }[/math], we take the target-interval's superunison value.
  • If the value is [math]\displaystyle{ -1 }[/math], we take the target-interval's subunison value.

Another way to look at these values is from the perspective of the product that ultimately we make from the combination of target-intervals: these values are the powers to which to raise each target-interval before multiplying a column up. So a power of +1 includes the target-interval as is, a power of -1 reciprocates it, and a power of 0 sends it to unison (so multiplying it in with the rest has no effect).

So, for example, the last constraint matrix here, [0 +1 -1], means that with our example target-interval list [[math]\displaystyle{ \frac32 }[/math], [math]\displaystyle{ \frac54 }[/math], and [math]\displaystyle{ \frac53 }[/math]] we've got a superunison [math]\displaystyle{ \frac54 }[/math] and a subunison [math]\displaystyle{ \frac53 }[/math] (and no [math]\displaystyle{ \frac32 }[/math]), so that's [math]\displaystyle{ \frac54 × \frac35 = \frac34 }[/math], or in other words, [math]\displaystyle{ (\frac32)^{0}(\frac54)^{+1}(\frac53)^{-1} }[/math]. Yes, we're still in suspense about what the purpose of these products is, but we'll address that soon.

Notice that each first nonzero entry in each constraint matrix is [math]\displaystyle{ +1 }[/math], per the previous section's point about effecting relative direction.

For a zero-damage point

For each of our zero-damage points we can build a constraint matrix from its STIC. Here those are:


[math]\displaystyle{ \begin{array} {c} \scriptsize 3/2 \\ \scriptsize 5/4 \\ \scriptsize 5/3 \end{array} \left[ \begin{array} {c} +1 \\ 0 \\ 0 \end{array} \right] , \left[ \begin{array} {c} 0 \\ +1 \\ 0 \end{array} \right] , \left[ \begin{array} {c} 0 \\ 0 \\ +1 \end{array} \right] }[/math]


These tell us which interval will be unchanged in the corresponding tuning (take that as a hint for what will happen with the [math]\displaystyle{ K }[/math] for ReDPOTICs!).

Note that since, as we noted earlier, relative direction is irrelevant for zero-damage points, these matrices will never contain -1 entries. They will only ever contain 0 and +1.

A simple example

For our first overarching example, to help us intuit how this technique works, let's use a simplified example where our target-intervals are even simpler than the ones we looked at so far: just the primes, and thus [math]\displaystyle{ \mathrm{T} = \mathrm{T}_{\text{p}} = I }[/math], an identity matrix we can ignore.

Let's also not weight damage so the weight matrix [math]\displaystyle{ W = I }[/math] too.

For our temperament, we'll go with the very familiar 12-ET, so [math]\displaystyle{ M }[/math] = ⟨12 19 28]. Since this mapping is in the 5-prime-limit, our [math]\displaystyle{ 𝒋 }[/math] = 1200 × ⟨[math]\displaystyle{ \log_2(2) }[/math] [math]\displaystyle{ \log_2(3) }[/math] [math]\displaystyle{ \log_2(5) }[/math]]. And since our mapping is an equal temperament, our generator tuning map [math]\displaystyle{ 𝒈 }[/math] has only a single entry [math]\displaystyle{ g_1 }[/math].

A system of approximations

We'll be applying a constraint matrix to our by-now familiar approximation [math]\displaystyle{ 𝒈M \approx 𝒋 }[/math] in order to transform it from an approximation into an equality, that is, to be able to change its approximately equals sign into an equals sign. This is how each of these constraints take us to a single solution.


[math]\displaystyle{ \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \end{array} \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 12 & 19 & 28 \\ \end{array} \right] \end{array} \approx \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200\log_2(2) & 1200\log_2(3) & 1200\log_2(5) \\ \end{array} \right] \end{array} }[/math]


Another way to view a matrix expression like this[note 2] is as a system of multiple expressions—in this case, a system of approximations:


[math]\displaystyle{ 12g_1 \approx 1200\log_2(2) \\ 19g_1 \approx 1200\log_2(3) \\ 28g_1 \approx 1200\log_2(5) }[/math]


One variable to satisfy three approximations… that's asking a lot of that one variable! We can see that if we tried to make these all equalities, it wouldn't be possible for all of them to be true at the same time:


[math]\displaystyle{ 12g_1 = 1200\log_2(2) \\ 19g_1 = 1200\log_2(3) \\ 28g_1 = 1200\log_2(5) }[/math]


But this of course is the whole idea of tempering: when we approximate some number of primes with fewer generators, we can't approximate all of them exactly at once.

Constraints we apply to the problem, however, can simplify it to a point where there is an actual solution, i.e. where the count of equations matches the count of variables, AKA the count of generators.

Apply constraint to system

So let's try applying one of our constraint matrices to this equation. Suppose we get the constraint matrix [+1 +1 0]. (We may notice this happens to be one of those made from a ReDPOTIC, for a general coinciding-damage point.) This constraint matrix tells us that the target-interval combination is [math]\displaystyle{ \frac21 }[/math] and [math]\displaystyle{ \frac31 }[/math], because those are the target-intervals corresponding to its nonzero entries. And both nonzero entries are [math]\displaystyle{ +1 }[/math] meaning that both target-intervals are combined in the same direction. In other words, [math]\displaystyle{ \frac21 × \frac31 = \frac61 }[/math] is going to have something to do with this (and we're finally about to find out what that is!).

We multiply both sides of our [math]\displaystyle{ 𝒈M \approx 𝒋 }[/math] style setup by that constraint, to produce [math]\displaystyle{ 𝒈MK \approx 𝒋K }[/math]:


[math]\displaystyle{ \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \end{array} \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 12 & 19 & 28 \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} +1 \\ +1 \\ 0 \end{array} \right] \end{array} \approx \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200\log_2(2) & 1200\log_2(3) & 1200\log_2(5) \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} +1 \\ +1 \\ 0 \end{array} \right] \end{array} }[/math]


And now multiply that through, to get:


[math]\displaystyle{ \begin{aligned} \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \end{array} \begin{array} {ccc} MK \\ \left[ \begin{array} {rrr} (12)(+1) + (19)(+1) + (28)(0) \\ \end{array} \right] \end{array} &\approx \begin{array} {ccc} 𝒋K \\ \left[ \begin{array} {rrr} (1200\log_2(2))(+1) + (1200\log_2(3))(+1) + (1200\log_2(5))(0) \\ \end{array} \right] \end{array} \\[15pt] \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \left[ \begin{array} {rrr} 31 \\ \end{array} \right] &= \left[ \begin{array} {rrr} 1200\log_2(2) + 1200\log_2(3) \\ \end{array} \right] \end{aligned} }[/math]


So now we've simplified things down to a single equation with a single variable. All of our matrices are [math]\displaystyle{ (1,1) }[/math]-shaped, which is essentially the same thing as a scalar, so we can drop the braces around them and just treat them as such. And we'll swap the [math]\displaystyle{ 31 }[/math] and [math]\displaystyle{ g_1 }[/math] around to put constants and variables in the conventional order, since scalar multiplication is commutative. Finally, we can use a basic logarithmic identity to consolidate what we have on the right-hand side:


[math]\displaystyle{ 31g_1 = 1200\log_2(6) }[/math]


So with our constraint matrix, we've achieved the situation we needed, where we have a matching count of equations and generators. We can solve for this generator tuning:


[math]\displaystyle{ g_1 = \dfrac{1200\log_2(6)}{31} }[/math]


The meaning of the ReDPOTIC product

And that's our tuning, the tuning found at this coinciding-damage point.

It's a tuning which makes [math]\displaystyle{ \frac61 }[/math] pure by dividing it into 31 equal parts.

In cents, our generator [math]\displaystyle{ g_1 }[/math] is equal to about 100.063 ¢, and indeed 100.063 × 31 = 3101.955, which is exactly [math]\displaystyle{ 1200 × \log_2(6) }[/math].

And so that's what the constraint matrix's ReDPOTIC product [math]\displaystyle{ \frac61 }[/math] had to do with things: this product is an unchanged-interval of this tuning (the only one, in fact).

But our original intention here was to find the tuning where [math]\displaystyle{ \frac21 }[/math] and [math]\displaystyle{ \frac31 }[/math] have coinciding damage. Well, it turns out this is an equivalent situation. If—according to this temperament's mapping ⟨12 19 28]—it takes 12 steps to reach [math]\displaystyle{ \frac21 }[/math] and also it takes 19 steps to reach [math]\displaystyle{ \frac31 }[/math], and that it therefore takes 31 steps to reach a [math]\displaystyle{ \frac61 }[/math], and it is also the case that [math]\displaystyle{ \frac61 }[/math] is pure, then that implies that whatever error there is on [math]\displaystyle{ \frac21 }[/math] must be the exact opposite of whatever damage there is on [math]\displaystyle{ \frac31 }[/math], since their errors apparently cancel out. So if their errors are exact opposites—negations—then their damages are the same. So we achieve coinciding target-interval damages via an unchanged-interval that they all relate to. Cue the success fanfare.

Applying a constraint for a zero-damage point

Let's also try applying a [math]\displaystyle{ K }[/math] for a zero-damage point, i.e. one that came from a STIC.

Suppose we get the constraint matrix [0 0 +1]. This constraint matrix tells us that [math]\displaystyle{ \frac51 }[/math] will be unchanged, because that's the target-interval corresponding to its nonzero entry (all entries of these types of [math]\displaystyle{ K }[/math] will only be 0 or +1, recall).

We multiply both sides of our [math]\displaystyle{ 𝒈M \approx 𝒋 }[/math] style setup by that constraint, to produce [math]\displaystyle{ 𝒈MK \approx 𝒋K }[/math]:


[math]\displaystyle{ \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \end{array} \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 12 & 19 & 28 \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} 0 \\ 0 \\ +1 \end{array} \right] \end{array} \approx \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200\log_2(2) & 1200\log_2(3) & 1200\log_2(5) \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} 0 \\ 0 \\ +1 \end{array} \right] \end{array} }[/math]


And now multiply that through, to get:


[math]\displaystyle{ \begin{aligned} \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \end{array} \begin{array} {ccc} MK \\ \left[ \begin{array} {rrr} (12)(0) + (19)(0) + (28)(+1) \\ \end{array} \right] \end{array} &\approx \begin{array} {ccc} 𝒋K \\ \left[ \begin{array} {rrr} (1200\log_2(2))(0) + (1200\log_2(3))(0) + (1200\log_2(5))(+1) \\ \end{array} \right] \end{array} \\[15pt] \left[ \begin{array} {rrr} g_1 \\ \end{array} \right] \left[ \begin{array} {rrr} 28 \\ \end{array} \right] &= \left[ \begin{array} {rrr} 1200\log_2(5) \\ \end{array} \right] \\[15pt] 28g_1 &= 1200\log_2(5) \\[15pt] g_1 &= \dfrac{1200\log_2(5)}{28} \\[15pt] g_1 &= 99.511 \end{aligned} }[/math]


Comparing the zero-damage method's unchanged-interval bases with the coinciding-damage method's constraint matrices

If you recall, the zero-damage method for miniaverage tunings works by directly assembling unchanged-interval bases [math]\displaystyle{ \mathrm{U} }[/math] out of combinations of target-intervals. The coinciding-damage method here, however, indirectly achieves unchanged-interval bases via constraint matrices [math]\displaystyle{ K }[/math]. It does this both for the zero-damage points such as are used by the zero-damage method, as well as for the general coinciding-damage points that the zero-damage method does not use.

Though we note that even the general coinciding-damage points, where [math]\displaystyle{ r + 1 }[/math] target-intervals coincide for some possibly nonzero damage, are equivalent to zero-damage points where [math]\displaystyle{ r }[/math] intervals coincide for zero damage; the difference is that these unchanged-intervals are not actually target-intervals, but rather products of pairs of directional permutations of them.

The zero-damage method might have been designed to use constraint matrices, but this would probably be overkill. When general coinciding-damage points are not needed, it's simpler to use unchanged-interval bases directly.

Get damage lists

From here, we basically just need to take every tuning we find from the linear solutions like this, and for each one, find its target-interval damage list, and then from that find its maximum damage.

In an earlier section's example we found a candidate tuning where [math]\displaystyle{ g_1 = \frac{1200\log_2(6)}{31} \approx 100.0632 }[/math], so we could check damages for this one using our familiar formula:


[math]\displaystyle{ \textbf{d} = |\,𝒈M\mathrm{T}W - 𝒋\mathrm{T}W\,| }[/math]


And we said that both [math]\displaystyle{ \mathrm{T} }[/math] and [math]\displaystyle{ W }[/math] are identity matrices to simplify things so we can get rid of those.


[math]\displaystyle{ \textbf{d} = |\,𝒈M - 𝒋\,| }[/math]


And now substitute in the 100.0632:


[math]\displaystyle{ \textbf{d} = \Large | \normalsize \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} 100.0632 \\ \end{array} \right] \end{array} \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 12 & 19 & 28 \\ \end{array} \right] \end{array} - \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200.000 & 1901.955 & 2786.314 \\ \end{array} \right] \end{array} \Large | }[/math]


Anyway, that's enough busywork for now. You can work that out if you like, and then you'll have to work it out in the same way for every single candidate tuning.

You'll end up with a ton of possible damage lists [math]\displaystyle{ \textbf{d} }[/math], one for each generator tuning [math]\displaystyle{ 𝒈 }[/math] (the [math]\displaystyle{ K }[/math] have been transposed here to fit better):


[math]\displaystyle{ \begin{array} {c} \left[ \begin{array} {rrr} +1 & +1 & 0 \end{array} \right] & 𝒈_1 = \left[ \begin{array} {rrr} 100.063 \end{array} \right] & \textbf{d}_1 = \left[ \begin{array} {rrr} 0.757 & 0.757 & 15.452 \end{array} \right] \\ \left[ \begin{array} {rrr} +1 & {-1} & 0 \end{array} \right] & 𝒈_2 = \left[ \begin{array} {rrr} 100.279 \end{array} \right] & \textbf{d}_2 = \left[ \begin{array} {rrr} 3.351 & 3.351 & 21.506 \end{array} \right] \\ \left[ \begin{array} {rrr} +1 & 0 & +1 \end{array} \right] & 𝒈_3 = \left[ \begin{array} {rrr} 99.657 \end{array} \right] & \textbf{d}_3 = \left[ \begin{array} {rrr} 4.106 & 8.456 & 4.106 \end{array} \right] \\ \left[ \begin{array} {rrr} +1 & 0 & {-1} \end{array} \right] & 𝒈_4 = \left[ \begin{array} {rrr} 99.144 \end{array} \right] & \textbf{d}_4 = \left[ \begin{array} {rrr} 10.265 & 18.208 & 10.265 \end{array} \right] \\ \left[ \begin{array} {rrr} 0 & +1 & +1 \end{array} \right] & 𝒈_5 = \left[ \begin{array} {rrr} 99.750 \end{array} \right] & \textbf{d}_5 = \left[ \begin{array} {rrr} 2.995 & 6.697 & 6.697 \end{array} \right] \\ \left[ \begin{array} {rrr} 0 & +1 & {-1} \end{array} \right] & 𝒈_6 = \left[ \begin{array} {rrr} 98.262 \end{array} \right] & \textbf{d}_6 = \left[ \begin{array} {rrr} 20.855 & 34.976 & 34.976 \end{array} \right] \\ \left[ \begin{array} {rrr} +1 & 0 & 0 \end{array} \right] & 𝒈_7 = \left[ \begin{array} {rrr} 100.000 \end{array} \right] & \textbf{d}_7 = \left[ \begin{array} {rrr} 0.000 & 1.955 & 13.686\end{array} \right] \\ \left[ \begin{array} {rrr} 0 & +1 & 0 \end{array} \right] & 𝒈_8 = \left[ \begin{array} {rrr} 100.103 \end{array} \right] & \textbf{d}_8 = \left[ \begin{array} {rrr} 1.235 & 0.000 & 16.567 \end{array} \right] \\ \left[ \begin{array} {rrr} 0 & 0 & +1 \end{array} \right] & 𝒈_9 = \left[ \begin{array} {rrr} 99.511 \end{array} \right] & \textbf{d}_9 = \left[ \begin{array} {rrr} 5.866 & 11.242 & 0.000 \end{array} \right] \\ \end{array} }[/math]


The first six of these are from ReDPOTICs, for general coinciding-damage points. The last three are from STICs, for zero-damage points.

For each damage list, we can find the coinciding damages. In the first tuning, it's the first two target-intervals' damages, both with [math]\displaystyle{ 0.757 }[/math]. In the fifth tuning, it's the second and third target-intervals' damages, both with [math]\displaystyle{ 6.697 }[/math]. Etcetera. Note that these coinciding damages are not necessarily the max damages of the tuning; for example, the third tuning shows the first and third target-intervals both equal to [math]\displaystyle{ 4.106 }[/math] damage, but the second interval has more than twice that, at [math]\displaystyle{ 8.456 }[/math] damage. That's fine. In many cases, in fact, the tuning we ultimately want is one of these where the coinciding damages are not the max damages.

Identify minimax

In order to identify the minimax is generally pretty straightforward. We gather up all the maxes. And pick their min. That's the min-i-max.

So here's the maxes:


[math]\displaystyle{ \begin{array} {c} 𝒈_1 = \left[ \begin{array} {rrr} 100.063 \end{array} \right] & \text{max}(\textbf{d}_1) = 15.452 \\ 𝒈_2 = \left[ \begin{array} {rrr} 100.279 \end{array} \right] & \text{max}(\textbf{d}_2) = 21.506 \\ 𝒈_3 = \left[ \begin{array} {rrr} 99.657 \end{array} \right] & \text{max}(\textbf{d}_3) = 8.456 \\ 𝒈_4 = \left[ \begin{array} {rrr} 99.144 \end{array} \right] & \text{max}(\textbf{d}_4) = 18.208 \\ 𝒈_5 = \left[ \begin{array} {rrr} 99.750 \end{array} \right] & \text{max}(\textbf{d}_5) = 6.697 \\ 𝒈_6 = \left[ \begin{array} {rrr} 98.262 \end{array} \right] & \text{max}(\textbf{d}_6) = 34.976 \\ 𝒈_7 = \left[ \begin{array} {rrr} 100.000 \end{array} \right] & \text{max}(\textbf{d}_7) = 13.686 \\ 𝒈_8 = \left[ \begin{array} {rrr} 100.103 \end{array} \right] & \text{max}(\textbf{d}_8) = 16.567 \\ 𝒈_9 = \left[ \begin{array} {rrr} 99.511 \end{array} \right] & \text{max}(\textbf{d}_9) = 11.242 \\ \end{array} }[/math]


Out of these maximum values, 6.697 is the minimum. So that's our minimax tuning, [math]\displaystyle{ 𝒈_5 }[/math], where the generator is 99.750 ¢ and the max damage to any of our target-intervals is 6.697 ¢(U).

Had there been a tie here, i.e. had some other tuning besides [math]\displaystyle{ 𝒈_5 }[/math] also had 6.697 ¢ for its maximum damage, such that more than one tuning tied for minimax, then we would need to move on to tie-breaking. That gets very involved, so we'll look at that in detail in a later section..

A bigger example

The rank-1 temperament case we've just worked through, which has just one generator, was a great introduction, but a bit too simple to demonstrate some of the ideas we want to touch upon here.

  • Some aspects of the constraint matrices require multiple generators in order to illustrate effectively.
  • And we didn't demonstrate with weighting yet.
  • And we didn't demonstrate with a more interesting target-interval set yet.
  • And we didn't compute an exact solution via generator embedding yet.

Dang!

So let's work through another example, this time of

  • a rank-3 temperament,
  • using complexity-weight damage,
  • a more interesting target-interval set,
  • and get our answer in the form of a generator embedding.

Prepare constraint matrix

If we have three generators, we will have many coinciding-damage points, each one corresponding to its own constraint matrix [math]\displaystyle{ K }[/math]. For this example, we're not going to bother showing all of them. It would be way too much to show. Let's just follow the logic from start to finish with a single constraint matrix.

Let's suppose our target-interval list is [math]\displaystyle{ \{ \frac65, \frac75, \frac85, \frac95, \frac76, \frac43, \frac32, \frac87, \frac97, \frac98 \} }[/math]. We've labeled each of the rows of our [math]\displaystyle{ K }[/math] here with its corresponding target-interval:


[math]\displaystyle{ \begin{array} {rrr} \scriptsize{6/5} \\ \scriptsize{7/5} \\ \scriptsize{8/5} \\ \scriptsize{9/5} \\ \scriptsize{7/6} \\ \scriptsize{4/3} \\ \scriptsize{3/2} \\ \scriptsize{8/7} \\ \scriptsize{9/7} \\ \scriptsize{9/8} \\ \end{array} \left[ \begin{array} {rrr} 0 & 0 & 0 \\ +1 & +1 & +1 \\ +1 & 0 & 0 \\ 0 & {-1} & 0 \\ 0 & 0 & 0 \\ 0 & 0 & {-1} \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} \right] }[/math]


As we can see, this is one of the ReDPOTIC types of constraints, for a general coinciding-damage point. (We won't work through a STIC type for this example; there's actually nothing particularly helpful that we don't already understand that would be illustrated by that.)

So this constraint matrix makes three statements:

  1. The first column tells us that the (possibly-weighted) errors for [math]\displaystyle{ \frac75 }[/math] and [math]\displaystyle{ \frac85 }[/math] are opposites (same value but opposite sign), because the damage to [math]\displaystyle{ \frac75 × \frac85 }[/math] is zero.
  2. The second column tells us that the (possibly-weighted) errors for [math]\displaystyle{ \frac75 }[/math] and [math]\displaystyle{ \frac95 }[/math] are identical, because the damage to [math]\displaystyle{ \frac75 × \frac59 }[/math] is zero.
  3. The third column tells us that the (possibly-weighted) errors for [math]\displaystyle{ \frac75 }[/math] and [math]\displaystyle{ \frac43 }[/math] are identical, because the damage to [math]\displaystyle{ \frac75 × \frac34 }[/math] is zero.

Here's something important to observe that we couldn't confront yet with the simpler single-generator example. Note that while there is always one row of the constraint matrix for each generator, each row of the constraint matrix has no particular association with any one of the generators. In other words, it wouldn't make sense for us to label the first column of this [math]\displaystyle{ K }[/math] with [math]\displaystyle{ g_1 }[/math], the second with [math]\displaystyle{ g_2 }[/math], and the third with [math]\displaystyle{ g_3 }[/math] (or any other ordering of those); each column is as relevant to one of those generators as it is to any other. Any one of the generators may turn out to be the one which satisfies one of these constraints. Said another way, when we perform matrix multiplication between this [math]\displaystyle{ K }[/math] matrix and the [math]\displaystyle{ M\mathrm{T}W }[/math] situation, each row of [math]\displaystyle{ K }[/math] touches each row of [math]\displaystyle{ M\mathrm{T}W }[/math], so [math]\displaystyle{ K }[/math]'s influence is exerted across the board.

Another thing to note is that we set up the constraint matrix so that there's one target-interval that has a non-zero entry in each row, and that this is also the first target-interval column with a non-zero entry, i.e. the one that's been anchored to the positive direction. As we can see, in our case, that target-interval is [math]\displaystyle{ \frac75 }[/math]. Setting up our constraint matrix in this way is how we establish—using the transitive property of equality—that all four of these target-intervals with non-zero entries somewhere their column will have coinciding (equal) damages. Because if A's damage equals B's, and B's damage equals C's, then we also know that A's damage equals C's. And same for D. So we end up with A's damage = B's damage = C's damage = D's damage. All four have coinciding damage.

Eventually we want to multiply this constraint matrix by [math]\displaystyle{ M\mathrm{T}W }[/math] and by [math]\displaystyle{ \mathrm{T}W }[/math]. So let's look at those next.

Prepare tempered and just sides of to-be equality

For our mapping, let's use the minimal generator form of breed temperament, and for weights, let's use complexity-weighted damage ([math]\displaystyle{ W = C }[/math]).


[math]\displaystyle{ \scriptsize \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 1 & 1 & 1 & 2 \\ 0 & 2 & 3 & 2 \\ 0 & 0 & 2 & 1 \end{array} \right] \end{array} \begin{array} {ccc} \mathrm{T} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 \\ \end{array} \right] \end{array} \begin{array} {ccc} C \\ \text{diag}(\log_2(\left[ \begin{array} {rrr} 30 & 35 & 40 & 45 & 42 & 12 & 6 & 56 & 63 & 72 \\ \end{array} \right])) \end{array} }[/math]


And that resolves to the following:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} M\mathrm{T}C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & \log_2(35) & 2\log_2(40) & \log_2(45) & 0 & \log_2(12) & 0 & \log_2(56) & 0 & {-\log_2(72)} \\ {-\log_2(30)} & {-\log_2(35)} & {-3\log_2(40)} & \log_2(45) & 0 & {-2\log_2(12)} & 2\log_2(6) & {-2\log_2(56)} & 2\log_2(63) & 4\log_2(72) \\ {-2\log_2(30)} & {-\log_2(35)} & {-2\log_2(40)} & {-2\log_2(45)} & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 \\ \end{array} \right] \end{array} }[/math]


And what we've got on the other side of the equality is [math]\displaystyle{ \mathrm{T}W }[/math]. Note that we're not using [math]\displaystyle{ 𝒋\mathrm{T}W }[/math] here, since we're shooting for a generator embedding [math]\displaystyle{ G }[/math] such that [math]\displaystyle{ G\mathrm{T}W \approx \mathrm{T}W }[/math]; in other words, we took [math]\displaystyle{ 𝒋G\mathrm{T}W \approx 𝒋\mathrm{T}W }[/math] and canceled out the [math]\displaystyle{ 𝒋 }[/math] on both sides.


[math]\displaystyle{ \scriptsize \begin{array} {ccc} \mathrm{T} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 \\ \end{array} \right] \end{array} \begin{array} {ccc} C \\ \text{diag}(\log_2(\left[ \begin{array} {rrr} 30 & 35 & 40 & 45 & 42 & 12 & 6 & 56 & 63 & 72 \\ \end{array} \right])) \end{array} }[/math]


And that resolves to the following:


[math]\displaystyle{ \begin{array} {ccc} \mathrm{T}C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & 0 & \log_2(40) & 0 & {-\log_2(42)} & 2\log_2(12) & {-\log_2(6)} & 3\log_2(56) & 0 & {-3\log_2(72)} \\ \log_2(30) & 0 & 0 & 2\log_2(45) & {-\log_2(42)} & {-\log_2(12)} & \log_2(6) & 0 & 2\log_2(63) & 2\log_2(72) \\ {-\log_2(30)} & {-\log_2(35)} & {-\log_2(40)} & {-\log_2(45)} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & \log_2(35) & 0 & 0 & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 \\ \end{array} \right] \end{array} }[/math]


Apply constraint

Now we've got to constrain both sides of the problem. First the left side:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} M\mathrm{T}C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & \log_2(35) & 2\log_2(40) & \log_2(45) & 0 & \log_2(12) & 0 & \log_2(56) & 0 & {-\log_2(72)} \\ {-\log_2(30)} & {-\log_2(35)} & {-3\log_2(40)} & \log_2(45) & 0 & {-2\log_2(12)} & 2\log_2(6) & {-2\log_2(56)} & 2\log_2(63) & 4\log_2(72) \\ {-2\log_2(30)} & {-\log_2(35)} & {-2\log_2(40)} & {-2\log_2(45)} & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} 0 & 0 & 0 \\ +1 & +1 & +1 \\ +1 & 0 & 0 \\ 0 & {-1} & 0 \\ 0 & 0 & 0 \\ 0 & 0 & {-1} \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} \right] \end{array} → \\ \begin{array} {c} M\mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(35·40^2) & {-\log_2(\frac{45}{35})} & \log_2(\frac{35}{12}) \\ {-\log_2(35·40^3)} & {-\log_2(35·45)} & \log_2(\frac{12^2}{35}) \\ {-\log_2(35·40^2)} & \log_2(\frac{45^2}{35}) & {-\log_2(35)} \\ \end{array} \right] \end{array} }[/math]


And now the right side:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} \mathrm{T}C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & 0 & \log_2(40) & 0 & {-\log_2(42)} & 2\log_2(12) & {-\log_2(6)} & 3\log_2(56) & 0 & {-3\log_2(72)} \\ \log_2(30) & 0 & 0 & 2\log_2(45) & {-\log_2(42)} & {-\log_2(12)} & \log_2(6) & 0 & 2\log_2(63) & 2\log_2(72) \\ {-\log_2(30)} & {-\log_2(35)} & {-\log_2(40)} & {-\log_2(45)} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & \log_2(35) & 0 & 0 & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 \\ \end{array} \right] \end{array} \begin{array} {ccc} K \\ \left[ \begin{array} {rrr} 0 & 0 & 0 \\ +1 & +1 & +1 \\ +1 & 0 & 0 \\ 0 & {-1} & 0 \\ 0 & 0 & 0 \\ 0 & 0 & {-1} \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} \right] \end{array} → \\ \begin{array} {c} \mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & {-\log_2(12^2)} \\ 0 & {-\log_2(45^2)} & \log_2(12) \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & {-\log_2(35)} \\ \log_2(35) & \log_2(35) & \log_2(35) \\ \end{array} \right] \end{array} }[/math]


So now we can put them together as an equality, making sure to include the generator embedding that we're solving for on the left-hand side:


[math]\displaystyle{ \small \begin{array} {c} G \\ \left[ \begin{array} {c} g_{11} & g_{12} & g_{13} \\ g_{21} & g_{22} & g_{23} \\ g_{31} & g_{32} & g_{33} \\ g_{41} & g_{42} & g_{43} \\ \end{array} \right] \end{array} \begin{array} {c} M\mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(35·40^2) & {-\log_2(\frac{45}{35})} & \log_2(\frac{35}{12}) \\ {-\log_2(35·40^3)} & {-\log_2(35·45)} & \log_2(\frac{12^2}{35}) \\ {-\log_2(35·40^2)} & \log_2(\frac{45^2}{35}) & {-\log_2(35)} \\ \end{array} \right] \end{array} = \begin{array} {c} \mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & {-\log_2(12^2)} \\ 0 & {-\log_2(45^2)} & \log_2(12) \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & {-\log_2(35)} \\ \log_2(35) & \log_2(35) & \log_2(35) \\ \end{array} \right] \end{array} }[/math]


Solve for generator embedding

To solve for [math]\displaystyle{ G }[/math], we take the inverse of [math]\displaystyle{ M\mathrm{T}CK }[/math] and right-multiply both sides of the equation by it. This will cancel it out on the left-hand side, isolating [math]\displaystyle{ G }[/math]:


[math]\displaystyle{ \begin{aligned} GM\mathrm{T}CK &= \mathrm{T}CK \\ GM\mathrm{T}CK(M\mathrm{T}CK)^{-1} &= \mathrm{T}CK(M\mathrm{T}CK)^{-1} \\ G\cancel{M\mathrm{T}CK}\cancel{(M\mathrm{T}CK)^{-1}} &= \mathrm{T}CK(M\mathrm{T}CK)^{-1} \\ G &= \mathrm{T}CK(M\mathrm{T}CK)^{-1} \end{aligned} }[/math]


And now we just multiply those two things on the right-hand side together:


[math]\displaystyle{ \scriptsize \begin{array} {c} \mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & {-\log_2(12^2)} \\ 0 & {-\log_2(45^2)} & \log_2(12) \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & {-\log_2(35)} \\ \log_2(35) & \log_2(35) & \log_2(35) \\ \end{array} \right] \end{array} \begin{array} {c} (M\mathrm{T}CK)^{-1} \\ \left[ \begin{array} {c} 3\log_2(35)\log_2(45) - \log_2(12)\log_2(\frac{405}{7}) & \log_2(35)\log_2(45) - \log_2(12)\log_2(\frac{405}{7}) & 2\log_2(35)\log_2(45) - \log_2(12)\log_2(\frac{18225}{7}) \\ -\log_2(35)\log_2(40) - \log_2(144)\log_2(56000) & -\log_2(12)\log_2(56000) & -\log_2(35)\log_2(40) - \log_2(12)\log_2(1400) \\ -8\log_2(40)\log_2(45) - \log_2(35)\log_2(\frac{18225}{8}) & -\log_2(45)\log_2(56000) & -\log_2(40)\log_2(45) - \log_2(35)\log_2(\frac{405}{8}) \\ \end{array} \right] \\ \hline \log_2(\frac98)\log_2(12)\log_2(35) - \log_2(40)\log_2(45)\log_2(\frac{20736}{35}) \end{array} }[/math]


To find [math]\displaystyle{ G }[/math].


[math]\displaystyle{ \scriptsize \begin{array} {c} G \\ \left[ \begin{array} {c} g_{11} & g_{12} & g_{13} \\ g_{21} & g_{22} & g_{23} \\ g_{31} & g_{32} & g_{33} \\ g_{41} & g_{42} & g_{43} \\ \end{array} \right] \end{array} = \begin{array} {c} \mathrm{T}CK(M\mathrm{T}CK)^{-1} \\ \left[ \begin{array} {c} \begin{array} {c} 9\log_2(35)\log_2(40)\log_2(45) \\ + 2\log_2(12)\log_2(35)\log_2(\frac{18225}{8}) \\ + 2\log_2(12)\log_2(40)\log_2(86821875) \end{array} & & \begin{array} {c} 3\log_2(35)\log_2(40)\log_2(45) \\ - 3\log_2(12)\log_2(40)\log_2(\frac{405}{7}) \\ + 2\log_2(12)\log_2(45)\log_2(56000) \end{array} & & \begin{array} {c} 6\log_2(35)\log_2(40)\log_2(45) \\ + 2\log_2(35)\log_2(12)\log_2(\frac{405}{8}) \\ + \log_2(12)\log_2(40)\log_2(1929375) \end{array} \\[9pt] \begin{array} {c} 2\log_2(45)\log_2(35)\log_2(40) \\ + 3\log_2(45)\log_2(144)\log_2(56000) \\ - 8\log_2(12)\log_2(40)\log_2(45) \\ - \log_2(12)\log_2(35)\log_2(\frac{18225}{8}) \end{array} & & \begin{array} {c} \log_2(12)\log_2(45)\log_2(56000) \end{array} & & \begin{array} {c} \log_2(35)\log_2(40)\log_2(45) \\ - 5\log_2(12)\log_2(40)\log_2(45) \\ - \log_2(12)\log_2(35)\log_2(\frac{405}{8}) \\ - 2\log_2(12)\log_2(45)\log_2(1400) \end{array} \\[9pt] \begin{array} {c} \log_2(144)\log_2(40)\log_2(\frac{405}{7}) \\ - \log_2(144)\log_2(45)\log_2(56000) \\ + 4\log_2(35)\log_2(40)\log_2(45) \\ + \log_2(35)\log_2(144)\log_2(3240000) \end{array} & & \begin{array} {c} \log_2(12)\log_2(40)\log_2(\frac{405}{7}) \\ - \log_2(12)\log_2(45)\log_2(56000) \\ - \log_2(35)\log_2(40)\log_2(45) \\ + \log_2(35)\log_2(45)\log_2(56000) \\ + \log_2(12)\log_2(35)\log_2(3240000) \\ - \log_2(35)\log_2(35)\log_2(45) \end{array} & & \begin{array} {c} \log_2(12)\log_2(40)\log_2(\frac{18225}{7}) \\ + 2\log_2(35)\log_2(40)\log_2(45) \\ + \log_2(12)\log_2(35)\log_2(3645000) \\ - \log_2(12)\log_2(45)\log_2(1400) \end{array} \\[9pt] \begin{array} {c} -8\log_2(35)\log_2(40)\log_2(45) \\ -\log_2(35)\log_2(144)\log_2(3240000) \end{array} & & \begin{array} {c} \log_2(35)\log_2(35)\log_2(45) \\ - \log_2(35)\log_2(45)\log_2(5600) \\ - \log_2(12)\log_2(35)\log_2(3240000) \end{array} & & \begin{array} {c} -\log_2(35)\log_2(40)\log_2(45) \\ -\log_2(12)\log_2(35)\log_2(3645000) \end{array} \end{array}\right] \\ \hline \log_2(\frac98)\log_2(12)\log_2(35) - \log_2(40)\log_2(45)\log_2(\frac{20736}{35}) \end{array} }[/math]


Egads!

Convert generator embedding to generator map

Taking the values from the first column of this, we can find that our first generator, [math]\displaystyle{ \textbf{g}_1 }[/math], is exactly equal to:


[math]\displaystyle{ \small \sqrt[ \log_2(\frac98)\log_2(12)\log_2(35) - \log_2(40)\log_2(45)\log_2(\frac{20736}{35}) ] { \rule[15pt]{0pt}{0pt} 2^{( 9\log_2(35)\log_2(40)\log_2(45) + 2\log_2(12)\log_2(35)\log_2(\frac{18225}{8}) + 2\log_2(12)\log_2(40)\log_2(86821875) )} } \hspace{1mu} \overline{\rule[15pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[15pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[15pt]{0pt}{0pt}} \\ \quad\quad\quad \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt} · 3^{( 2\log_2(45)\log_2(35)\log_2(40) + 3\log_2(45)\log_2(144)\log_2(56000) - 8\log_2(12)\log_2(40)\log_2(45) - \log_2(12)\log_2(35)\log_2(\frac{18225}{8}) )} } \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \\ \quad\quad\quad \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt} · 5^{( \log_2(144)\log_2(40)\log_2(\frac{405}{7}) - \log_2(144)\log_2(45)\log_2(56000) + 4\log_2(35)\log_2(40)\log_2(45) + \log_2(35)\log_2(144)\log_2(3240000) )} } \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \\ \quad\quad\quad \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt}} \hspace{1mu} \overline{\rule[11pt]{0pt}{0pt} · 7^{( {-(8\log_2(35)\log_2(40)\log_2(45) + \log_2(35)\log_2(144)\log_2(3240000))} )} } }[/math]


Clearly, such an exact value is of dubious interest as is. But it may be nice for some types of personalities (including the present author) to know, theoretically speaking, that this expression gives us the truly optimal size of this generator, where the general solution would only find a close approximation. It would look a little less insane if we were using unity-weight damage, or our complexity didn't include logarithmic values.

At some point we do need to convert this to an inexact decimal form to make any practical use of it. But we should wait until the last possible moment, so as to not let rounding errors compound.

Well, this is that last possible moment. So this value works out to about 1.99847, just shy of 2, which is great because it's supposed to be a tempered octave. In cents it is 1198.679 ¢.

We won't show the exact exponential form for the other generators [math]\displaystyle{ \textbf{g}_2 }[/math] and [math]\displaystyle{ \textbf{g}_3 }[/math]; the point has been made. The practical thing to do is simply multiply this [math]\displaystyle{ G }[/math] by [math]\displaystyle{ 𝒋 }[/math], to find [math]\displaystyle{ 𝒈 }[/math]. We'll go ahead and show things in decimals now:


[math]\displaystyle{ \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200.000 & 1901.955 & 2786.314 & 3368.826 \\ \end{array} \right] \end{array} \begin{array} {ccc} G \\ \left[ \begin{array} {r} 10.156 & 2.701 & 5.530 \\ 1.831 & 1.140 & 0.306 \\ 3.662 & 1.281 & 2.612 \\ {-7.325} & {-2.561} & {-4.224} \\ \end{array} \right] \end{array} = \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} 1198.679 & 350.516 & 265.929 \\ \end{array} \right] \end{array} }[/math]


And so that's the tuning (in cents) we find for this constraint matrix! (But remember, this is only one of many candidates for the minimax tuning here—it is not necessarily the actual minimax tuning. We picked this particular ReDPOTIC / constraint matrix / coinciding-damage point / candidate tuning example basically at random.)

System of equations style

In our simpler example, we looked at our matrix equation as a system of equations. It may be instructive to consider this related approach toward this result.

Suppose instead that rather than going for a matrix solution in [math]\displaystyle{ G }[/math], we went straight for a single vector, our generator tuning map [math]\displaystyle{ 𝒈 }[/math]. In other words, we don't save the conversion from [math]\displaystyle{ G }[/math] to [math]\displaystyle{ 𝒈 }[/math] via [math]\displaystyle{ 𝒋 }[/math] to the end; we build this into our solution. So rewind back to before we did a matrix inverse, and instead we multiply each side of the equation by [math]\displaystyle{ 𝒋 }[/math]. The [math]\displaystyle{ 𝒋G }[/math] goes to [math]\displaystyle{ 𝒈 }[/math], and we just go ahead and multiply its entries [math]\displaystyle{ g_1 }[/math], [math]\displaystyle{ g_2 }[/math], and [math]\displaystyle{ g_3 }[/math] up with everything else:


[math]\displaystyle{ \begin{array} {ccc} 𝒈M\mathrm{T}CK \\ \left[ \begin{array} {rrr} 15.773g_1 & {-0.363g_1} & 1.544g_1 \\ {-21.095g_2} & {-10.621g_2} & 2.041g_2 \\ {-15.773g_3} & 5.854g_3 & {-5.129g_3} \\ \end{array} \right] \end{array} = \begin{array} {ccc} 𝒋\mathrm{T}CK \\ \left[ \begin{array} {rrr} 7318.250 & {-2600.619} & 1202.397 \\ \end{array} \right] \end{array} }[/math]


Now the columns of this can be viewed as a system of equations (so we essentially transpose everything to get this new look):


[math]\displaystyle{ \begin{array} {r} 15.773g_1 & + & {-21.095g_2} & + & {-15.773g_3} & = & 7318.250 \\ {-0.363}g_1 & + & {-10.621g_2} & + & 5.854g_3 & = & {-2600.619} \\ 1.544g_1 & + & 2.041g_2 & + & {-5.129g_3} & = & 1202.397 \\ \end{array} }[/math]


These can all be true at once now (again, before the constraint, they couldn't). The values come out to:


[math]\displaystyle{ g_1 = 1198.679 \\ g_2 = 350.516 \\ g_3 = 265.929 }[/math]


This matches what we found for [math]\displaystyle{ 𝒈 }[/math] via solving for [math]\displaystyle{ G }[/math].

The system of equations style is how Keenan's original algorithm works. The matrix inverse style is Dave's modification which may be less obvious how it works, but is capable of solving for generator embeddings.

Sanity-check

We can sanity check it if we like. This was supposed to find us the tuning of breed temperament where [math]\displaystyle{ \frac75 × \frac85 = \frac{56}{25} }[/math], [math]\displaystyle{ \frac75 × \frac59 = \frac79 }[/math] (or we might prefer to think of it in its superunison form, [math]\displaystyle{ \frac97 }[/math]), and [math]\displaystyle{ \frac75 × \frac34 = \frac{21}{20} }[/math] are pure.

Well, breed maps [math]\displaystyle{ \textbf{i}_1 = \frac{56}{25} }[/math] [3 0 -2 1⟩ to the generator-count vector [math]\displaystyle{ \textbf{y}_1 }[/math] [3 -4 -3}. And [math]\displaystyle{ 𝒈\textbf{y}_1 }[/math] looks like {1198.679 350.516 265.929][3 -4 -3} [math]\displaystyle{ = 1198.679 × 3 + 350.516 x {-4} + 265.929 × {-3} = 1396.186 }[/math]. Its JI size is [math]\displaystyle{ 1200 × \log_2(\frac{56}{25}) = 1396.198 }[/math] which is pretty close; close enough, perhaps, given all the rounding errors we were accumulating.

And breed maps [math]\displaystyle{ \textbf{i}_2 = \frac{9}{7} }[/math] [0 2 0 -1⟩ to the generator-count vector [math]\displaystyle{ \textbf{y}_2 }[/math] [0 2 -1}. And [math]\displaystyle{ 𝒈\textbf{y}_2 }[/math] looks like {1198.679 350.516 265.929][0 2 -1} [math]\displaystyle{ = 1198.679 × 0 + 350.516 × 2 + 265.929 × {-1} = 435.103 }[/math]. Its JI size is [math]\displaystyle{ 1200 × \log_2(\frac97) = 435.084 }[/math], also essentially pure.

Finally breed maps [math]\displaystyle{ \textbf{i}_3 = \frac{21}{20} }[/math] [-2 1 -1 1⟩ to the generator-count vector [math]\displaystyle{ \textbf{y}_3 }[/math] [0 1 -1}. And [math]\displaystyle{ 𝒈\textbf{y}_3 }[/math] looks like {1198.679 350.516 265.929][0 1 -1} [math]\displaystyle{ = 1198.679 × 0 + 350.516 × 1 + 265.929 × {-1} = 84.587 }[/math]. Its JI size is [math]\displaystyle{ 1200 × \log_2(\frac{21}{20}) = 84.467 }[/math], again, essentially pure.

Relation to only-held intervals method and zero-damage method

Note that this [math]\displaystyle{ G = \mathrm{T}CK(M\mathrm{T}CK)^{-1} }[/math] formula is the same thing as the [math]\displaystyle{ G = U(MU)^{-1} }[/math] formula used for the only held-intervals method; it's just that formula where [math]\displaystyle{ \mathrm{U} = \mathrm{T}CK }[/math]. In other words, we will find a basis for the unchanged intervals of this tuning of this temperament to be:


[math]\displaystyle{ \begin{array} {c} \mathrm{U} = \mathrm{T}CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & {-\log_2(12^2)} \\ 0 & {-\log_2(45^2)} & \log_2(12) \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & {-\log_2(35)} \\ \log_2(35) & \log_2(35) & \log_2(35) \\ \end{array} \right] \end{array} }[/math]


Owing to our choice to weight our absolute error to obtain damage, these intervals are quite strange. Not only do we have non-integer entries in our prime-count vectors here, we've gone beyond the rational entries we often find for generator embeddings and unchanged-interval bases, etc. and now have irrational entries with freaking logarithms in them. So these aren't particularly insight-giving unchanged-intervals, but they are what they are.

So, in effect, the coinciding-damage method is fairly similar to the zero-damage method. Each point in either method's point set corresponds to an unchanged-interval basis [math]\displaystyle{ \mathrm{U} }[/math]. It is the case that for the zero-damage method the members of this [math]\displaystyle{ \mathrm{U} }[/math] are pulled directly from the target-interval set [math]\displaystyle{ \mathrm{T} }[/math], whereas for the coinciding-damage method here, the members of each [math]\displaystyle{ \mathrm{U} }[/math] have a more complex relationship with the members of [math]\displaystyle{ \mathrm{T} }[/math] set, being products of relative direction pairs of them instead.

With held-intervals

When a tuning scheme has optimization power [math]\displaystyle{ p = ∞ }[/math] and also specifies one or more held-intervals, we can adapt the coinciding-damage method to accommodate this. In short, we can no longer dedicate every generator toward our target-intervals; we must allocate one generator toward each interval to be held unchanged.

Counts of target-intervals with held-intervals

In the earlier section Generalizing to higher dimensions: Counts of target-intervals required to make the points, we looked at how it generally takes [math]\displaystyle{ r + 1 }[/math] target-interval damage graphs to intersect to make a point, but only [math]\displaystyle{ r }[/math] of them on the zero-damage floor.

When there are held-intervals, however, things get a little trickier.

Each additional held-interval added is like taking a cross-section through the tuning damage space, specifically, the cross-section wherever that interval is held unchanged. Tuning damage space is still [math]\displaystyle{ (r + 1) }[/math]-dimensional, but now we only care about a slice through that space, a slice with [math]\displaystyle{ h }[/math] fewer dimensions. That is, it'll be a [math]\displaystyle{ (r + 1 - h) }[/math]-dimensional slice. And within this slice, then, we only need [math]\displaystyle{ r + 1 - h }[/math] target-intervals' damages to coincide to make a point, and only [math]\displaystyle{ r - h }[/math] of them to make a point on the floor.

For example, when tuning an octave-fifth form of meantone temperament, we'd know we'd be searching a 3D tuning damage space, with one floor axis for [math]\displaystyle{ g_1 }[/math] in the vicinity of 1200 ¢ and the other floor axis for [math]\displaystyle{ g_2 }[/math] in the vicinity of 701.955 ¢. But if we say it's a held-octave tuning we want, then while all of our target-interval's hyper-V's are still exactly as they were, fully occupying the three dimensions of this space, but now we only care about the 2D slice through it where [math]\displaystyle{ g_1 = 1200 }[/math].

In that very simple example, only one of the temperament's generators was involved in the mapped interval that the held-interval maps to, so the cross-section is conveniently perpendicular to the axis for that generator, and thus the tuning damage graph with reduced dimension is easy to prepare. However, if we had instead requested a held-{5/4}, then since that maps to [-2 4}, using multiple different generators, then the cross-section will be diagonal across the floor, perpendicular to no generator axes.

Modified constraint matrices

We do this by changing our constraint matrices [math]\displaystyle{ K }[/math]; rather than building them to represent permutations of relative direction for combinations of [math]\displaystyle{ r + 1 }[/math] target-intervals, instead we only combine [math]\displaystyle{ r + 1 - h }[/math] target-intervals for each of these constraint matrices, where [math]\displaystyle{ h }[/math] is the count of held-intervals. As a result of this, each [math]\displaystyle{ K }[/math] has [math]\displaystyle{ h }[/math] fewer columns than before—or at least it would, if we didn't replace these columns with [math]\displaystyle{ h }[/math] new columns, one for each of our [math]\displaystyle{ h }[/math] held-intervals. Remember, each of these constraint matrices gets multiplied together with other matrices that represent information about our temperament and tuning scheme—our targeted intervals, and their weights (if any)—in order to take a system of approximations (represented by matrices) and crunch it down to a smaller system of equalities (still represented by matrices) that can be automatically solved (using a matrix inverse). So, instead of these constraint matrices doing only a single job—enforcing that [math]\displaystyle{ r + 1 }[/math] target-intervals receive coinciding damage, each constraint matrix now handles two jobs at once—enforcing that only [math]\displaystyle{ r + 1 - h }[/math] target-intervals receive coinciding damage, and that [math]\displaystyle{ h }[/math] held-intervals receive zero damage.

In order for the constraint matrices to handle their new second job, however, we must make further changes. The held-intervals must now be accessible in the other matrices that multiply together to form our solvable system of equations. In particular:

  1. We concatenate the target-interval list [math]\displaystyle{ \mathrm{T} }[/math] and the held-interval basis [math]\displaystyle{ \mathrm{H} }[/math] together to a new matrix [math]\displaystyle{ \mathrm{T}|\mathrm{H} }[/math].
  2. We accordingly extend the weight matrix [math]\displaystyle{ W }[/math] diagonally so that matrix shapes work out for multiplication purposes, or said another way, so that each held-interval appended to [math]\displaystyle{ \mathrm{T} }[/math] gets matched up with a dummy weight.[note 3]

Prepare constraint matrix

Let's demonstrate this by example. We'll revise the example we looked at in the earlier "bigger example" section, with 3 generators ([math]\displaystyle{ r = 3 }[/math]) and 10 target-intervals ([math]\displaystyle{ k = 10 }[/math]). The specific example constraint matrix we looked at, therefore, was an [math]\displaystyle{ (k, r) }[/math]-shaped matrix, which related [math]\displaystyle{ r + 1 = 4 }[/math] of those target-intervals together with coinciding damage:


[math]\displaystyle{ \begin{array} {rrr} \scriptsize{6/5} \\ \scriptsize{7/5} \\ \scriptsize{8/5} \\ \scriptsize{9/5} \\ \scriptsize{7/6} \\ \scriptsize{4/3} \\ \scriptsize{3/2} \\ \scriptsize{8/7} \\ \scriptsize{9/7} \\ \scriptsize{9/8} \\ \end{array} \left[ \begin{array} {rrr} 0 & 0 & 0 \\ +1 & +1 & +1 \\ +1 & 0 & 0 \\ 0 & {-1} & 0 \\ 0 & 0 & 0 \\ 0 & 0 & {-1} \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} \right] }[/math]


For a tuning scheme with [math]\displaystyle{ h = 1 }[/math], however, we can only get three target-intervals to have coinciding damage at the same time. So we'd never see this constraint matrix for such a scheme. Instead, any example constraint matrix we'd pick would only have two such rows. In order to keep working with something similar to this example, then, let's just drop the last column:


[math]\displaystyle{ \begin{array} {rrr} \scriptsize{6/5} \\ \scriptsize{7/5} \\ \scriptsize{8/5} \\ \scriptsize{9/5} \\ \scriptsize{7/6} \\ \scriptsize{4/3} \\ \scriptsize{3/2} \\ \scriptsize{8/7} \\ \scriptsize{9/7} \\ \scriptsize{9/8} \\ \end{array} \left[ \begin{array} {rrr} 0 & 0 \\ +1 & +1 \\ +1 & 0 \\ 0 & {-1} \\ 0 & 0 \\ 0 & 0 \\ 0 & 0 \\ 0 & 0 \\ 0 & 0 \\ 0 & 0 \\ \end{array} \right] }[/math]


But we still want a third column; we still have [math]\displaystyle{ r = 3 }[/math] generators in this example. But now we need to specify that one of these generators needs to accomplish the job of tuning our held-interval exactly. We do that by adding a column that's all zeros except for a single nonzero entry in the row for that held-interval (if it's not clear how this enforces that interval to be unchanged, don't worry; it will become clear in a later step when we translate this system of matrices to the system of linear equations which it is essentially shorthand notation for):


[math]\displaystyle{ \begin{array} {rrr} \scriptsize{6/5} \\[2pt] \scriptsize{7/5} \\[2pt] \scriptsize{8/5} \\[2pt] \scriptsize{9/5} \\[2pt] \scriptsize{7/6} \\[2pt] \scriptsize{4/3} \\[2pt] \scriptsize{3/2} \\[2pt] \scriptsize{8/7} \\[2pt] \scriptsize{9/7} \\[2pt] \scriptsize{9/8} \\[2pt] \style{background-color:#FFF200;padding:5px}{\scriptsize{5/3}} \\[2pt] \end{array} \left[ \begin{array} {rrr} 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ +1 & +1 & \style{background-color:#FFF200;padding:5px}{0}\\ +1 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & {-1} & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{1} \\ \end{array} \right] }[/math]


Oh, right—we didn't have a row for this held-interval yet. All the rows we had before were for our target-intervals. No big deal, though. We just added an extra row for this, our held-interval, and we can fill out the new entries it creates in the other columns with zeros.

Modified tempered and just sides of to-be equality

The consequences of adding this row are more far-reaching than our [math]\displaystyle{ K }[/math] matrices, however. Remember, these multiply with [math]\displaystyle{ M\mathrm{T}C }[/math] on the left-hand side of the equal sign and [math]\displaystyle{ \mathrm{T}C }[/math] on the right-hand side. So matrix shapes have to keep matching for matrix multiplication to remain possible. We just changed the shape of [math]\displaystyle{ K }[/math] from an [math]\displaystyle{ (k, r) }[/math]-shaped matrix to a [math]\displaystyle{ (k + h, r) }[/math]-shaped matrix. The shape of [math]\displaystyle{ M\mathrm{T}C }[/math] is [math]\displaystyle{ (r, k) }[/math] and the shape of [math]\displaystyle{ \mathrm{T}C }[/math] is [math]\displaystyle{ (d, k) }[/math]. So if we want these shapes to keep matching, we need to change them to [math]\displaystyle{ (r, k + h) }[/math] and [math]\displaystyle{ (d, k + h) }[/math], respectively.

Now that's a rather dry way of putting it. Let's put it in more natural terms. We know what these additions to [math]\displaystyle{ M\mathrm{T}C }[/math] and [math]\displaystyle{ \mathrm{T}C }[/math] are about: they're the held-intervals that the new entries we added to the constraint matrices are referring to! In particular, we need to expand [math]\displaystyle{ \mathrm{T} }[/math] (the actual target-intervals we chose here are arbitrary and don't really matter for this example):


[math]\displaystyle{ \begin{array} {ccc} \mathrm{T} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 \\ \end{array} \right] \end{array} }[/math]


to include the held-intervals. We can just tack them on at the end. We said [math]\displaystyle{ h = 1 }[/math], that is, that we only have one held-interval, but we haven't picked what it is yet. This is also arbitrary for this example. How about we go with [math]\displaystyle{ \frac53 }[/math], with prime-count vector [0 -1 1 0⟩:


[math]\displaystyle{ \begin{array} {ccc} \mathrm{T|\style{background-color:#FFF200;padding:2px}{H}} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} & \style{background-color:#FFF200;padding:5px}{0} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 & \style{background-color:#FFF200;padding:5px}{-1} \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 & \style{background-color:#FFF200;padding:5px}{1} \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} }[/math]


We've got to extend [math]\displaystyle{ C }[/math] too. We can pick any weight we want, other than 0. You'll see why when we work out the system of equations in a moment):


[math]\displaystyle{ \begin{array} {ccc} C \\ \text{diag}(\log_2(\left[ \begin{array} {rrr} 30 & 35 & 40 & 45 & 42 & 12 & 6 & 56 & 63 & 72 & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right])) \end{array} }[/math]


(Note that the last entry appears as 2 here, because we placed the [math]\displaystyle{ \log_2 }[/math] outside the array brackets.)

There's no need to mess with [math]\displaystyle{ M }[/math] here.

Prepare tempered and just sides of to-be equality

As before, let's work out [math]\displaystyle{ M\mathrm{T}C }[/math] and [math]\displaystyle{ \mathrm{T}C }[/math] separately, then constrain each of them with [math]\displaystyle{ K }[/math], then put them together in a linear system of equations, solving for the generator tuning map [math]\displaystyle{ 𝒈 }[/math]. Though this time around, all occurrences of [math]\displaystyle{ \mathrm{T} }[/math] will be replaced with [math]\displaystyle{ \mathrm{T|\style{background-color:#FFF200;padding:2px}{H}} }[/math].

First, [math]\displaystyle{ M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C }[/math]:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} M \\ \left[ \begin{array} {rrr} 1 & 1 & 1 & 2 \\ 0 & 2 & 3 & 2 \\ 0 & 0 & 2 & 1 \end{array} \right] \end{array} \begin{array} {ccc} \mathrm{T|\style{background-color:#FFF200;padding:2px}{H}} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} & \style{background-color:#FFF200;padding:5px}{0} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 & \style{background-color:#FFF200;padding:5px}{-1} \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 & \style{background-color:#FFF200;padding:5px}{1} \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} \begin{array} {ccc} C \\ \text{diag}(\log_2(\left[ \begin{array} {rrr} 30 & 35 & 40 & 45 & 42 & 12 & 6 & 56 & 63 & 72 & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right])) \end{array} }[/math]


Which works out to:


[math]\displaystyle{ \small \begin{array} {ccc} M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & \log_2(35) & 2\log_2(40) & \log_2(45) & 0 & \log_2(12) & 0 & \log_2(56) & 0 & {-\log_2(72)} & \style{background-color:#FFF200;padding:5px}{0} \\ {-\log_2(30)} & {-\log_2(35)} & {-3\log_2(40)} & \log_2(45) & 0 & {-2\log_2(12)} & 2\log_2(6) & {-2\log_2(56)} & 2\log_2(63) & 4\log_2(72) & \style{background-color:#FFF200;padding:5px}{1} \\ {-2\log_2(30)} & {-\log_2(35)} & {-2\log_2(40)} & {-2\log_2(45)} & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right] \end{array} }[/math]


So that's the same as before, but with the extra column at the right, which is alone in having integer entries owing to its weight being the integer 1. What we're seeing there is that [0 -1 1 0⟩ maps to [0 1 2} in this temperament, that's all.

Now, we do [math]\displaystyle{ (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C }[/math]:


[math]\displaystyle{ \small \begin{array} {ccc} \mathrm{T|\style{background-color:#FFF200;padding:2px}{H}} \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r|r|r} 1 & 0 & 3 & 0 & {-1} & 2 & {-1} & 3 & 0 & {-3} & \style{background-color:#FFF200;padding:5px}{0} \\ 1 & 0 & 0 & 2 & {-1} & {-1} & 1 & 0 & 2 & 2 & \style{background-color:#FFF200;padding:5px}{-1} \\ {-1} & {-1} & {-1} & {-1} & 0 & 0 & 0 & 0 & 0 & 0 & \style{background-color:#FFF200;padding:5px}{1} \\ 0 & 1 & 0 & 0 & 1 & 0 & 0 & {-1} & {-1} & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} \begin{array} {ccc} C \\ \text{diag}(\log_2(\left[ \begin{array} {rrr} 30 & 35 & 40 & 45 & 42 & 12 & 6 & 56 & 63 & 72 & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right])) \end{array} = \\[50pt] \small \begin{array} {ccc} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & 0 & \log_2(40) & 0 & {-\log_2(42)} & 2\log_2(12) & {-\log_2(6)} & 3\log_2(56) & 0 & {-3\log_2(72)} & \style{background-color:#FFF200;padding:5px}{0} \\ \log_2(30) & 0 & 0 & 2\log_2(45) & {-\log_2(42)} & {-\log_2(12)} & \log_2(6) & 0 & 2\log_2(63) & 2\log_2(72) & \style{background-color:#FFF200;padding:5px}{-1} \\ {-\log_2(30)} & {-\log_2(35)} & {-\log_2(40)} & {-\log_2(45)} & 0 & 0 & 0 & 0 & 0 & 0 & \style{background-color:#FFF200;padding:5px}{1} \\ 0 & \log_2(35) & 0 & 0 & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} }[/math]


Again, same as before, but with one more column on the right now.

Apply constraint

Now, let's constrain both sides. First, the left side:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & \log_2(35) & 2\log_2(40) & \log_2(45) & 0 & \log_2(12) & 0 & \log_2(56) & 0 & {-\log_2(72)} & \style{background-color:#FFF200;padding:5px}{0} \\ {-\log_2(30)} & {-\log_2(35)} & {-3\log_2(40)} & \log_2(45) & 0 & {-2\log_2(12)} & 2\log_2(6) & {-2\log_2(56)} & 2\log_2(63) & 4\log_2(72) & \style{background-color:#FFF200;padding:5px}{1} \\ {-2\log_2(30)} & {-\log_2(35)} & {-2\log_2(40)} & {-2\log_2(45)} & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right] \end{array} \begin{array} {c} K \\ \left[ \begin{array} {rrr} 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ +1 & +1 & \style{background-color:#FFF200;padding:5px}{0}\\ +1 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & {-1} & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{1} \\ \end{array} \right] \end{array} → \\ \begin{array} {c} M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {c} \log_2(35·40^2) & {-\log_2(\frac{45}{35})} & \style{background-color:#FFF200;padding:5px}{0} \\ {-\log_2(35·40^3)} & {-\log_2(35·45)} & \style{background-color:#FFF200;padding:5px}{1} \\ {-\log_2(35·40^2)} & \log_2(\frac{45^2}{35}) & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right] \end{array} }[/math]


Same as before, with the rightmost column replaced with a column for our held-interval.

And now the right side:


[math]\displaystyle{ \scriptsize \begin{array} {ccc} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})C \\ \left[ \begin{array} {r|r|r|r|r|r|r|r|r} \log_2(30) & 0 & \log_2(40) & 0 & {-\log_2(42)} & 2\log_2(12) & {-\log_2(6)} & 3\log_2(56) & 0 & {-3\log_2(72)} & \style{background-color:#FFF200;padding:5px}{0} \\ \log_2(30) & 0 & 0 & 2\log_2(45) & {-\log_2(42)} & {-\log_2(12)} & \log_2(6) & 0 & 2\log_2(63) & 2\log_2(72) & \style{background-color:#FFF200;padding:5px}{-1} \\ {-\log_2(30)} & {-\log_2(35)} & {-\log_2(40)} & {-\log_2(45)} & 0 & 0 & 0 & 0 & 0 & 0 & \style{background-color:#FFF200;padding:5px}{1} \\ 0 & \log_2(35) & 0 & 0 & \log_2(42) & 0 & 0 & {-\log_2(56)} & {-\log_2(63)} & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} \begin{array} {c} K \\ \left[ \begin{array} {rrr} 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ +1 & +1 & \style{background-color:#FFF200;padding:5px}{0}\\ +1 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & {-1} & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ 0 & 0 & \style{background-color:#FFF200;padding:5px}{0}\\ \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{0} & \style{background-color:#FFF200;padding:5px}{1} \\ \end{array} \right] \end{array} → \\ \begin{array} {c} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & {-\log_2(45^2)} & \style{background-color:#FFF200;padding:5px}{{-1}} \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & \style{background-color:#FFF200;padding:5px}{1} \\ \log_2(35) & \log_2(35) & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} }[/math]


Again, same as before, but with the rightmost column replaced with a column for our held-interval.

Now, put them together, with [math]\displaystyle{ G }[/math] on the left-hand side, as an equality:


[math]\displaystyle{ \small \begin{array} {c} G \\ \left[ \begin{array} {c} g_{11} & g_{12} & g_{13} \\ g_{21} & g_{22} & g_{23} \\ g_{31} & g_{32} & g_{33} \\ g_{41} & g_{42} & g_{43} \\ \end{array} \right] \end{array} \begin{array} {c} M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {c} \log_2(35·40^2) & {-\log_2(\frac{45}{35})} & \style{background-color:#FFF200;padding:5px}{0} \\ {-\log_2(35·40^3)} & {-\log_2(35·45)} & \style{background-color:#FFF200;padding:5px}{1} \\ {-\log_2(35·40^2)} & \log_2(\frac{45^2}{35}) & \style{background-color:#FFF200;padding:5px}{2} \\ \end{array} \right] \end{array} = \begin{array} {c} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {c} \log_2(40^3) & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & {-\log_2(45^2)} & \style{background-color:#FFF200;padding:5px}{{-1}} \\ {-\log_2(35·40)} & \log_2(\frac{45}{35}) & \style{background-color:#FFF200;padding:5px}{1} \\ \log_2(35) & \log_2(35) & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} }[/math]

Solve for generator embedding

At this point, following the pattern from above, we can solve for [math]\displaystyle{ G }[/math] as [math]\displaystyle{ (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK(M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK)^{-1} }[/math]. The matrix inverse is the step where the exact values in terms of logarithms start to get out of hand. Since we've already proven our point about exactness of the solutions from this method in the earlier "bigger example" section, for easier reading, let's lapse into decimal numbers from this point forward:


[math]\displaystyle{ \begin{array} {c} G \\ \left[ \begin{array} {c} g_{11} & g_{12} & g_{13} \\ g_{21} & g_{22} & g_{23} \\ g_{31} & g_{32} & g_{33} \\ g_{41} & g_{42} & g_{43} \\ \end{array} \right] \end{array} = \begin{array} {ccc} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {rrr} 15.966 & 0 & \style{background-color:#FFF200;padding:5px}{0} \\ 0 & {-10.984} & \style{background-color:#FFF200;padding:5px}{{-1}} \\ {-10.451} & 0.363 & \style{background-color:#FFF200;padding:5px}{1} \\ 5.129 & 5.129 & \style{background-color:#FFF200;padding:5px}{0} \\ \end{array} \right] \end{array} \begin{array} {ccc} (M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK)^{-1} \\ \left[ \begin{array} {rrr} {-27.097} & 0.725 & {-0.363} \\ 26.417 & 31.546 & {-15.773} \\ \style{background-color:#FFF200;padding:5px}{{-291.028}} & \style{background-color:#FFF200;padding:5px}{{-86.624}} & \style{background-color:#FFF200;padding:5px}{{-175.177}} \\ \end{array} \right] \\ \hline {-436.978} \end{array} }[/math]


Note where the yellow-highlights went: inversing transposed them from the rightmost column to the bottom row. It's no longer super clear what these values have to do with the held-interval anymore, however, and that's okay. In the next step, notice that when we multiply together [math]\displaystyle{ (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK }[/math] and [math]\displaystyle{ (M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK)^{-1} }[/math] that the yellow-highlighted entries will pair up for every individual dot products, and thus that the final matrix product will have a "little bit of yellow" mixed in to every entry. In other words, every entry of [math]\displaystyle{ G }[/math] may potentially participate in achieving the effect that this interval is held unchanged.

So, actually multiplying those up now, we find [math]\displaystyle{ G }[/math] =


[math]\displaystyle{ \begin{array} {c} (\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK(M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK)^{-1} \\ \left[ \begin{array} {c} 0.990 & {-0.0265} & {0.0132} \\ {-0.00199} & 0.595 & {-0.797} \\ {-0.00399} & 0.189 & 0.405 \\ 0.00798 & {-0.379} & 0.189 \\ \end{array} \right] \\ \end{array} }[/math]


Convert generator embedding to generator tuning map

And from here we can find [math]\displaystyle{ 𝒈 = 𝒋G }[/math]:


[math]\displaystyle{ \begin{array} {ccc} 𝒋 \\ \left[ \begin{array} {rrr} 1200.000 & 1901.955 & 2786.314 & 3368.826 \\ \end{array} \right] \end{array} \begin{array} {c} G \\ \left[ \begin{array} {c} 0.990 & {-0.0265} & {0.0132} \\ {-0.00199} & 0.595 & {-0.797} \\ {-0.00399} & 0.189 & 0.405 \\ 0.00798 & {-0.379} & 0.189 \\ \end{array} \right] \end{array} = \begin{array} {ccc} 𝒈 \\ \left[ \begin{array} {rrr} 1200.000 & 350.909 & 266.725 \\ \end{array} \right] \end{array} }[/math]


Confirming: yes, {1200.000 350.909 266.725][0 1 2} = [math]\displaystyle{ (1200.000 × 0) + (350.909 × 1) + (266.725 × 2) = 0 + 350.909 + 533.450 = 884.359 }[/math]. So the constraint to hold that interval unchanged has been satisfied.

System of equations style

It may be instructive again to consider the system of equations style, solving directly for [math]\displaystyle{ 𝒈 }[/math]. Rewinding to before we took our matrix inverse, introducing [math]\displaystyle{ 𝒋 }[/math] to both sides, and multiplying the entries of [math]\displaystyle{ 𝒈 }[/math] through, we find:


[math]\displaystyle{ \begin{array} {ccc} 𝒈M(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {rrr} 15.773g_1 & {-0.363g_1} & \style{background-color:#FFF200;padding:5px}{0g_1} \\ {-21.095g_2} & {-10.621g_2} & \style{background-color:#FFF200;padding:5px}{1g_2} \\ {-15.773g_3} & 5.854g_3 & \style{background-color:#FFF200;padding:5px}{2g_3} \\ \end{array} \right] \end{array} = \begin{array} {ccc} 𝒋(\mathrm{T|\style{background-color:#FFF200;padding:2px}{H}})CK \\ \left[ \begin{array} {rrr} 7318.250 & {-2600.619} & \style{background-color:#FFF200;padding:5px}{884.359} \\ \end{array} \right] \end{array} }[/math]


Which gets viewed as a system of equations:


[math]\displaystyle{ \begin{array} {r} 15.773g_1 & + & {-21.095g_2} & + & {-15.773g_3} & = & 7318.250 \\ {-0.363}g_1 & + & {-10.621g_2} & + & 5.854g_3 & = & {-2600.619} \\ \style{background-color:#FFF200;padding:5px}{0g_1} & + & \style{background-color:#FFF200;padding:5px}{1g_2} & + & \style{background-color:#FFF200;padding:5px}{2g_3} & = & \style{background-color:#FFF200;padding:5px}{884.359} \\ \end{array} }[/math]


The third equation—which in the earlier "bigger example" was used to enforce that a fourth target-interval received coinciding damage to the other three target-intervals tapped by the constraint matrix—here has been replaced with an equation that enforces that [0 1 2}, the generator-count vector that [math]\displaystyle{ \frac53 }[/math] maps to in this temperament, is equal to the just tuning of that same interval. And so, when we solve this system of equations, we now get a completely different set of generator tunings.


[math]\displaystyle{ g_1 = 1200.000 \\ g_2 = 350.909 \\ g_3 = 266.725 \\ }[/math]


Which agrees with what we found by solving directly for [math]\displaystyle{ G }[/math].

Sanity-check

But is this a minimax tuning candidate still? That is, do we find that in the damage list for this tuning, that the three target-intervals whose damages were requested to coincide, are still coinciding? Indeed we do:


[math]\displaystyle{ \begin{array} {c} \textbf{d} \\ \left[ \begin{array} {r} 0.007 & 0.742 & 0.742 & 0.742 & 0.788 & 0.495 & 0.353 & 1.650 & 0.057 & 1.694 \\ \end{array} \right] \end{array} }[/math]


We can see that the 2nd, 3rd, and 4th target-intervals, the ones with non-zero entries in their columns of [math]\displaystyle{ K }[/math], all coincide with 0.742 damage, so this is a proper candidate for minimax tuning here. It's some point where three damage graphs are intersecting while within the held-interval plane. Rinse and repeat.

For all-interval tuning schemes

When computing an all-interval tuning where the dual norm power is [math]\displaystyle{ ∞ }[/math], we use a variation on the method we used for ordinary tunings when the optimization power was [math]\displaystyle{ ∞ }[/math].

In this case, our optimization power is also still [math]\displaystyle{ ∞ }[/math]. That is to say, that in this case we're doing the same computation we would have been doing if we had a finite target-interval set, but now we're doing it as if the primes alone were our target-interval set.

Let's get the minimax-S tuning of meantone. With three proxy target-intervals and two generators, we end up with four constraint matrices:


[math]\displaystyle{ \left[ \begin{array} {rrr} +1 & +1 \\ +1 & 0 \\ 0 & +1 \\ \end{array} \right] , \left[ \begin{array} {rrr} +1 & +1 \\ +1 & 0 \\ 0 & {-1} \\ \end{array} \right] , \left[ \begin{array} {rrr} +1 & +1 \\ {-1} & 0 \\ 0 & +1 \\ \end{array} \right] , \left[ \begin{array} {rrr} +1 & +1 \\ {-1} & 0 \\ 0 & {-1} \\ \end{array} \right] }[/math]


These correspond to tunings with the following pairs (one for each generator) of unchanged-intervals:

  1. [math]\displaystyle{ (\frac21)^1 × (\frac31)^1 = \frac61 }[/math] and [math]\displaystyle{ (\frac21)^1 × (\frac51)^1 = \frac{10}{1} }[/math]
  2. [math]\displaystyle{ (\frac21)^1 × (\frac31)^1 = \frac61 }[/math] and [math]\displaystyle{ (\frac21)^1 × (\frac51)^{-1} = \frac{2}{5} }[/math]
  3. [math]\displaystyle{ (\frac21)^1 × (\frac31)^{-1} = \frac23 }[/math] and [math]\displaystyle{ (\frac21)^1 × (\frac51)^1 = \frac{10}{1} }[/math]
  4. [math]\displaystyle{ (\frac21)^1 × (\frac31)^{-1} = \frac23 }[/math] and [math]\displaystyle{ (\frac21)^1 × (\frac51)^{-1} = \frac{2}{5} }[/math]

Which in turn become the following tunings:

  1. ⟨1202.682 695.021]
  2. ⟨1201.699 697.564]
  3. ⟨1195.387 699.256]
  4. ⟨0.000 0.000] (Yup, not kidding. This tuning is probably not going to win…)

And these in turn give the following prime absolute error lists (for each list, all three primes have coinciding absolute scaled errors, because minimax tunings lead to [math]\displaystyle{ r + 1 }[/math] of them coinciding):

  1. ⟨2.682 2.682 2.682]
  2. ⟨1.699 1.699 1.699]
  3. ⟨4.613 4.613 4.613]
  4. ⟨1200.000 1200.000 1200.000]

And so our second tuning wins, and that's our minimax-S tuning of meantone.

Footnotes

  1. ↑ See https://yahootuninggroupsultimatebackup.github.io/tuning-math/topicId_20405.html and https://yahootuninggroupsultimatebackup.github.io/tuning-math/topicId_21022.html
  2. ↑ were everything transposed, anyway; a superficial issue
  3. ↑ This weight is irrelevant, since these aren't really target-intervals, they're held-intervals, and so the damage to them must be 0; we can choose any value for this weight other than 0 and the effect will be the same, so we may as well choose 1).