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",
  )
}