Recursive structure of MOS scales

From Xenharmonic Wiki
Jump to navigation Jump to search
This page assumes the reader is familiar with the concept of MOS scales.

This page discusses recursive properties of MOS scales.

Recursive structure

Chunking operation

Let w be an arbitrary moment-of-symmetry scale in either its brightest mode (where L's come before s's) or darkest mode (where s's come before L's). Let x be the number of L's in the scale and let y be the number of s's in the scale. Such a scale will fall under one of three general cases or one of three special cases described below.

General cases

  • Case 1: The scale is a single-period moment-of-symmetry scale where there are more L's than s's, and there is more than one s (or x > y > 1). Scale w can broken up into y substrings (or chunks) where each substring contains at least one L and exactly one s. Among these chunks, there are two unique chunks whose sizes differ by exactly one L: the larger of the two contains ceil(x/y) L's and exactly one s, and the smaller of the two contains floor(x/y) L's and exactly one s.
  • Case 2: The scale is a single-period moment-of-symmetry scale where there are more s's than L's, and there is more than one L (or y > x > 1). Scale w can broken up into x substrings (or chunks) where each substring contains at least one s and exactly one L. Among these chunks, there are two unique chunks whose sizes differ by exactly one s: the larger of the two contains ceil(y/x) s's and exactly one L, and the smaller of the two contains floor(y/x) s's and exactly one L.
  • Case 3: The scale is a multi-period moment-of-symmetry scale. Because a multi-period scale consists of a single MOS-like chunk that's repeated throughout the scale, x and y necessarily share a common factor c, where c is the greatest common factor of x and y, and c is the number of times that chunk is repeated. Therefore, when considering a multi-period moment-of-symmetry scale, only the first chunk, the first (x+y)/c steps of the scale, needs to be considered. This chunk will fall under case 1 or case 2, or one of the special cases.

Special cases

  • The special case for case 1 is when there is only one s in the scale. The scale is a moment-of-symmetry scale where the entire scale is considered to be one chunk.
  • The special case for case 2 is when there is only one L in the scale. The scale is a moment-of-symmetry scale where the entire scale is considered to be one chunk.
  • There is a third special case where there is exactly one L and one s in the scale, producing "Ls" or "sL". Technically speaking, it's possible to reduce the previous two special cases even further into this special case.

In both case 1 and 2, the L's and s's are distributed such that they are maximally even (that is, they are distributed as evenly as possible), but the chunks of L's and s's are arranged so that they too are maximally even. This can be demonstrated by reducing the larger chunks into L and the smaller chunks into s. This produces a new scale W that is also a moment-of-symmetry scale. This process can be repeated multiple times until the scale is reduced into one of the special cases. In case 3, it is possible to reduce a multi-period scale until it consists of a single unique MOS-like chunk repeated c times, where that chunk is one of the special cases.

Note that in this reduction process, the order of L's and s's may reverse. This is normal.

Reversing the reduction rules into production rules

Just as reducing a moment-of-symmetry scale using the aforementioned process produces another moment-of-symmetry scale, reversing the reduction rules into production rules will produce another scale w' that is also a moment-of-symmetry scale. One of the following sets of production rules can be used:

  • L -> LL...LLs (n+1 L's and one s), s -> LL...LLs (n L's and one s)
  • L -> ss...ssL (n+1 s's and one L), s -> ss...ssL (n s's and one L)
  • L -> Ls, s -> s (a special case of the first set of productions rules where n = 0)
  • L -> sL, s -> L (a special case of the second set of productions rules where n = 0)

Repeating these production rules will produce a scale that is more chromatic than the last, and every scale produced this way is another moment-of-symmetry scale.

The recursive nature of moment-of-symmetry scales allows for two algorithms to be made: one that can determine whether an arbitrary scale of large and small steps is a valid moment-of-symmetry scale and another that can construct a moment-of-symmetry scale from any number of large and small steps, without any prior knowledge of the scale's structure.

Determining whether a scale has the MOS property

General algorithm

Stepwise version

