generator API
Luna-Flow/mare_mark/generator 使基准测试输入可复现:它从一个运行种子为数据集、重复和区组派生相互独立的种子,构建生成上下文,并为序列化后的输入计算指纹。混合函数的推导见 generator 设计。
源码:src/generator/generator.mbt。
import {
"Luna-Flow/mare_mark/model",
"Luna-Flow/mare_mark/generator",
}
种子
derive_seed
derive_seed 由父种子、一个域名称和一个索引派生出子种子。
pub fn derive_seed(UInt64, String, Int) -> UInt64
结果取决于且只取决于这三个参数,只使用回绕的 64 位算术,因此在每个目标上都完全相同。请为每种用途使用不同的域(“dataset”、“noise”、用例 id),使不同用途的流互不相关。
test "derived seeds" {
let run_seed = 42UL
let first = @generator.derive_seed(run_seed, "dataset", 0)
let second = @generator.derive_seed(run_seed, "dataset", 1)
let other = @generator.derive_seed(run_seed, "noise", 0)
inspect(first == @generator.derive_seed(42UL, "dataset", 0), content="true")
inspect(first != second && first != other, content="true")
}
measurement_seed
measurement_seed 由运行种子及数据集、重复和区组的 id 派生出一次测量的种子。
pub fn measurement_seed(UInt64, Int, Int, Int) -> UInt64
它等于 derive_seed(derive_seed(derive_seed(seed, "dataset", d), "repetition", r), "block", b)。
test "measurement seeds" {
let a = @generator.measurement_seed(7UL, 0, 1, 2)
let b = @generator.measurement_seed(7UL, 0, 2, 1)
inspect(a != b, content="true")
inspect(
a == @generator.derive_seed(
@generator.derive_seed(@generator.derive_seed(7UL, "dataset", 0), "repetition", 1),
"block",
2,
),
content="true",
)
}
上下文与生成器
context
context 构建一个 @model.GenerationContext。
pub fn[Scale] context(UInt64, String, String, @model.DatasetKey[Scale], String, String) -> @model.GenerationContext[Scale]
参数:种子、套件 id、用例 id、数据集键、生成器 id 和生成器版本。它与 @model.GenerationContext::new 相同。
Generator
Generator 把一个生成函数与其身份和指纹捆绑在一起。
pub struct Generator[Scale, Input] {
id : String
version : String
generate : (@model.GenerationContext[Scale]) -> Input
fingerprint : (Input) -> String
}
pub fn[Scale, Input] Generator::new(String, String, (@model.GenerationContext[Scale]) -> Input, (Input) -> String) -> Self[Scale, Input]
每当 generate 生成的值发生变化时就提升 version;版本是上下文的一部分,也是每个输入来源信息的一部分。
test "a generator" {
let ramp : @generator.Generator[Int, Array[Int]] = @generator.Generator::new(
"ramp",
"1",
context => Array::makei(context.dataset_key.scale, i => i),
xs => @generator.stable_fingerprint(xs.map(x => x.to_string()).join(",")),
)
let context = @generator.context(1UL, "suite", "sum", @model.DatasetKey::new(4, 0), ramp.id, ramp.version)
let input = (ramp.generate)(context)
debug_inspect(input, content="[0, 1, 2, 3]")
inspect((ramp.fingerprint)(input).has_prefix("sha256:"), content="true")
}
指纹
stable_fingerprint
stable_fingerprint 返回 "sha256:",后接字符串 UTF-8 编码的 SHA-256 摘要的小写十六进制形式。
pub fn stable_fingerprint(String) -> String
请先把输入规范地序列化;指纹标识的是序列化结果,而不是内存中的值。它是一个无密钥的哈希:它能检测意外的改动,但不能认证数据。
test "fingerprint" {
inspect(
@generator.stable_fingerprint("abc"),
content="sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
)
}