3 个版本 (重大更新)
0.3.0 | 2023年2月26日 |
---|---|
0.2.0 | 2023年2月21日 |
0.1.0 | 2023年2月16日 |
#951 in 算法
20KB
261 行
L-系统构建器
林登迈尔系统(或 L-系统)是一种简单的无上下文文法,它使用一组 符号 和一组 规则 来迭代地重写这些符号。通常很有趣的是将 L-系统的符号解释为一系列 动作,然后可以将这些动作可视化。
作为介绍,可以考虑原始的 L-系统,它只使用符号 "A" 和 "B",以及两个规则:“A" ⇒ "AB"(A 变成 AB)和 "B" ⇒ "A"(B 变成 A)。现在从一些称为 公理 的初始符号字符串开始,我们可以应用这些规则。假设我们只从 "A" 开始,那么我们将得到以下字符串序列。
- A
- AB
- ABA
- ABAAB
- ABAABABA
- ABAABABAABAAB
我们可以如下表示这个系统。
use lindenmayer::LSystem;
let axiom = String::from("A");
let rules = [
('A', "AB"), ('B', "A")
];
let system = LSystem::new(axiom, &rules);
可以使用 LSystem
结构来生成一个字符串或迭代器,该迭代器将生成符号。
let depth = 5;
println!("{}",system.string(depth));
// ABAABABAABAAB
println!("{}",system.builder(depth).collect::<String>());
// ABAABABAABAAB
更复杂的 L-系统有更多的符号和规则。重要的是,这些系统可以包含 终端符号,即应用规则时不会改变的符号,或者等价地,有一个规则将它们自身转换为自身,如 "C" ⇒ "C"(C 变成 C)。由于 LSystem
的方法是如何实现的,最好根本不包含这些符号的规则,这表示程序可以立即返回符号。考虑一个包含比规则更多的符号的更复杂的 L-系统。
let axiom = String::from("X");
let rules = [
('X', "F[X][+FX]-FX"),
];
let system = LSystem::new(axiom, &rules);
在这里,符号 "F"、"["、"]"、"+"、"-" 都是隐式终端符号,因为不存在它们的规则。尽管它们被 "X" 规则添加到结果字符串中,但一旦引入,它们就永远不会变成其他任何东西。这个系统产生的字符串相当长。
let depth = 3;
println!("{}",system.string(depth));
// F[F[F[X][+FX]-FX][+FF[X][+FX]-FX]-FF[X][+FX]-FX][+FF[F[X][+FX]-FX][+FF[X][+FX]-FX]-FF[X][+FX]-FX]-FF[F[X][+FX]-FX][+FF[X][+FX]-FX]-FF[X][+FX]-FX
如果将深度参数设置得非常高,则结果字符串的长度会变得任意大,增长速度也会相当高。对于深度为 12,上述系统将需要分配三个兆字节,并且在深度为 16 时内存使用量超过了一千兆字节。当使用 .builder
方法时,所需的唯一内存使用量是每级递归一对指针。如果不需要保存字符串,这可能是更好的选择。
迭代器的一个用法是将系统解释为一串指令。如果适当解释,这个字符串可以产生一个类似树形的图像。
不要求L-系统必须是确定性的。在随机L-系统中,每个符号都通过从一组规则中随机选择的规则进行重写。这些可以通过具有替换部分规则的LSystemStochastic
结构体来创建,该规则部分由Vec<(&str,f32)>
指定,其中每个条目包含可能的替换及其相对于其他选项的概率。接口与其他LSystem
类似,只是需要一个Option<u64>
来初始化.string()
和.builder()
方法。
use lindenmayer::builder::LSystemStochastic;
let axiom = String::from("X");
let rules = [
('X', &vec![("F[X][+DX]-DX", 1.0)]),
('D', &vec![("F", 2.0), ("FF", 1.0), ("D", 1.0)])
];
let system = LSystemStochastic::new(axiom, &rules);
let depth = 2;
let seed = Some(19251989);
println!("{}", system.string(depth, seed));
//F[F[X][+DX]-DX][+FFF[X][+DX]-DX]-FF[X][+DX]-DX
依赖关系
~405KB