rsgridsynth 0.2.2

Rust-based synthesizer that decomposes single-qubit Z-axis rotations into Clifford+T gate sequences
Documentation
use rsgridsynth::clear_caches;
use rsgridsynth::config::config_from_theta_epsilon;
use rsgridsynth::gridsynth::gridsynth_gates;
use serial_test::serial;

#[test]
#[serial]
fn simple_test() {
    let pi = std::f64::consts::PI;
    let theta = pi / 8.0; // ≈ 0.39269908169872414
    let epsilon = 1e-10;

    let gates_1234 = "HTHTSHTSHTHTSHTHTSHTHTHTSHTSHTHTHTHTHTHTSHTSHTHTSHTSHTSHTSHTHTSHTSHTSHTHTHTHTHTHTSHTSHTHTSHTSHTSHTHTHTSHTSHTSHTSHTSHTSHTSHTHTHTHTHTSHTSHTSHTSHTSHTSHTHTHTHTHTSHTHTSHTHTHTSHTSHTSHTHTSHTSHTHTSHTHTSHTSHTHTSHTHTHTSHTSHTSHTSHTHTHTHTSHTHTHTSHTHTSHTHTHTSHTHTSHTHTSHTXSSWWW";

    let gates_101 = "HTSHTSHTSHTHTHTSHTHTHTSHTSHTHTHTHTHTHTSHTHTHTHTSHTSHTHTSHTHTHTHTHTHTHTHTSHTHTHTHTSHTHTSHTSHTSHTSHTHTSHTSHTHTSHTSHTHTSHTHTHTSHTSHTHTHTHTSHTHTSHTHTSHTHTHTSHTSHTHTHTHTHTSHTHTSHTSHTHTHTHTSHTHTHTSHTHTHTHTSHTHTSHTSHTHTSHTHTSHTHTHTHTHTHTHTHTSHTHTHTSHTSSSWW";

    let gates_1 = "HTSHTHTHTSHTHTHTHTHTHTHTHTSHTHTSHTHTSHTSHTHTSHTHTHTHTSHTHTHTSHTHTHTHTSHTSHTHTSHTHTHTHTHTSHTSHTHTHTSHTHTSHTHTSHTHTHTHTSHTSHTHTHTSHTHTSHTSHTHTSHTSHTHTSHTSHTSHTSHTHTSHTHTHTHTSHTHTHTHTHTHTHTHTSHTHTSHTSHTHTHTHTSHTHTHTHTHTHTSHTSHTHTHTSHTHTHTSHTSHTSHTSSSWW";

    let test_inputs = vec![(1234, gates_1234), (101, gates_101), (1, gates_1)];

    let verbose = false;
    let up_to_phase = false;
    for (seed, expected_gates) in test_inputs {
        clear_caches();
        let mut gridsynth_config =
            config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase);
        let gates = gridsynth_gates(&mut gridsynth_config).gates;
        assert_eq!(gates, expected_gates, "Test failed for seed: {}", seed);
    }
}

#[test]
#[serial]
fn pi_over_two_test() {
    let pi = std::f64::consts::PI;
    let theta = pi / 2.0;

    let epsilons = vec![1e-2, 1e-3, 1e-10];

    let verbose = false;
    let up_to_phase = false;
    for epsilon in epsilons {
        let seeds = 10..50;
        for seed in seeds {
            clear_caches();
            let mut gridsynth_config =
                config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase);
            let gates = gridsynth_gates(&mut gridsynth_config).gates;
            let expected_gates = "SWWWWWWW";
            assert_eq!(gates, expected_gates);
        }
    }
}

#[test]
#[serial]
fn pi_over_4_exact_test() {
    let pi = std::f64::consts::PI;
    let theta = pi / 4.0;
    let epsilon = 1e-10;
    let seed = 1234;
    let up_to_phase = false;
    let verbose = false;
    let mut gridsynth_config =
        config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase);
    let gates = gridsynth_gates(&mut gridsynth_config).gates;
    let expected_gates = "SHTSHTHTSHTSHTHTSHTHTHTSHTSHTSHTHTSHTSHTHTHTSHTSHTSHTHTHTSHTHTSHTSHTSHTSHTSHTSHTSHTHTHTHTSHTHTHTHTHTHTSHTSHTHTHTSHTSHTHTHTHTSHTSHTHTSHTSHTSHTHTSHTHTHTSHTSHTHTSHTSHTSHTHTSHTHTHTSHTHTHTSHTSHTSHTSHTHTHTHTHTSHTSHTSHTHTSHTSHTHTSHTHTSHTHTHTHTSHTSHTHTSHTSHTSHTHTSHTSHTSHTHTSHTHTHTSHTHTHTSHTSHTHTSHTSHTHTSHTSHTSHTHTHTSHTSHTSHTSHTHTHTHTSHTHTHTHTHTSHTSHTHTSHSWW";

    assert_eq!(gates, expected_gates);
}

