arcweight 0.3.0

A high-performance, modular library for weighted finite state transducers with comprehensive examples and benchmarks
Documentation
//! Difference operation benchmarks
//!
//! These benchmarks measure the performance of FST difference operations across
//! different FST sizes and structures.

use arcweight::algorithms::difference;
use arcweight::prelude::*;
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;

/// Create a linear FST with the specified number of states
fn create_linear_fst(size: usize, symbol_offset: u32) -> VectorFst<TropicalWeight> {
    let mut fst = VectorFst::new();

    if size == 0 {
        return fst;
    }

    // Add states
    let states: Vec<_> = (0..size).map(|_| fst.add_state()).collect();

    // Set start and final states
    fst.set_start(states[0]);
    fst.set_final(states[size - 1], TropicalWeight::one());

    // Add transitions in a chain
    for i in 0..size - 1 {
        fst.add_arc(
            states[i],
            Arc::new(
                (i % 26 + 97 + symbol_offset as usize) as u32,
                (i % 26 + 97 + symbol_offset as usize) as u32,
                TropicalWeight::new(1.0),
                states[i + 1],
            ),
        );
    }

    fst
}

fn bench_difference_linear(c: &mut Criterion) {
    let mut group = c.benchmark_group("difference_linear");

    for size in [10, 100, 500].iter() {
        // Create FSTs with overlapping symbol sets
        let fst1 = create_linear_fst(*size, 0);
        let fst2 = create_linear_fst(*size, 0); // Same symbols

        group.bench_function(format!("identical_linear_{size}"), |b| {
            b.iter(|| {
                let result: VectorFst<TropicalWeight> =
                    difference(black_box(&fst1), black_box(&fst2)).unwrap();
                black_box(result)
            })
        });

        // Create FSTs with partially overlapping symbols
        let fst3 = create_linear_fst(*size, 5); // Offset symbols

        group.bench_function(format!("partial_overlap_linear_{size}"), |b| {
            b.iter(|| {
                let result: VectorFst<TropicalWeight> =
                    difference(black_box(&fst1), black_box(&fst3)).unwrap();
                black_box(result)
            })
        });
    }

    group.finish();
}

fn bench_difference_disjoint(c: &mut Criterion) {
    let mut group = c.benchmark_group("difference_disjoint");

    for size in [50, 200, 500].iter() {
        // Create FSTs with completely disjoint symbol sets
        let fst1 = create_linear_fst(*size, 0); // symbols a-z
        let fst2 = create_linear_fst(*size, 26); // symbols A-Z (shifted by 26)

        group.bench_function(format!("disjoint_{size}"), |b| {
            b.iter(|| {
                let result: VectorFst<TropicalWeight> =
                    difference(black_box(&fst1), black_box(&fst2)).unwrap();
                black_box(result)
            })
        });
    }

    group.finish();
}

fn bench_difference_empty(c: &mut Criterion) {
    let mut group = c.benchmark_group("difference_empty");

    let empty_fst = VectorFst::<TropicalWeight>::new();
    let linear_fst = create_linear_fst(100, 0);

    group.bench_function("empty_x_linear", |b| {
        b.iter(|| {
            match difference::<TropicalWeight, _, _, VectorFst<TropicalWeight>>(
                black_box(&empty_fst),
                black_box(&linear_fst),
            ) {
                Ok(result) => black_box(result),
                Err(_) => black_box(VectorFst::<TropicalWeight>::new()),
            }
        })
    });

    group.bench_function("linear_x_empty", |b| {
        b.iter(|| {
            match difference::<TropicalWeight, _, _, VectorFst<TropicalWeight>>(
                black_box(&linear_fst),
                black_box(&empty_fst),
            ) {
                Ok(result) => black_box(result),
                Err(_) => black_box(VectorFst::<TropicalWeight>::new()),
            }
        })
    });

    group.finish();
}

criterion_group!(
    benches,
    bench_difference_linear,
    bench_difference_disjoint,
    bench_difference_empty
);
criterion_main!(benches);