Skip to content

Commit

Permalink
Add snow2
Browse files Browse the repository at this point in the history
  • Loading branch information
tansongchen committed Jan 23, 2025
1 parent aadea30 commit c50446a
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 20 deletions.
10 changes: 8 additions & 2 deletions src/encoder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
//! 编码引擎
use crate::Error;
use crate::representation::{
Assemble, AssembleList, Assets, AutoSelect, Code, CodeInfo, CodeSubInfo, Codes, Element, Entry,
Frequency, Key, KeyMap, Representation, Sequence, MAX_WORD_LENGTH,
};
use crate::Error;
use c3::C3;
use occupation::Occupation;
use rustc_hash::{FxHashMap, FxHashSet};
use simple_occupation::SimpleOccupation;
use snow2::Snow2;
use std::cmp::Reverse;

pub mod c3;
pub mod occupation;
pub mod simple_occupation;
pub mod snow2;

/// 一个可编码对象
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -212,6 +214,10 @@ impl Encoder {
};
let mut driver: Box<dyn Driver> = if representation.config.info.name == "c3" {
Box::new(C3::new(representation.get_space()))
} else if representation.config.info.name == "冰雪双拼"
|| representation.config.info.name == "冰雪双拼声介"
{
Box::new(Snow2::new(representation.get_space()))
} else if representation.config.encoder.max_length <= 4 {
Box::new(SimpleOccupation::new(representation.get_space()))
} else {
Expand All @@ -229,7 +235,7 @@ impl Encoder {
}

pub fn init(&mut self, keymap: &KeyMap) {
self.default_driver
self.driver
.run(keymap, &self.config, &mut self.buffer, &[]);
}

Expand Down
119 changes: 119 additions & 0 deletions src/encoder/snow2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use super::{Driver, EncoderConfig};
use crate::representation::{Codes, Element, KeyMap, Representation};

/// 编码是否已被占据
/// 用一个数组和一个哈希集合来表示,数组用来表示四码以内的编码,哈希集合用来表示四码以上的编码
pub struct Snow2 {
pub full_space: Vec<bool>,
pub short_space: Vec<bool>,
pub involved_message: Vec<Vec<usize>>,
}

impl Snow2 {
pub fn new(length: usize) -> Self {
Self {
full_space: vec![false; length],
short_space: vec![false; length],
involved_message: vec![],
}
}

pub fn reset(&mut self) {
self.full_space.iter_mut().for_each(|x| {
*x = false;
});
self.short_space.iter_mut().for_each(|x| {
*x = false;
});
}
}

impl Driver for Snow2 {
fn init(&mut self, config: &EncoderConfig, _: &Representation) {
for _ in 0..=config.elements_length {
self.involved_message.push(vec![]);
}
for (index, encodable) in config.encodables.iter().enumerate() {
for element in &encodable.sequence {
self.involved_message[*element].push(index);
}
}
}

fn run(
&mut self,
keymap: &KeyMap,
config: &EncoderConfig,
buffer: &mut Codes,
moved_elements: &[Element],
) {
self.reset();
let weights: [u64; 4] = [
1,
config.radix,
config.radix * config.radix,
config.radix * config.radix * config.radix,
];

if moved_elements.is_empty() {
for (encodable, pointer) in config.encodables.iter().zip(buffer.iter_mut()) {
let sequence = &encodable.sequence;
let full = &mut pointer.full;
let mut code = keymap[sequence[0]] as u64
+ keymap[sequence[1]] as u64 * weights[1]
+ keymap[sequence[2]] as u64 * weights[2];
if sequence.len() == 4 {
code += keymap[sequence[3]] as u64 * weights[3];
};
full.actual = code;
full.has_changed = true;
}
} else {
// 部分编码,只计算变化的部分
for element in moved_elements {
for index in &self.involved_message[*element] {
let pointer = &mut buffer[*index];
let encodable = &config.encodables[*index];
let sequence = &encodable.sequence;
let full = &mut pointer.full;
let mut code = keymap[sequence[0]] as u64
+ keymap[sequence[1]] as u64 * weights[1]
+ keymap[sequence[2]] as u64 * weights[2];
if sequence.len() == 4 {
code += keymap[sequence[3]] as u64 * weights[3];
};
full.check_actual(code);
}
}
}

for pointer in buffer.iter_mut() {
let full = &mut pointer.full;
let duplicate = self.full_space[full.actual as usize];
full.check_duplicate(duplicate);
self.full_space[full.actual as usize] = true;
}

// 出简码
for (index, p) in buffer.iter_mut().enumerate() {
let full = &mut p.full;
let short = &mut p.short;
let has_short = index <= 1000;
let first = full.actual % weights[1];
let second = full.actual % weights[2];
if has_short && !self.short_space[first as usize] {
short.check(first, false);
self.short_space[first as usize] = true;
} else if has_short && !self.short_space[second as usize] {
short.check(second, false);
self.short_space[second as usize] = true;
} else {
let duplicate = self.short_space[full.actual as usize];
short.check(full.actual, duplicate);
self.short_space[full.actual as usize] = true;
}
// println!("{:?}", short);
}
// exit(0);
}
}
12 changes: 7 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ pub enum Message {
Progress {
steps: usize,
temperature: f64,
metric: String,
metric: Metric,
},
BetterSolution {
metric: String,
config: String,
metric: Metric,
config: Config,
save: bool,
},
Elapsed(u128),
Expand Down Expand Up @@ -338,17 +338,19 @@ impl Interface for CommandLine {
let time = Local::now();
let prefix = time.format("%m-%d+%H_%M_%S_%3f").to_string();
let config_path = format!("output/{}.yaml", prefix);
let metric_path = format!("output/{}.txt", prefix);
let metric_path = format!("output/{}.metric.yaml", prefix);
println!(
"{} 系统搜索到了一个更好的方案,评测指标如下:",
time.format("%H:%M:%S")
);
print!("{}", metric);
let config = serde_yaml::to_string(&config).unwrap();
let metric = serde_yaml::to_string(&metric).unwrap();
if save {
write(metric_path, metric).unwrap();
write(config_path, config).unwrap();
println!(
"方案文件保存于 {}.yaml 中,评测指标保存于 {}.txt 中",
"方案文件保存于 {}.yaml 中,评测指标保存于 {}.metric.yaml 中",
prefix, prefix
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() -> Result<(), Error> {
let objective = Objective::new(&representation, encoder, assets)?;
match solver {
SolverConfig::SimulatedAnnealing(sa) => {
if config.info.name == "冰雪双拼" {
if config.info.name == "冰雪双拼" || config.info.name == "冰雪双拼声介" {
let mut problem = Snow2::new(representation, objective);
sa.solve(&mut problem, &cli);
} else {
Expand Down
5 changes: 2 additions & 3 deletions src/metaheuristics/simulated_annealing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,10 @@ impl SimulatedAnnealing {
let temperature = t_max * (t_min / t_max).powf(progress);
// 每过一定的步数,报告当前状态和计算速度
if step % update_interval == 0 {
let metric = format!("{}", annealing_rank.0);
interface.post(Message::Progress {
steps: step,
temperature,
metric,
metric: annealing_rank.0.clone(),
});
if step == update_interval {
let elapsed = start.elapsed().as_micros() / update_interval as u128;
Expand Down Expand Up @@ -108,7 +107,7 @@ impl SimulatedAnnealing {
interface.post(Message::Progress {
steps,
temperature: t_min,
metric: format!("{}", best_rank.0),
metric: best_rank.0.clone(),
});
problem.update(&best_candidate, &best_rank, true, interface);
best_candidate
Expand Down
4 changes: 1 addition & 3 deletions src/problems/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,8 @@ impl Problem for DefaultProblem {
interface: &dyn Interface,
) {
let config = self.representation.update_config(candidate);
let metric = format!("{}", rank.0);
let config = serde_yaml::to_string(&config).unwrap();
interface.post(Message::BetterSolution {
metric,
metric: rank.0.clone(),
config,
save,
})
Expand Down
11 changes: 5 additions & 6 deletions src/problems/snow2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ impl Problem for Snow2 {
interface: &dyn Interface,
) {
let config = self.representation.update_config(candidate);
let metric = format!("{}", rank.0);
let config = serde_yaml::to_string(&config).unwrap();
interface.post(Message::BetterSolution {
metric,
metric: rank.0.clone(),
config,
save,
})
Expand All @@ -69,7 +67,8 @@ impl Problem for Snow2 {
self.randomly_move_initial(candidate)
} else {
// 3. 随机交换两个《中华通韵》中的韵部
self.randomly_swap_final(candidate)
// self.randomly_swap_final(candidate)
self.randomly_move_final(candidate)
}
}
}
Expand All @@ -82,9 +81,9 @@ impl Snow2 {
let mut finals = vec![];
for element in (representation.radix as usize)..representation.initial.len() {
let repr = &representation.repr_element[&element];
if repr.starts_with("落声") {
if repr.starts_with("声介") || repr.starts_with("冰声") {
initials.push(element);
} else if repr.starts_with("落韵") {
} else if repr.starts_with("韵调") || repr.starts_with("冰韵") {
finals.push(element);
let chars: Vec<char> = repr.chars().collect();
let tone = chars[chars.len() - 1].to_digit(10).unwrap() - 1;
Expand Down

0 comments on commit c50446a

Please sign in to comment.