This is the general algorithm for determining whether a scale is maximally even (that is, it is a valid MOS). This version of the algorithm that uses the production rules in reverse: L -> Ls and s ->s; and L -> sL and s -> L. It is required to perform this on the string that represents the scale in its brightest mode. This algorithm is recursive.

  1. Count how many L's and s's there are within the string. Let x be the number of L's and y be the number of s's. One of two situations will happen:
    1. If both x and y are equal to 1, then the scale is maximally even.
    2. If x and y share a common factor k (that is, x and y are not coprime), then the scale is a multi-period scale. Split the string into k substrings that are exactly (x+y)/k characters long. If all of the substrings are identical, then perform the algorithm corresponding to that substring to determine whether the substring is maximally even. If it's not the case that all of the substrings are identical or the substring is not maximally even, then the scale is not maximally even.
  2. If there are more L's than s's AND there are either at least two adjacent s's or an s is at the beginning and end of the string, then scale is not maximally even. If there are more s's than L's AND there are either at least two adjacent L's or an L is at the beginning and end of the string, then the scale is not maximally even. This is because between every two instances of the character that appears the least must be at least one instance of the character that appears the most; this also applies if the character that appears the least appears at both ends of the string, as a different mode of the same string will put those two characters next to another.
  3. Split the string into a sequence of chunks as described: if there are more L's than s's (or if x > y), then each chunk will consist of at least one L followed by exactly one s; if instead there are more s's than L's (or y > x), then each chunk will consist of exactly one L followed by at least one s. Preserve the order of these chunks.
  4. Count how many UNIQUE chunks there are. If there are more than two unique strings, then the scale is not maximally even. If there are only two unique strings but their lengths differ by more than 1, then the scale is not maximally even.
  5. If there are more L's than s's, then for each chunk, replace all but the last two characters with s's, and replace the last two characters with a single L. This process represents L->sL and s->L. If there are more s's than L's, then for each chunk, replace only the first two characters with a single L. This process represents L->Ls and s->s, but reversed. The scale produced this way is the parent scale.
  6. Repeat the algorithm recursively on the parent scale. If that scale is maximally even, then the original scale is maximally even.

Chunking version

This is the general algorithm for determining whether a scale is maximally even (that is, it is a valid MOS). This version of the algorithm reduces entire chunks into L's and s's based on the size of the chunks. It is recommended, but not required, to perform this on the string representing the scale in either its brightest or darkest mode. This algorithm is recursive.

  1. Count how many L's and s's there are within the string. Let x be the number of L's and y be the number of s's. One of two situations will happen:
    1. If either x or y is equal to 1, or both x and y are equal to 1, then the scale is maximally even.
    2. If x and y share a common factor k (that is, x and y are not coprime), then the scale is a multi-period scale. Split the string into k substrings that are exactly (x+y)/k characters long. If all of the substrings are identical, then perform the algorithm corresponding to that substring to determine whether the substring is maximally even. If it's not the case that all of the substrings are identical or the substring is not maximally even, then the scale is not maximally even.
  2. If there are more L's than s's AND there are either at least two adjacent s's or an s is at the beginning and end of the string, then scale is not maximally even. If there are more s's than L's AND there are either at least two adjacent L's or an L is at the beginning and end of the string, then the scale is not maximally even. This is because between every two instances of the character that appears the least must be at least one instance of the character that appears the most; this also applies if the character that appears the least appears at both ends of the string, as a different mode of the same string will put those two characters next to another.
  3. Split the string into a sequence of chunks, not by splitting the strings into chunks that contain L's and s's, but AT the character that appears the least. Because every chunk contains at least one L and at least one s, removing the character that appears the least will not make any difference to how the chunks are ordered in terms of size. If there are more L's than s's, then there should be exactly y chunks consisting of only L's, and if there are more s's than L's, then there should be exactly x chunks consisting of only s's. If there is exactly one more string than expected, this may be because the string was in a mode that split one of the chunks into two; in this case, combine the first and last chunks in the sequence back into one chunk to get the correct number of chunks.
  4. Count how many UNIQUE chunks there are. If there are more than two unique strings, then the scale is not maximally even. If there are only two unique strings but their lengths differ by more than 1, then the scale is not maximally even.
  5. Produce a new scale consisting of L's and s's, based on the sequence of tokenized strings, as this will be the progenitor scale of the original; in the sequence, every instance of the larger string corresponds to an L in the progenitor scale, and every instance of the smaller string corresponds to an s in that scale. Call this algorithm recursively on that scale to determine whether that scale is also maximally even. If that scale is maximally even, then the original scale is maximally even. Otherwise, the scale is not maximally even.

