Default pipeline with backend arguments (#2557)

Depends on #2535 and standardizes the backend argument in `Pipeline`:
1. `backend` now defaults to `BackendType::Mock` when constructing the
pipeline.
2. For tests that only computes up to witgen without actually running
the backend, `with_backend_factory` API is used instead of
`with_backend`.
- If the test doesn't care which backend the witgen is computed for, NO
`with_backend_factory` is called, because the default pipeline already
defaults to `BackendType::Mock`.
- Note that `with_backend_factory(backend)` is equivalent to
`with_backend(backend, None)`.
3. For tests that generate proof, `with_backend` API is used.
This commit is contained in:
Steve Wang
2025-03-26 17:19:40 +08:00
committed by GitHub
parent 19d7117d37
commit b159d9e445
12 changed files with 24 additions and 46 deletions

View File

@@ -17,9 +17,10 @@ use powdr_number::{DegreeType, FieldElement};
use std::{collections::BTreeMap, io, path::PathBuf, sync::Arc};
use strum::{Display, EnumString, EnumVariantNames};
#[derive(Clone, EnumString, EnumVariantNames, Display, Copy)]
#[derive(Clone, Default, EnumString, EnumVariantNames, Display, Copy)]
pub enum BackendType {
#[strum(serialize = "mock")]
#[default]
Mock,
#[cfg(feature = "halo2")]
#[strum(serialize = "halo2")]

View File

@@ -426,7 +426,7 @@ fn execute<F: FieldElement>(
) -> Result<(), Vec<String>> {
let mut pipeline = Pipeline::<F>::default()
.from_asm_file(file_name.to_path_buf())
.with_backend(backend, None)
.with_backend_factory(backend)
.with_prover_inputs(inputs)
.with_output(output_dir.into(), true);

View File

@@ -1,5 +1,4 @@
use ::powdr_pipeline::Pipeline;
use powdr_backend::BackendType;
use powdr_number::GoldilocksField;
use criterion::{criterion_group, criterion_main, Criterion};
@@ -11,10 +10,8 @@ fn jit_witgen_benchmark(c: &mut Criterion) {
group.sample_size(10);
// Poseidon benchmark
let mut pipeline = Pipeline::<T>::default()
.from_file("../test_data/std/poseidon_benchmark.asm".into())
.with_backend(BackendType::Mock, None);
// this `jit_witgen_benchmark` function will also require backend type
let mut pipeline =
Pipeline::<T>::default().from_file("../test_data/std/poseidon_benchmark.asm".into());
pipeline.compute_backend_tuned_pil().unwrap();
pipeline.compute_fixed_cols().unwrap();

View File

@@ -105,8 +105,8 @@ struct Arguments<T: FieldElement> {
external_witness_values: Vec<(String, Vec<T>)>,
/// Callback for queries for witness generation.
query_callback: Option<Arc<dyn QueryCallback<T>>>,
/// Backend to use for proving. If None, proving will fail.
backend: Option<BackendType>,
/// Backend to use for proving. Defaults to Mock Backend.
backend: BackendType,
/// Backend options
backend_options: BackendOptions,
/// Linker options
@@ -365,19 +365,17 @@ impl<T: FieldElement> Pipeline<T> {
self
}
pub fn with_backend(mut self, backend: BackendType, options: Option<BackendOptions>) -> Self {
self.arguments.backend = Some(backend);
self.arguments.backend_options = options.unwrap_or_default();
pub fn with_backend_factory(mut self, backend: BackendType) -> Self {
self.arguments.backend = backend;
self.artifact.backend = None;
self
}
pub fn with_backend_if_none(&mut self, backend: BackendType, options: Option<BackendOptions>) {
if self.arguments.backend.is_none() {
self.arguments.backend = Some(backend);
self.arguments.backend_options = options.unwrap_or_default();
self.artifact.backend = None;
}
pub fn with_backend(mut self, backend: BackendType, options: Option<BackendOptions>) -> Self {
self.arguments.backend = backend;
self.arguments.backend_options = options.unwrap_or_default();
self.artifact.backend = None;
self
}
pub fn with_setup_file(mut self, setup_file: Option<PathBuf>) -> Self {
@@ -1002,7 +1000,7 @@ impl<T: FieldElement> Pipeline<T> {
self.compute_optimized_pil()?;
let backend_type = self.arguments.backend.expect("no backend selected!");
let backend_type = self.arguments.backend;
// If backend option is set, compute and cache the backend-tuned pil in artifacts and return backend-tuned pil.
let optimized_pil = self.artifact.optimized_pil.clone().unwrap();
@@ -1146,7 +1144,7 @@ impl<T: FieldElement> Pipeline<T> {
let pil = self.compute_backend_tuned_pil()?; // will panic if backend type is not set yet
let fixed_cols = self.compute_fixed_cols()?;
let backend = self.arguments.backend.expect("no backend selected!");
let backend = self.arguments.backend;
let factory = backend.factory::<T>();
// Opens the setup file, if set.

View File

@@ -172,7 +172,7 @@ fn block_to_block_empty_submachine() {
.iter()
.for_each(|backend| {
let mut pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus)
.with_backend(*backend, None);
.with_backend_factory(*backend);
let witness_and_publics = pipeline.compute_witness().unwrap();
let arith_size = witness_and_publics
.0
@@ -313,7 +313,7 @@ fn dynamic_vadcop() {
// Witness generation require backend to be known
for backend in [BackendType::Mock, BackendType::Plonky3].iter() {
let mut pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus)
.with_backend(*backend, None);
.with_backend_factory(*backend);
let witness = &pipeline.compute_witness().unwrap().0;
let witness_by_name = witness
.iter()
@@ -890,7 +890,6 @@ fn expand_fixed_jit() {
let file_name = "asm/expand_fixed.asm";
let mut pipeline = Pipeline::<GoldilocksField>::default()
.with_backend(BackendType::Mock, None)
.with_tmp_output()
.from_file(resolve_test_file(file_name));
let pil = pipeline.compute_backend_tuned_pil().unwrap();

View File

@@ -5,7 +5,6 @@ use test_log::test;
fn run_witgen_pil<T: FieldElement>(pil: &str) -> Columns<T> {
Pipeline::default()
.with_backend(powdr_pipeline::BackendType::Mock, None)
.from_pil_string(pil.to_string())
.compute_witness()
.unwrap()

View File

@@ -16,8 +16,7 @@ fn fibonacci_wrong_initialization() {
// Initializes y with 2 instead of 1
// -> fails `ISLAST * (y' - 1) = 0;` in the last row
let f = "pil/fibonacci.pil";
let pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus)
.with_backend(powdr_backend::BackendType::Mock, None);
let pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus);
let pipeline = pipeline.set_witness(vec![
// This would be the correct witness:
// col("Fibonacci::x", [1, 1, 2, 3]),
@@ -36,8 +35,7 @@ fn block_to_block_wrong_connection() {
// So, if we multiply all columns with a constant, the constraint
// should still be satisfied, but the connection argument should fail.
let f = "asm/block_to_block.asm";
let mut pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus)
.with_backend(powdr_backend::BackendType::Mock, None);
let mut pipeline = make_simple_prepared_pipeline::<GoldilocksField>(f, LinkerMode::Bus);
pipeline.compute_witness().unwrap();

View File

@@ -110,12 +110,9 @@ fn fibonacci() {
fn fibonacci_with_public() {
// Public references are not supported by the backends yet, but we can test witness generation.
let f = "pil/fibonacci_with_public.pil";
let pipeline: Pipeline<GoldilocksField> =
let mut pipeline: Pipeline<GoldilocksField> =
make_prepared_pipeline(f, vec![], vec![], LinkerMode::Bus);
pipeline
.with_backend(powdr_backend::BackendType::Mock, None)
.compute_witness()
.unwrap();
pipeline.compute_witness().unwrap();
}
#[test]

View File

@@ -1,5 +1,4 @@
use ::powdr_pipeline::Pipeline;
use powdr_backend::BackendType;
use powdr_number::GoldilocksField;
use powdr_riscv::{compile_rust_crate_to_riscv, elf, CompilerOptions};
@@ -19,9 +18,7 @@ fn executor_benchmark(c: &mut Criterion) {
compile_rust_crate_to_riscv("./tests/riscv_data/keccak/Cargo.toml", &tmp_dir, None);
let options = CompilerOptions::new_gl();
let contents = elf::translate(&executable, options);
let mut pipeline = Pipeline::<T>::default()
.from_asm_string(contents, None)
.with_backend(BackendType::Mock, None);
let mut pipeline = Pipeline::<T>::default().from_asm_string(contents, None);
pipeline.compute_backend_tuned_pil().unwrap();
pipeline.compute_fixed_cols().unwrap();

View File

@@ -59,8 +59,6 @@ pub fn rust_continuations<F: FieldElement, PipelineCallback, E>(
where
PipelineCallback: Fn(&mut Pipeline<F>) -> Result<(), E>,
{
pipeline.with_backend_if_none(powdr_pipeline::BackendType::Mock, None);
let bootloader_inputs = dry_run_result.bootloader_inputs;
let num_chunks = bootloader_inputs.len();
@@ -339,8 +337,6 @@ pub fn rust_continuations_dry_run<F: FieldElement>(
pipeline: &mut Pipeline<F>,
profiler_opt: Option<ProfilerOptions>,
) -> DryRunResult<F> {
pipeline.with_backend_if_none(powdr_pipeline::BackendType::Mock, None);
let field = F::known_field().unwrap();
// All inputs for all chunks.

View File

@@ -1,5 +1,4 @@
use mktemp::Temp;
use powdr_backend::BackendType;
use powdr_number::{BabyBearField, FieldElement, GoldilocksField, KnownField, KoalaBearField};
use powdr_pipeline::{
test_util::{test_mock_backend, test_plonky3_pipeline},
@@ -24,8 +23,7 @@ pub fn verify_riscv_asm_string<T: FieldElement, S: serde::Serialize + Send + Syn
let mut pipeline = Pipeline::default()
.with_prover_inputs(inputs.to_vec())
.with_output(temp_dir.to_path_buf(), true)
.from_asm_string(contents.to_string(), Some(PathBuf::from(file_name)))
.with_backend(BackendType::Mock, None);
.from_asm_string(contents.to_string(), Some(PathBuf::from(file_name)));
if let Some(data) = data {
pipeline = pipeline.add_data_vec(data);

View File

@@ -427,7 +427,6 @@ fn read_slice_with_options<T: FieldElement>(options: CompilerOptions) {
let mut pipeline = Pipeline::<T>::default()
.from_asm_string(powdr_asm, Some(PathBuf::from(case)))
.with_backend(powdr_backend::BackendType::Mock, None)
.with_prover_inputs(vec![answer.into()])
.with_prover_dict_inputs(d);
@@ -612,7 +611,6 @@ fn output_syscall_with_options<T: FieldElement>(options: CompilerOptions) {
let inputs = vec![1u32, 2, 3].into_iter().map(T::from).collect();
let mut pipeline = Pipeline::<T>::default()
.with_backend(powdr_backend::BackendType::Mock, None)
.from_asm_string(powdr_asm, Some(PathBuf::from(case)))
.with_prover_inputs(inputs);