#memoization #struct #cache #xvrqt

memoizer

简单的函数备忘录结构体

5 个版本

0.2.2 2020年1月2日
0.2.1 2019年6月20日
0.2.0 2019年6月19日
0.1.1 2019年6月19日
0.1.0 2019年6月19日

#149 in 缓存

BSD-3-Clause

12KB
143

Memoizer

此结构体允许您将确定性、纯函数的结果进行备忘录化,以在重复函数调用中节省计算资源。此库的更好版本在此:此处

快速入门

将以下内容添加到您的 Cargo.toml 中

[dependencies]
memoize = "0.2.2"

将以下内容添加到您的 main/lib.rs 中

use memoizer::Memoizer;

fn main() {
    let mut increment = Memoizer::new(|n| {
        println!("Function Called");
        n + 1
    });

    
    println!("{}", increment.value(0));
    println!("{}", increment.value(0));
}   

这将打印

Fuction Called!
1
1

示例

简单的昂贵函数

函数 difficult(n: usize) 模拟一个计算昂贵的函数。它大约需要20毫秒来运行,并返回空值。当以随机输入(限于[0,9))调用500次时,它需要大约 ~2.5 秒。使用 Memoizer 结构体时,它需要 ~0.05 秒。

use std::thread::sleep;
use std::time::{Duration, Instant};

use rand::Rng;
use memoizer::Memoizer;

// Expensive Calculation
fn difficult(n: usize) {
    sleep(Duration::new(0,5000000));
}

fn main() {
    let mut rng = rand::thread_rng();

    let now = Instant::now();
    for i in 0..500 {
        difficult(rng.gen_range(0,10));
    }
    println!("Unmemoized Time: {:.2}", now.elapsed().as_millis() as f64 / 1000.0);

    let now = Instant::now();
    let mut memoized = Memoizer::new(difficult);
    for i in 0..500 {
        memoized.value(rng.gen_range(0,10));
    }
    println!("Memoized Time: {:.2}", now.elapsed().as_millis() as f64 / 1000.0);
}

这将打印

Unmemoized Time: 2.54
Memoized Time: 0.05

函数签名

提供给 Memoize 结构体的闭包必须接受单个参数并返回单个值。传递结构体、引用和堆分配的参数是允许的,但请确保它们实现了:Eq、Hash、Clone,以便它们可以作为 HashMap 中的键使用。幸运的是,大多数这些特性都可以为复杂类型推导。

返回值必须实现 Clone 特性,以便 HashMap 中的值不会被损坏。

以下是一个使用结构体作为输入参数并返回数字的示例。

use memoizer::Memoizer;

/* Dummy struct to test more complex inputs/returns */
#[derive(Debug, Clone, Hash)]
struct Dummy {
    pub id: usize,
    pub name: String,
}

/* PartialEq & Eq required for HashMap */
impl PartialEq for Dummy {
    fn eq(&self, other: &Dummy) -> bool {
        self.id == other.id && self.name == other.name
    }
}

impl Eq for Dummy {}

fn main() {
    let d = Dummy {
        id: 1,
        name: String::from("Amy"),
    };
    
    let mut calc = Memoizer::new(|d: Dummy| d.id + d.name.len());
    assert_eq!(4, calc.value(d));
}   

未来工作

目前,没有将递归函数进行备忘录化的能力,这是不幸的,因为动态规划是备忘录器可以真正大放异彩的地方,而且它们经常使用递归。在 v0.3.0 中寻找这个功能。

无运行时依赖