1 个不稳定版本
0.1.0 | 2023年7月20日 |
---|
#778 在 算法
65KB
788 行
Chrono-probe
Chrono-probe 是一个用于测量算法时间复杂度的库。
为了测量算法的时间复杂度,你需要提供一个算法(或多个)以及为该算法生成输入的方法。然后库将测量算法在生成的不同长度的输入上的运行时间。这样,可以绘制算法随输入大小变化的耗时图。
库设计得尽可能灵活。只要算法可以表示为一个接收输入并返回输出的函数,就可以使用库来测量任何算法的时间复杂度。
如何使用chrono-probe
在本节中,我们将展示如何使用 chrono-probe 来测量排序算法的时间复杂度。我们将以 quicksort
算法为例。更多示例可以在 示例 文件夹中找到。
对于此示例,quicksort 算法的实现并不重要,定义可能如下所示
fn quick_sort<T: Ord + Clone>(v: &mut [T]) {
// ...
}
第一步是定义一个表示算法输入的类型。在这种情况下,我们希望测量排序向量 u32 的时间复杂度,因此我们定义了一个新的类型,它是一个 u32 的向量。这是因为 Rust 不允许我们为在其他包中定义的类型实现特性,我们需要为我们的类型实现 Input 特性。
#[derive(Clone)]
pub struct InputVec(Vec<u32>);
我们还可以为 InputVec 实现 Deref
和 DerefMut
,这样我们就可以将其用作 Vec<u32>
。这不是必需的,但它使得使用更加方便。
impl Deref for InputVec {
type Target = Vec<u32>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for InputVec {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
现在我们可以将 quicksort 算法定义为接收 InputVec 的函数。
fn quick_sort_measure(v: &mut InputVec) {
quick_sort(v);
}
下一步是实现为input::Input
为InputVec
实现的特质。这个特质定义了如何为算法生成输入以及输入的大小。在这种情况下,我们不需要在多个输入生成器之间进行选择,因此不需要Builder。有关如何使用Builder的更多信息,请参阅input::Input
特质的文档。
impl Input for InputVec {
// We don't need a Builder.
type Builder = ();
// Return the size of the input, in this case the size is the length of the vector.
fn get_size(&self) -> usize {
self.len()
}
// Generate a vector of the given size and fill it with random numbers.
fn generate_input(size: usize, _builder: &Self::Builder) -> Self {
let mut rng = thread_rng();
let mut v = Vec::with_capacity(size);
for _ in 0..size {
let rand: u32 = rng.gen();
v.push(rand);
}
InputVec(v)
}
}
现在我们已经实现了所有必要的特质,我们可以使用这个库来衡量算法。
在主函数中,我们为向量的长度创建一个分布。这里我们使用最小值为1000,最大值为500_000的线性分布。因此,所有向量的长度将在1000到500_000之间,并且长度将随机均匀选择。
let length_distribution = Linear::new(1000..=500_000);
下一步是为向量创建一个Builder。Builder用于生成向量,我们只需要指定向量的长度分布,因为我们不需要为InputVec创建Builder,所以我们可以使用()
作为Builder。
let vector_builder = InputBuilder::new(length_distribution, ());
现在我们可以构建向量。这里我们构建了200个向量,每种长度10个。
let mut vectors = vector_builder.build_with_repetitions(200, 10);
最后,我们可以测量算法。我们需要指定算法、输入和相关误差。相关误差用于确定每个输入大小应该运行算法的次数。算法将运行,直到相关误差小于给定的相关误差。我们使用measurements::measure_mut
函数,因为算法接受输入的可变引用。
// Create a slice of the algorithms we want to measure
let algorithms: & [( fn ( & mut input::InputVec), & str); 1] = & [
(quick_sort_input, "Quick sort"),
];
// Measure the algorithms on the vectors, given a relative error of 0.001
let results = measure_mut( & mut vectors, algorithms, 0.001);
结果作为measurements::Measurement
向量的形式返回。每个测量包含输入的大小、算法运行所需的时间和测量的相关误差。
可以使用plot::time_plot
函数来绘制结果。
// Plot the results
let config = PlotConfig::default ()
.with_title("Sorting algorithms")
.with_caption("The time plot of sorting algorithms");
time_plot(file_name, results, & config);
整个代码和其他示例可以在示例文件夹中找到。
安装Rust
如果您还没有安装Rust,可以通过运行以下命令进行安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
依赖项
~5.5–8MB
~143K SLoC