#[test]
#[serial]
fn pi_over_4_with_phase_test() {
    let pi = std::f64::consts::PI;
    let theta = pi / 4.0;
    let epsilon = 1e-10;
    let seed = 1234;
    let up_to_phase = true;
    let verbose = false;
    let mut gridsynth_config =
        config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase);
    let gates = gridsynth_gates(&mut gridsynth_config).gates;
    let expected_gates = "TWWWWWWW";
    assert_eq!(gates, expected_gates);
}

#[test]
#[serial]
fn test_correct_decomposition_exact() {
    let epsilon = 1e-10;

    let verbose = false;
    let seed = 0u64;
    let up_to_phase = false;

    let thetas = (0..64).map(|k| k as f64 * std::f64::consts::PI / 32.0);

    for theta in thetas {
        clear_caches();
        let mut gridsynth_config =
            config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase)
                .with_compute_error(true);

        let res = gridsynth_gates(&mut gridsynth_config);

        // not printed, unless cargo test is run with -- -no-capture
        match res.error {
            Some(error) => {
                println!(
                    "theta = {theta}, gates = {}, error = {:.6e}, correct = {:?}",
                    res.gates, error, res.is_correct,
                )
            }
            None => panic!("Expected computed error"),
        }

        // Check that the check result exits and is valid.
        assert!(res.is_correct.is_some_and(|v| v));
    }
}

#[test]
#[serial]
fn test_correct_decomposition_up_to_phase() {
    let epsilon = 1e-10;

    let verbose = false;
    let seed = 0u64;
    let up_to_phase = true;

    let thetas = (0..64).map(|k| k as f64 * std::f64::consts::PI / 32.0);

    for theta in thetas {
        clear_caches();
        let mut gridsynth_config =
            config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase)
                .with_compute_error(true);

        let res = gridsynth_gates(&mut gridsynth_config);

        // not printed, unless cargo test is run with -- -no-capture
        match res.error {
            Some(error) => {
                println!(
                    "theta = {theta}, gates = {}, error = {:.6e}, correct = {:?}",
                    res.gates, error, res.is_correct,
                )
            }
            None => panic!("Expected computed error"),
        }
        // Check that the check result exits and is valid.
        assert!(res.is_correct.is_some_and(|v| v));
    }
}

#[test]
#[serial]
fn test_low_precision_bug() {
    let pi = std::f64::consts::PI;
    let theta = pi / 2.0;
    let epsilon = 1e-1;
    let verbose = false;
    let mut gridsynth_config = config_from_theta_epsilon(theta, epsilon, 1234, verbose, false);
    gridsynth_gates(&mut gridsynth_config);
}

#[test]
#[serial]
fn test_shared_cache_across_denomexp_no_panic() {
    let epsilon = 1e-3;
    let verbose = false;
    let seed = 0u64;
    let up_to_phase = true;
    let mut panic_thetas = Vec::new();
    let mut incorrect_thetas = Vec::new();
    let mut max_error = 0.0_f64;

    clear_caches();
    for i in 1..=320 {
        let theta = i as f64 * 0.01;
        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            let mut gridsynth_config =
                config_from_theta_epsilon(theta, epsilon, seed, verbose, up_to_phase)
                    .with_compute_error(true);
            gridsynth_gates(&mut gridsynth_config)
        }));

        match result {
            Ok(res) => {
                if let Some(error) = res.error {
                    max_error = max_error.max(error);
                }
                if !res.is_correct.is_some_and(|v| v) {
                    incorrect_thetas.push(theta);
                }
            }
            Err(_) => panic_thetas.push(theta),
        }
    }

    println!(
        "shared-cache scan: n=320 epsilon={epsilon} panics={} incorrect={} max_error={max_error:.6e}",
        panic_thetas.len(),
        incorrect_thetas.len()
    );
    assert!(panic_thetas.is_empty(), "panic_thetas={panic_thetas:?}");
    assert!(
        incorrect_thetas.is_empty(),
        "incorrect_thetas={incorrect_thetas:?}"
    );
}

#[test]
#[serial]
fn test_timeouts_preserved_after_synthesis() {
    let mut gridsynth_config =
        config_from_theta_epsilon(std::f64::consts::PI / 8.0, 1e-10, 1234, false, true);
    gridsynth_config.diophantine_data.diophantine_timeout = 237;
    gridsynth_config.diophantine_data.factoring_timeout = 61;

    clear_caches();
    let result = gridsynth_gates(&mut gridsynth_config);

    assert!(!result.gates.is_empty());
    assert_eq!(gridsynth_config.diophantine_data.diophantine_timeout, 237);
    assert_eq!(gridsynth_config.diophantine_data.factoring_timeout, 61);
}