Pseudocode

This is the pseudocode for the chunking operation described above.

VerifyMaximallyEvenScale(string scale : scale encodes an arbitrary scale of only L's and s's) returns TRUE or FALSE {

	integer x = 0;
	integer y = 0;

	for (integer i = 0 to scale.length) {
		if (scale[i] == x) {
			x += 1
		} else if (scale[i] == y) {
			y += 1
		}
	}

	// This is a separate function that returns the greatest common factor between x and y
	// This should return 1 if x and y are coprime
	integer common_factor = FindLargestCommonFactor(x, y)

	if (common_factor > 1) {
		set<string> substrings = { }

		integer length_counter = 0
		string temp_string = ""
		for (integer i = 0 to x + y) {
			length_counter += 1
			temp_string += scale[i]
			if (length_counter == common_factor) {
				length_counter = 0
				set.add(temp_string)
				temp_string = ""
			}
		}
		
		if (set.size != 1) {
			return FALSE
		} else {
			string subscale = set.beginning_of_set
			return VerifyMaximallyEvenScale(subscale)
		}
	}

	if (x == 1 OR y == 1) {
		return TRUE
	} else {
		if (x > y) {
			if (scale.contains_substring("ss") OR (scale[0] == "s" AND scale[s.size-1] == "s") return false
		} else if (y > x) {
			if (scale.contains_substring("LL") OR (scale[0] == "L" AND scale[s.size-1] == "L") return false
		}

		array<string> tokenized_strings = []

		// TokenizeString is a separate function that tokenizes a string at a specific character
		// Actual code may vary based on programming languages or libraries, but for the sake of
		// pseudocode, it's represented as a function that returns an array of tokenized strings
		if (x > y) {
			tokenized_strings = TokenizeString(string, 's')
		} else if (y < x) {
			tokenized_strings = TokenizeString(string, 'L')
		}

		integer string_count = min(x, y)

		if (tokenized_strings.length = string_count + 1) {
			tokenized_strings[0] = tokenized_strings[0] + tokenized_strings[string_count]
			tokenized_strings.remove_element_from_end()
		}

		set<string> unique_strings = { }

		for (integer i = 0 to string_count ) {
			unique_strings.add(tokenized_strings[i])
		}

		if (unique_strings.size != 2) {
			return FALSE
		} else {
			// A set should order things in alphabetical order, so string_1 and string_2
			// should represent the smaller and larger of the strings respectively
			string string_1 = unique_strings.beginning_of_set
			string string_2 = unique_strings.end_of_set

			if (abs(string_1.length - string_2.length) != 1) {
				return FALSE
			} else {
				string subscale = ""

				for (integer i = 0 to tokenized_strings.length) {
					if (tokenized_strings[i] == string_1)
						subscale += "s"
					else if (tokenized_string[i] == string_2)
						subscale += "L"

				return VerifyMaximallyEvenScale(subscale)
			}
		}
	}
}

Examples

6L 1s, or LLLLLLs. This falls under one of the special cases and is a moment-of-symmetry scale.

1L 6s, or Lssssss. This falls under one of the special cases and is a moment-of-symmetry scale.

5L 2s, or LLLsLLs. This produces two unique chunks of LLLs and LLs; replacing them with L and s respectively reduces the scale into Ls and is a moment-of-symmetry scale.

2L 5s, or LssLsss. This produces two unique chunks of Lss and Lsss; replacing them with s and L respectively reduces the scale into sL and is a moment-of-symmetry scale.

5L 7s, or LsLsLssLsLss. This produces two unique chunks of Ls and Lss; replacing them with s and L respectively reduces the scale into ssLsL. That scale produces two unique chunks of ssL and sL; replacing them with L and s respectively reduces the scale into Ls and is a moment-of-symmetry scale.

7L 5s, or LLsLsLLsLsLs. This produces two unique chunks of LLs and Ls; replacing them with L and s respectively reduces the scale into LsLss. That scale produces two unique chunks of Ls and Lss; replacing them with s and L respectively reduces the scale into sL and is a moment-of-symmetry scale.

5L 4s, or LLsLsLsLs. This scale consists of two unique chunks of LLs and Ls; replacing them with L and s respectively reduces the scale into Lsss and is a moment-of-symmetry scale.

3L 6s, or LssLssLss. Since 3 and 6 share a common factor of 3, this scale consists of Lss repeated three times, which falls under the special cases and is a multi-period moment-of-symmetry scale.

Counterexamples

LLLLsLs. This produces two unique chunks of LLLLs and Ls. However, the two chunks differ in size by two L's, and it is not maximally even.

LLLLLss. This produces one chunk of LLLLLs. The lone s at the end can be considered a chunk consisting of zero L's and one s. Since the two chunks differ in size by 5 L's, this is not maximally even.

LsssLsssL. The quantity of L's and s's are coprime, sharing a common factor of 3. However, dividing the scale into three equal-sized chunks shows that all three chunks are different (Lss, sLs, and ssL), so this is not maximally even.

LLsLLLsLLLLs. This produces three unique chunks of LLs, LLLs, and LLLLs. This is not maximally even.

Finding the MOS pattern from xL ys

There is a linear-time algorithm for generating a MOS that works by traversing the closest approximation to y = b/a*x, and the generator may be found from the integer point on this path that is closest to this line; this is essentially the Bresenham line algorithm. The following presents the slower recursive algorithms as is topical for this article.

General algorithm

This is the general algorithm for generating a moment of symmetry scale of the form xL ys represented as a string of L's and s's in its brightest mode. This algorithm will produce that scale without any prior knowledge of how the scale's steps are ordered. This algorithm is recursive. Let x be the number of L's and y the number of s's.

  1. If either x or y is equal to 1 (base cases):
    1. If both x and y are equal to 1, then the final scale is "Ls".
    2. If only x is equal to 1, then the final scale is L followed by y s's.
    3. If only y is equal to 1, then the final scale is x L's followed by s.
  2. If neither x nor y is equal to 1 (recursive cases):
    1. Let k be the greatest common factor of x and y.
    2. If x and y share a common factor k, where k is greater than 1, then recursively call this algorithm to find the scale for (x/k)L (y/k)s; the final scale will be (x/k)L (y/k)s duplicated k times.
    3. If x and y don't share a common factor that is greater than 1 (if x and y are coprime), then:
      1. Let m1 = min(x, y) and m2 = max(x, y).
      2. Let z = m2 mod m1 and w = m1 - z.
      3. Let prescale be the mos string for zL ws. Recursively call this algorithm to find the scale for zL ws; the final scale will be based on this.
      4. If x < y, reverse the order of characters in the prescale. This is only needed if there are more L's than s's in the final scale.
      5. To produce the final scale, the L's and s's of the prescale must be replaced with substrings consisting of L's and s's. Let u = ceil(m2/m1) and v = floor(m2/m1).
        1. If x > y, every instance of an L in the prescale is replaced with one L and u s's, and every s replaced with one L and v s's. This produces the final scale in its brightest mode.
        2. If y > x, every instance of an L in the prescale is replaced with u L's and one s, and every s replaced with v L's and one s. This produces the final scale in its brightest mode.

Python code

The code shown here is a Python function that implements the algorithm described above.

 1 def CalculateMos(x, y):
 2 
 3     mos_string = ""
 4 
 5     # Base cases
 6     if (x == 1 or y == 1):
 7         if (x == 1 and y == 1):
 8             mos_string = "Ls"
 9         elif (x == 1 and y > 1):
10             mos_string = "L" + "s" * y
11         elif (x > 1 and y == 1):
12             mos_string = "L" * x + "s"
13         else:
14             mos_string = "unable to find mos"
15     
16     # Recursive case
17     else:
18         
19         # Fing GCF
20         k = min(x, y)
21         while (k > 0):
22             if (x % k == 0 and y % k == 0):
23                 break
24             k -= 1
25 
26         # If mos is multi-period
27         if (k != 1):
28             mos_string = CalculateMos(x // k, y // k) * k
29             
30         # If mos is single-period
31         elif (k == 1):
32             m1 = min(x, y)
33             m2 = max(x, y)
34             z = m2 % m1
35             w = m1 - z
36 
37             # Recursive call
38             prescale = CalculateMos(z, w)
39             
40             # Revesal needed in some mosses
41             if (x < y):
42                 prescale = prescale[::-1]
43 
44             # Building up production rules
45             l_rule = ""
46             s_rule = ""
47             if (x > y):
48                 l_rule = "L" * math.ceil(m2 / m1) + "s"
49                 s_rule = "L" * math.floor(m2 / m1) + "s"
50             else:
51                 l_rule = "L" + "s" * math.ceil(m2 / m1)
52                 s_rule = "L" + "s" * math.floor(m2 / m1)
53 
54             # Apply rules
55             for step in prescale:
56                 if step == "L":
57                     mos_string += l_rule
58                 elif step == "s":
59                     mos_string += s_rule
60 
61         else:
62             mos_string = "unable to find mos"
63 
64     return mos_string


Example

To find the generators for 5L 7s, we can start at step 2.3.1, as the mos is neither multi-period nor 1L 1s. Using these steps, we can recursively find the mos 2L 3s, which means we recursively find the mos 1L 1s.

Since our mos is Ls, we need to expand L and s to find the mos for 2L 3s. Since we have more small steps than large steps, we need to reverse the scale into sL. Since we recursively called this algorithm for 2L 3s, we can deduce that L is replaced with Lss, and s with Ls, using steps 2.3.5.1 and 2.3.5.2, producing the mos 2L 3s represented as LsLss.

Since our mos is LsLss, we need to expand L and s again to find the mos for 5L 7s. Since we have more small steps than large steps, we need to reverse the scale into ssLsL. Since we recursively called this algorithm for 5L 7s, we can deduce that L is replaced with Lss and s with Ls.

With that, our final mos in its brightest mode is LsLsLssLsLss.

To make sure that we have the correct mos, we can relate it back to 5L 2s, whose mos LLLsLLs. By replacing "Ls" with L, we can reduce our mos into that for 5L 2s.

Finding a generator

The recursive structure also allows a recursive algorithm to find the generator, as a substring of the mos pattern. The reason why this works is that the reduction both preserves and reflects the generator; see the proofs section.

General algorithm

This is the general algorithm for finding a moment of symmetry scale's generator and its octave complement for a mos xL ys as two, not-necessarily-equal halves of the mos pattern xL ys. If the mos is multi-period, its generator and period complement are returned as two halves of the period. This algorithm will produce these intervals without any prior knowledge of how the scale's steps are ordered. This algorithm is recursive. Let x be the number of L's and y the number of s's.

  1. If either x or y is equal to 1 (base cases):
    1. If both x and y are equal to 1, then the generator is "L" and its complement is "s".
    2. If only x is equal to 1, then the generator is "L" followed by y-1 s's, and the complement is "s".
    3. If only y is equal to 1, then the generator is "L" and the complement is x-1 L's followed by "s".
  2. If neither x nor y is equal to 1 (recursive cases):
    1. Let k be the greatest common factor of x and y.
    2. If x and y share a common factor k, where k is greater than 1, then recursively call this algorithm to find the generator and complement for (x/k)L (y/k)s; the intervals returned this way will apply to the period rather than the octave.
    3. If x and y don't share a common factor that is greater than 1 (if x and y are coprime), then:
      1. Let m1 = min(x, y) and m2 = max(x, y).
      2. Let z = m2 mod m1 and w = m1 - z.
      3. Let gen be the scale's generator and comp be the generator's octave complement for the mos zL ws. Recursively call this algorithm to find these intervals for zL ws; the final scale's generator and complement will be based on this.
      4. If x < y, reverse the order of characters in gen and comp, then swap gen and comp. This is only needed if there are more L's than s's in the scale.
      5. To produce the scale's generator and complement, the L's and s's of both intervals must be replaced with substrings consisting of L's and s's. Let u = ceil(m2/m1) and v = floor(m2/m1).
        1. If x > y, every instance of an L in both intervals is replaced with one L and u s's, and every s replaced with one L and v s's. This produces the final scale's generator and complement.
        2. If y > x, every instance of an L in both intervals is replaced with u L's and one s, and every s replaced with v L's and one s. This produces the final scale's generator and complement.

Notes on output

The algorithm described here returns what is known as the chroma-positive generator, or bright generator, and is usually what is meant by the generator of a scale. The octave-complement returned this way is the scale's chroma-negative generator, or dark generator. More specifically, the bright generator is in its perfect form, and the dark generator is in its augmented form. If the perfect dark generator is needed instead, a quick way to produce it is to replace one L in the dark generator with an s.

If the number of steps in the generators is needed, simply count the total number of L's and s's in each generator.

Python code

The code shown here is a Python function that implements the algorithm described above.

 1 def CalculateMosGenerators(x, y):
 2 
 3     # Left is (bright) generator, right is octave-complement (dark generator)
 4     mos_string_left = ""
 5     mos_string_right = ""
 6 
 7     # Base cases
 8     if (x == 1 or y == 1):
 9         if (x == 1 and y == 1):
10             mos_string_left = "L"
11             mos_string_right = "s"
12         elif (x == 1 and y > 1):
13             mos_string_left = "L" + "s" * (y - 1)
14             mos_string_right = "s"
15         elif (x > 1 and y == 1):
16             mos_string_left = "L"
17             mos_string_right = "L" * (x - 1) + "s"
18         else:
19             mos_string_left = "unable to find generator"
20             mos_string_right = "unable to find generator"
21     
22     # Recursive case
23     else:
24         
25         # Find GCF
26         k = min(x, y)
27         while (k > 0):
28             if (x % k == 0 and y % k == 0):
29                 break
30             k -= 1
31 
32         # If mos is multi-period
33         if (k != 1):
34             mos_string_left, mos_string_right = CalculateMosGenerators(x // k, y // k)
35             
36         # If mos is single-period
37         elif (k == 1):
38             m1 = min(x, y)
39             m2 = max(x, y)
40             z = m2 % m1
41             w = m1 - z
42 
43             # Recursive call
44             prescale_left, prescale_right = CalculateMosGenerators(z, w)
45 
46             # Reversal step, needed in some mosses
47             if (x < y):
48                 prescale_left = prescale_left[::-1]
49                 prescale_right = prescale_right[::-1]
50                 
51                 temp = prescale_left
52                 prescale_left = prescale_right
53                 prescale_right = temp
54 
55             # Build up production rules
56             l_rule = ""
57             s_rule = ""
58             if (x > y):
59                 l_rule = "L" * math.ceil(m2 / m1) + "s"
60                 s_rule = "L" * math.floor(m2 / m1) + "s"
61             else:
62                 l_rule = "L" + "s" * math.ceil(m2 / m1)
63                 s_rule = "L" + "s" * math.floor(m2 / m1)
64 
65             # Apply rules
66             for step in prescale_left:
67                 if step == "L":
68                     mos_string_left += l_rule
69                 elif step == "s":
70                     mos_string_left += s_rule
71             for step in prescale_right:
72                 if step == "L":
73                     mos_string_right += l_rule
74                 elif step == "s":
75                     mos_string_right += s_rule
76 
77         else:
78             mos_string_left = "unable to find generator"
79             mos_string_right = "unable to find generator"
80 
81     return mos_string_left, mos_string_right

Example

To find the generators for 5L 7s, we can start at step 2.3.1, as the mos is neither multi-period nor 1L 1s. Using these steps, we can recursively find the generators for the mos 2L 3s, which means we recursively find the generators for 1L 1s.

Since our generators are L and s, we need to expand L and s to find the generators for 2L 3s. Since we have more small steps than large steps, we need to reverse and swap the generators, so our bright generator is s and dark generator is L. Since we recursively called this algorithm for 2L 3s, we can deduce that L is replaced with Lss, and s with Ls, using steps 2.3.5.1 and 2.3.5.2, producing the generator pair of Ls and Lss.

Since our generators are now Ls and Lss, we need to expand them again to find the generators for 5L 7s. Since we have more small steps than large steps, we need to reverse and swap the generators, so our bright generator is ssL and dark generator is sL. Since we recursively called this algorithm for 5L 7s, we can deduce that L is replaced with Lss and s with Ls.

With that, our final generator pair is LsLsLss and LsLss.

To make sure that we have the correct generator pair, we can relate it back to 5L 2s, whose generator pair is LLLs and LLs. By replacing "Ls" with L, we can reduce our generator pair into that for 5L 2s.

Tree of MOS patterns

MOS patterns have parents and children. If 1L 1s is the root of the tree, with any generator between 0\1 (for collapsed 1L 1s) and 1\2 (for equalized 1L 1s) Every node aL bs has two children, aL (a+b)s and (a+b)L as (these MOS patterns are sister MOS patterns; they are called such because they have the same parent). The generator range of aL bs splits at the mediant of the endpoints of the parent interval (which is the generator size for basic aL bs), giving the generator ranges of the two child patterns.

The tree of MOS patterns starts with:

1L 1s
1L 2s        2L 1s
1L 3s 3L 1s  3L 2s 2L 3s

The corresponding tree of generator ranges looks like:

(0\1, 1\2)
(0\1, 1\3)            (1\3, 1\2)
(0\1, 1\4) (1\4, 1\3) (1\3, 2\5) (2\5, 1\2)

Proofs

Definition of MOS

A periodic scale is MOS if it has maximum variety 2. This in particular implies that MOS scales are binary.

Preservation of the MOS property

(Assume that the MOS has length n; the notation w(X, Y) for a word w(L, s) in L, s means w with step sizes X substituted for L and Y substituted for s.)

Suppose w(L, s) had three chunks L...s with r < r+i < r+j 'L's. Then we have a length r+2 subword that's only 'L's, one that has one s at the end and one that has two 's's on either side, which means that the original scale was not MOS. Therefore the reduced word has two step sizes that differ by 1. Repeating this argument for sequences of k > 1 chunks shows that any k-step in the reduced word must come in at most 2 sizes, showing that the reduced word is indeed MOS.

Preservation of generators

Assume there are more L's and s's, and that there is more than one s, and thus more than one chunk. Assume there is a generator. Assume the imperfect generator is bigger than the perfect generator. (If this isn't true, just use the inverted generator.) Because there are at least two chunk boundaries, and only one imperfect generator, there must be a chunk boundary with a perfect generator on top (the chunk boundary is on the left of the generator, e.g. ...|Ls|LLs|Ls...). Because there's a chunk boundary to the left, there's an s just to the left of the left endpoint of the generator. If the rightmost step of this generator were an L, scooting the generator one step to the left would make it smaller, which contradicts the assumption that the imperfect generator is larger than perfect. Thus, the rightmost step of this generator is an s. That means the right endpoint of this generator falls on a chunk boundary. We already know the left endpoint also falls on a chunk boundary, so this perfect generator is still present as an interval in the reduced MOS.

This interval is, in fact, the generator of the reduced scale. Indeed, you can build this generator on all of the chunk boundaries of the non-reduced scale. All but one of these will be perfect. The perfect ones will have their right endpoint be a chunk boundary, as we showed before, so this is an interval that's on all but one tone of the reduced scale. This is a generator.

Reflection of generators

Suppose there is a generator after chunking. Assume also that there are more L's than s's, and that the imperfect generator is larger than the perfect generator. This means that this interval, built on the chunk boundaries after expanding, will still be "a generator" on the chunk boundaries: it will be the same size on all but one of the chunk boundaries. Take one of the "perfect" (smaller) intervals. We showed previously that, before expansion, the step to its right was an L, just like its first step; therefore we can scoot it over for the entirety of the first chunk and keep it perfect. We now come to another chunk. If a "perfect" interval can be built on it then we can repeat. If the interval is imperfect, then we know that the step to its right is an s, which will make it smaller and thus perfect, and we can keep doing this for the remainder of the chunk. Therefore, the interval is a generator after expansion as well, since it is only imperfect in one position.

Uniqueness and existence of the generator

Every MOS can be reduced to nL 1s (or 1L ns). Each step of the reduction decreases either the number of L's or the number of s's (or both), so one of them must reach 1 at some point. (note that reducing further gets us to 1L 0s, which has a period, but no generator per se)

It is clear that the MOS nL 1s has a unique generator, L (or its inversion). However, the previous proof showed that reduction reflects generators, and so by induction all MOS scales have a single generator.

See also