use crate::transducer::{OperationSet, OperationSetBuilder, OperationType, SubstitutionSet};
pub fn consonant_digraphs() -> OperationSet {
let mut digraphs_2_to_1 = SubstitutionSet::new();
digraphs_2_to_1.allow_str("ch", "k");
digraphs_2_to_1.allow_str("sh", "s");
digraphs_2_to_1.allow_str("ph", "f");
digraphs_2_to_1.allow_str("th", "t");
let mut digraphs_1_to_2 = SubstitutionSet::new();
digraphs_1_to_2.allow_str("k", "ch");
digraphs_1_to_2.allow_str("s", "sh");
digraphs_1_to_2.allow_str("f", "ph");
digraphs_1_to_2.allow_str("t", "th");
let mut digraphs_2_to_2 = SubstitutionSet::new();
digraphs_2_to_2.allow_str("qu", "kw");
digraphs_2_to_2.allow_str("kw", "qu");
OperationSetBuilder::new()
.with_operation(OperationType::with_restriction(
2,
1,
0.15,
digraphs_2_to_1,
"consonant_digraphs_2to1",
))
.with_operation(OperationType::with_restriction(
1,
2,
0.15,
digraphs_1_to_2,
"consonant_digraphs_1to2",
))
.with_operation(OperationType::with_restriction(
2,
2,
0.15,
digraphs_2_to_2,
"consonant_digraphs_2to2",
))
.build()
}
pub fn initial_clusters() -> OperationSet {
let mut clusters_2_to_1 = SubstitutionSet::new();
clusters_2_to_1.allow_str("wr", "r");
clusters_2_to_1.allow_str("wh", "w");
clusters_2_to_1.allow_str("kn", "n");
clusters_2_to_1.allow_str("ps", "s");
clusters_2_to_1.allow_str("pn", "n");
clusters_2_to_1.allow_str("gn", "n");
clusters_2_to_1.allow_str("rh", "r");
let mut clusters_1_to_2 = SubstitutionSet::new();
clusters_1_to_2.allow_str("r", "wr");
clusters_1_to_2.allow_str("w", "wh");
clusters_1_to_2.allow_str("n", "kn");
clusters_1_to_2.allow_str("s", "ps");
clusters_1_to_2.allow_str("n", "pn");
clusters_1_to_2.allow_str("n", "gn");
clusters_1_to_2.allow_str("r", "rh");
OperationSetBuilder::new()
.with_operation(OperationType::with_restriction(
2,
1,
0.20,
clusters_2_to_1,
"initial_clusters_2to1",
))
.with_operation(OperationType::with_restriction(
1,
2,
0.20,
clusters_1_to_2,
"initial_clusters_1to2",
))
.build()
}
pub fn phonetic_confusions() -> OperationSet {
let mut confusions = SubstitutionSet::new();
confusions.allow('c', 'k');
confusions.allow('k', 'c');
confusions.allow('c', 's');
confusions.allow('s', 'c');
confusions.allow('s', 'z');
confusions.allow('z', 's');
confusions.allow('g', 'j');
confusions.allow('j', 'g');
confusions.allow('f', 'v');
confusions.allow('v', 'f');
confusions.allow('a', 'e');
confusions.allow('e', 'a');
confusions.allow('i', 'e');
confusions.allow('e', 'i');
let op = OperationType::with_restriction(
1,
1,
0.25, confusions,
"phonetic_confusions",
);
OperationSetBuilder::new().with_operation(op).build()
}
pub fn double_consonants() -> OperationSet {
let mut doubles = SubstitutionSet::new();
let consonants = [
'b', 'c', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'z',
];
for &c in &consonants {
let double = format!("{}{}", c, c);
let single = format!("{}", c);
doubles.allow_str(&double, &single);
doubles.allow_str(&single, &double);
}
let op = OperationType::with_restriction(
2,
1,
0.10, doubles,
"double_consonants",
);
OperationSetBuilder::new().with_operation(op).build()
}
pub fn phonetic_english_basic() -> OperationSet {
let mut builder = OperationSetBuilder::new();
for op in consonant_digraphs().operations() {
builder = builder.with_operation(op.clone());
}
for op in initial_clusters().operations() {
builder = builder.with_operation(op.clone());
}
for op in phonetic_confusions().operations() {
builder = builder.with_operation(op.clone());
}
for op in double_consonants().operations() {
builder = builder.with_operation(op.clone());
}
builder.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_consonant_digraphs() {
let ops = consonant_digraphs();
assert!(!ops.is_empty());
assert_eq!(ops.len(), 3);
let names: Vec<_> = ops.operations().iter().map(|op| op.name()).collect();
assert!(names.contains(&"consonant_digraphs_2to1"));
assert!(names.contains(&"consonant_digraphs_1to2"));
assert!(names.contains(&"consonant_digraphs_2to2"));
}
#[test]
fn test_initial_clusters() {
let ops = initial_clusters();
assert!(!ops.is_empty());
assert_eq!(ops.len(), 2);
let names: Vec<_> = ops.operations().iter().map(|op| op.name()).collect();
assert!(names.contains(&"initial_clusters_2to1"));
assert!(names.contains(&"initial_clusters_1to2"));
}
#[test]
fn test_phonetic_confusions() {
let ops = phonetic_confusions();
assert!(!ops.is_empty());
assert_eq!(ops.len(), 1);
let op = &ops.operations()[0];
assert_eq!(op.name(), "phonetic_confusions");
assert_eq!(op.consume_x(), 1);
assert_eq!(op.consume_y(), 1);
}
#[test]
fn test_double_consonants() {
let ops = double_consonants();
assert!(!ops.is_empty());
assert_eq!(ops.len(), 1);
let op = &ops.operations()[0];
assert_eq!(op.name(), "double_consonants");
assert_eq!(op.consume_x(), 2);
assert_eq!(op.consume_y(), 1);
}
#[test]
fn test_phonetic_english_basic() {
let ops = phonetic_english_basic();
assert!(!ops.is_empty());
assert_eq!(ops.len(), 7);
let names: Vec<_> = ops.operations().iter().map(|op| op.name()).collect();
assert!(names.contains(&"consonant_digraphs_2to1"));
assert!(names.contains(&"consonant_digraphs_1to2"));
assert!(names.contains(&"consonant_digraphs_2to2"));
assert!(names.contains(&"initial_clusters_2to1"));
assert!(names.contains(&"initial_clusters_1to2"));
assert!(names.contains(&"phonetic_confusions"));
assert!(names.contains(&"double_consonants"));
}
#[test]
fn test_can_apply_consonant_digraphs() {
let ops = consonant_digraphs();
let op_2to1 = ops
.operations()
.iter()
.find(|op| op.name() == "consonant_digraphs_2to1")
.expect("Should have 2to1 operation");
assert!(op_2to1.can_apply(b"ph", b"f"));
let op_1to2 = ops
.operations()
.iter()
.find(|op| op.name() == "consonant_digraphs_1to2")
.expect("Should have 1to2 operation");
assert!(op_1to2.can_apply(b"f", "ph".as_bytes()));
assert!(!op_2to1.can_apply(b"xy", b"z"));
}
#[test]
fn test_can_apply_initial_clusters() {
let ops = initial_clusters();
let op_2to1 = ops
.operations()
.iter()
.find(|op| op.name() == "initial_clusters_2to1")
.expect("Should have 2to1 operation");
assert!(op_2to1.can_apply(b"wr", b"r"));
assert!(op_2to1.can_apply(b"kn", b"n"));
let op_1to2 = ops
.operations()
.iter()
.find(|op| op.name() == "initial_clusters_1to2")
.expect("Should have 1to2 operation");
assert!(op_1to2.can_apply(b"r", b"wr"));
}
#[test]
fn test_operation_weights() {
let digraphs = consonant_digraphs();
let clusters = initial_clusters();
let confusions = phonetic_confusions();
let doubles = double_consonants();
assert!(doubles.operations()[0].weight() < digraphs.operations()[0].weight());
assert!(digraphs.operations()[0].weight() < clusters.operations()[0].weight());
assert!(clusters.operations()[0].weight() < confusions.operations()[0].weight());
}
}