Recursive structure of MOS scales: Difference between revisions

Ganaram inukshuk (talk | contribs)
Recursive structure (chunking operation): Clarified chunking process for scales with more s's than L's; also accounted for multi-period scales as repetitions of a single-period scale. I've brought up these properties on the xen discord and I've finally gotten around to putting it on the wiki in hopefully a proper place. My contributions may still need some rewording. (Does not include the pseudocode I brought up since it still had bugs) - Ganaram
Ganaram inukshuk (talk | contribs)
Recursive structure (chunking operation): I've gotten around to adding the pseudocode and did a bit of rewording. It may contain errors, so please feel free to edit if there are any. (Also please feel free to edit any of my other changes should it be too wordy.)
Line 3: Line 3:
== Recursive structure (chunking operation) ==
== Recursive structure (chunking operation) ==


Let w be an arbitrary moment-of-symmetry scale in either its brightest mode or darkest mode. 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:  
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:  


* '''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 substrings (or chunks) where each substring contains at least one L and exactly one s. Among these chunks, of which there are y in total, 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. If the scale is in its brightest mode, groups of L's should come before singular s's; this order is reversed if the scale is in its darkest mode.
* '''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 substrings (or chunks) where each substring contains at least one s and exactly one L. Among these chunks, of which there are x in total, 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. If the scale is in its brightest mode, singular L's should come before groups of s's; this order is reversed if the scale is in its darkest mode.
* '''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.
* '''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.


Line 31: Line 31:


(TODO: Maximal evenness test for any arbitrary scale in any arbitrary mode.)
(TODO: Maximal evenness test for any arbitrary scale in any arbitrary mode.)
=== 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 ===
=== Examples ===
Line 37: Line 137:
1L 6s, or Lssssss. 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.
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.
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.
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.
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.
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.
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.
Line 54: Line 154:
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.
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 chunks shows that all three chunks are different (Lss, sLs, and ssL), so 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.
LLsLLLsLLLLs. This produces three unique chunks of LLs, LLLs, and LLLLs. This is not maximally even.
Line 79: Line 179:


(TODO: Examples)
(TODO: Examples)
=== Pseudocode ===
This is the pseudocode for the algorithm described above.
Pseudocode
ProduceMaximallyEvenScale(integer x : number of large steps, integer y : number of small steps) returns string : string encodes a MOS/MV2 scale represented in its brightest mode {
string final_scale = ""
// 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)
// x and y have a common factor greater than 1, so it's a multi-period scale
if (common_factor > 1) {
string intermediate_scale = ProduceMaximallyEvenScale(x/common_factor, y/common_factor)
for (integer i = 0 to common_factor) {
final_scale += intermediate_scale
}
}
// Both x and y are equal to 1
else if (x == 1 AND y == 1) {
final_scale = "Ls"
}
// ONLY x is equal to 1
else if (x == 1 AND y != 1) {
final_scale += "L"
for (integer i = 0 to y) {
final_scale += "s"
}
}
// ONLY y is equal to 1
else if (x != 1 AND y == 1) {
for (integer i = 0 to x) {
final_scale += "L"
}
final_scale += "s"
}
// Neither x nor y are equal to 1
else if (x != 1 AND y != 1) {
// There are more large steps than small steps
if (x > y) {
integer large_group_count = x % y
integer small_group_count = y - large_group_count
string large_group_production_rule = ""
string small_group_production_rule = ""
integer l_count = floor(x/y)
for (integer i = 0 to l_count) {
large_group_production_rule += "L"
small_group_production_rule += "L"
}
large_group_production_rule += "Ls"
small_group_production_rule += "s"
string intermediate_scale = ProduceMaximallyEvenScale(large_group_count, small_group_count)
for (integer i = 0 to intermediate_scale.length) {
if (intermediate_scale[i] = "L") {
final_scale += large_group_production_rule
} else if (intermediate_scale[i] = "s") {
final_scale += small_group_production_rule
}
}
}
// There are more small steps than large steps
if (y > x) {
integer large_group_count = y % x
integer small_group_count = y - large_group_count
string large_group_production_rule = ""
string small_group_production rule = ""
integer l_count = floor(y/x)
for (integer i = 0 to l_count) {
large_group_production_rule += "s"
small_group_production_rule += "s"
}
large_group_production_rule += "sL"
small_group_production_rule += "L"
string intermediate_scale = ProduceMaximallyEvenScale(large_group_count, small_group_count)
for (integer i = 0 to intermediate_scale.length) {
if (intermediate_scale[i] = "L") {
final_scale += large_group_production_rule
} else if (intermediate_scale[i] = "s") {
final_scale += small_group_production_rule
}
}
}
}
return final_scale
}


=== Example ===
=== Example ===