From b104799cbde98d135e75d1351df9b212e9c34b12 Mon Sep 17 00:00:00 2001 From: inthar-raven Date: Thu, 12 Sep 2024 18:21:01 -0400 Subject: [PATCH] Add detempered Ploidacot interpretations (#35) --- index.js | 10 ++++ src/guide.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 6 ++- 3 files changed, 145 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index bd2cdf3..c883b5a 100644 --- a/index.js +++ b/index.js @@ -475,6 +475,7 @@ stack()` h2.innerText = `Scale profile for ${currentWord}`; el.appendChild(h2); if (currentProfile) { + const ploidacot = currentProfile["ploidacot"]; const structure = currentProfile["structure"]; if (structure) { el.innerHTML += `Guide frame
`; @@ -487,6 +488,15 @@ stack()` el.innerHTML += `Interleaving polyoffset ${structure["polyoffset"].map((g) => alsoInCurrentTuning(g))}
`; // TODO prettify el.innerHTML += `Multiplicity ${JSON.stringify(structure["multiplicity"])}
`; // TODO prettify el.innerHTML += `Complexity ${JSON.stringify(structure["complexity"])}

`; // TODO prettify + if (ploidacot) { + const ploid = ploidacot["ploid"]; + const ploidString = ploid === 1 ? "" : `${ploid}-ploid `; + const shear = ploidacot["shear"]; + const shearString = shear === 0 ? "" : `${shear}-sheared `; + const cot = ploidacot["cot"]; + const cotString = `${cot}-cot`; + el.innerHTML += `Detempered Ploidacot: ${ploidString}${shearString}${cotString}

`; // TODO prettify + } el.innerHTML += `Monotone MOS properties
`; el.innerHTML += currentProfile["lm"] ? `L = m
` : ""; el.innerHTML += currentProfile["ms"] ? `m = s
` : ""; diff --git a/src/guide.rs b/src/guide.rs index ec790b5..1534b4e 100644 --- a/src/guide.rs +++ b/src/guide.rs @@ -1,6 +1,7 @@ use std::collections::BTreeSet; use itertools::Itertools; +use serde::Serialize; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -100,6 +101,71 @@ fn guided_gs_list_for_subscale(subscale: &[CountVector]) -> Vec Option { + println!("gf: {:?}", guide_frames(scale)); + if let Some(gf) = guide_frames(scale).first() { + let n = scale.len(); + println!("gf: {:?}", gf.clone()); + let po = &gf.polyoffset; + let gs = &gf.gs; + let multigen_class = gs.len() * gs[0].len(); + let patent_3_mapping = + f64::round(n as f64 * f64::log(3.0, std::f64::consts::E) / std::f64::consts::LN_2) + as usize; + let ploid = if po.len() == 1 || gcd(patent_3_mapping as u64, n as u64) > 1 { + 1 // do this instead of polyploid acot + } else { + n / po[1].len() + }; + let patent_fifth_mapping = patent_3_mapping - n; + let patent_fourth_mapping = 2 * n - patent_3_mapping; + // Check if one generator in the GS can be interpreted as a fifth + if gs[0].len() == patent_fifth_mapping || gs[0].len() == patent_fourth_mapping { + Some(Self { + ploid, + cot: 1, + shear: 0, + }) + } else { + // Check if aggregate generator can be interpreted as a fifth + for i in 0..gs.len() { + if patent_fifth_mapping + i * n == multigen_class { + let cot = gs.len(); + let shear = i; + return Some(Self { ploid, cot, shear }); + } + } + let patent_fourth_mapping = 2 * n - patent_3_mapping; + for i in 0..gs.len() { + if patent_fourth_mapping + i * n == multigen_class { + let cot = gs.len(); + let shear = (cot - 1 - i) % cot; + return Some(Self { ploid, cot, shear }); + } + } + None + } + } else { + None + } + } +} + /// A guide frame structure for a scale word, consisting of a generator sequence together with a set of offsets or a multiplicity. /// Multiplicity greater than 1 is a generalization of diregular MV3s; /// scales of this type always have the number of notes divisible by the multiplicity. @@ -163,7 +229,7 @@ impl GuideFrame { let co_d = scale.len() / d; if co_d % multiplicity != 0 { if d == multiplicity { - println!("interleaved"); + // println!("interleaved"); // It's an interleaved scale. let subscales = (0..d) .map(|degree| rotate(scale, degree)) @@ -228,7 +294,7 @@ impl GuideFrame { vec![] } } else { - println!("not interleaved"); + // println!("not interleaved"); // stack at most this many k-steps let chain_length: usize = scale.len() / multiplicity; if chain_length == 1 { @@ -251,8 +317,6 @@ impl GuideFrame { // `init` will be nonempty, so the following check won't be vacuous. init.all(|k_step| *k_step != *last) }); - let g: Vec<_> = gen_chains_enumerated.clone().collect(); - println!("gen_chains_enumerated: {:?}", g); let gses: Vec>> = gen_chains_enumerated .clone() // Take prefix of gs_length_limit - 1 elements and get what GS it is generated by @@ -260,7 +324,7 @@ impl GuideFrame { .sorted() .dedup() .collect(); - println!("{:?}", gses); + // println!("{:?}", gses); gses.iter() .map(|gs| { ( @@ -269,11 +333,11 @@ impl GuideFrame { .clone() // Check only the prefix of gs_length_limit - 1 elements, because that's what the guided GS is based on. .filter(|(_, gen_chain)| { - println!("gen_chain: {:?}", gen_chain); - println!( - "weak_period: {:?}", - weak_period(&gen_chain[..chain_length - 1]) - ); + // println!("gen_chain: {:?}", gen_chain); + //println!( + // "weak_period: {:?}", + // weak_period(&gen_chain[..chain_length - 1]) + // ); weak_period(&gen_chain[..chain_length - 1]) == *gs.clone() }) // Get all indices on which this particular GS occurs. @@ -294,13 +358,13 @@ impl GuideFrame { .collect(); union_of_chains.sort(); union_of_chains.dedup(); - println!("union_of_chains: {:?}", union_of_chains); + // println!("union_of_chains: {:?}", union_of_chains); let chains_are_disjoint: bool = union_of_chains.len() == scale.len(); chains_are_disjoint && polyoffset_indices.len() == multiplicity }) .map(|(gs, polyoffset_indices)| { - println!("gs: {:?}", gs); - println!("polyoffset_indices: {:?}", polyoffset_indices); + // println!("gs: {:?}", gs); + // println!("polyoffset_indices: {:?}", polyoffset_indices); let first_deg = polyoffset_indices[0]; let polyoffset: Vec> = polyoffset_indices .iter() @@ -363,6 +427,59 @@ mod tests { use super::*; #[test] + fn test_ploidacot() { + let pinedye = [0, 0, 1, 0, 1, 0, 0, 2]; + assert_eq!( + // Pinedye is monocot + Ploidacot::try_get_ploidacot(&pinedye), + Some(Ploidacot { + ploid: 1, + cot: 1, + shear: 0, + }) + ); + let diasem = [0, 1, 0, 2, 0, 1, 0, 2, 0]; + assert_eq!( + // Diasem is 1-sheared dicot + Ploidacot::try_get_ploidacot(&diasem), + Some(Ploidacot { + ploid: 1, + cot: 2, + shear: 1, + }) + ); + let diamech_4sl: [usize; 11] = [1, 0, 2, 0, 2, 0, 1, 0, 2, 0, 2]; + assert_eq!( + // Diamech is tricot + Ploidacot::try_get_ploidacot(&diamech_4sl), + Some(Ploidacot { + ploid: 1, + cot: 3, + shear: 0, + }) + ); + let diachrome_5sc = [0, 2, 0, 2, 0, 1, 2, 0, 2, 0, 2, 1]; + assert_eq!( + // Central diachrome is diploid monocot + Ploidacot::try_get_ploidacot(&diachrome_5sc), + Some(Ploidacot { + ploid: 2, + cot: 1, + shear: 0, + }) + ); + let blackdye: [usize; 10] = [0, 1, 0, 2, 0, 1, 0, 2, 0, 2]; + assert_eq!( + // Blackdye is haploid monocot (ignore the contorsion caused by the offset) + Ploidacot::try_get_ploidacot(&blackdye), + Some(Ploidacot { + ploid: 1, + cot: 1, + shear: 0, + }) + ); + } + #[test] fn test_lllmllms() { let bad_scale: [usize; 8] = [0, 0, 0, 1, 0, 0, 1, 2]; let complexity_2_gses = GuideFrame::try_multiple(&bad_scale, 2, 2); diff --git a/src/lib.rs b/src/lib.rs index a094617..9174349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use serde::Serialize; use serde_wasm_bindgen::to_value; use guide::guide_frames; -use guide::GuideFrame; +use guide::{GuideFrame, Ploidacot}; use interval::JiRatio; use words::{least_mode, maximum_variety, monotone_lm, monotone_ms, monotone_s0, CountVector}; @@ -104,6 +104,8 @@ pub struct ScaleProfile { reversed: String, /// lowest-complexity guide frame structure provided there is one structure: Option, + /// detempered Ploidacot interpretation + ploidacot: Option, /// whether scale is L=M monotone MOS lm: bool, /// whether scale is M=s monotone MOS @@ -324,6 +326,7 @@ pub fn word_to_profile(query: &[usize]) -> ScaleProfile { ScaleProfile { word: brightest, lattice_basis: Some(lattice_basis), + ploidacot: Ploidacot::try_get_ploidacot(query), chirality, reversed, structure: Some(structure), @@ -336,6 +339,7 @@ pub fn word_to_profile(query: &[usize]) -> ScaleProfile { ScaleProfile { word: brightest, lattice_basis: None, + ploidacot: Ploidacot::try_get_ploidacot(query), chirality, reversed, structure: None,