diff --git a/concrete-optimizer/src/noise_estimator/operators/mod.rs b/concrete-optimizer/src/noise_estimator/operators/mod.rs index cb66c1737..b1fa230bf 100644 --- a/concrete-optimizer/src/noise_estimator/operators/mod.rs +++ b/concrete-optimizer/src/noise_estimator/operators/mod.rs @@ -1 +1,2 @@ pub mod atomic_pattern; +pub mod wop_atomic_pattern; diff --git a/concrete-optimizer/src/noise_estimator/operators/wop_atomic_pattern.rs b/concrete-optimizer/src/noise_estimator/operators/wop_atomic_pattern.rs new file mode 100644 index 000000000..5117233bc --- /dev/null +++ b/concrete-optimizer/src/noise_estimator/operators/wop_atomic_pattern.rs @@ -0,0 +1,43 @@ +use concrete_commons::dispersion::{DispersionParameter, Variance}; +use concrete_commons::key_kinds::BinaryKeyKind; +use concrete_commons::numeric::UnsignedInteger; +use concrete_npe::KeyDispersion; + +use crate::parameters::PbsParameters; +use crate::utils::square; + +pub fn estimate_packing_private_keyswitch( + var_glwe: Variance, + var_ggsw: Variance, + param: PbsParameters, +) -> Variance +where + T: UnsignedInteger, +{ + type K = BinaryKeyKind; + let l = param.br_decomposition_parameter.level as f64; + let b = (1 << param.br_decomposition_parameter.log2_base) as f64; + let n = (param.output_glwe_params.glwe_dimension * param.output_glwe_params.polynomial_size()) + as f64; // param.internal_lwe_dimension.0 as f64; + let b2l = f64::powf(b, 2. * l); + let var_s_w = 1. / 4.; + let mean_s_w = 1. / 2.; + // println!("n = {}", n); + let res_1 = + (l * (n + 1.) * var_ggsw.get_modular_variance::()) as f64 * (square(b) + 2.) / 12.; + + #[allow(clippy::cast_possible_wrap)] + let log_q = T::BITS as i32; + + let res_3 = ((square(f64::powi(2., log_q)) as f64 - b2l) / (12. * b2l) + * (1. + + n * (K::variance_key_coefficient::().get_modular_variance::() + + square(K::expectation_key_coefficient()))) + + n / 4. * K::variance_key_coefficient::().get_modular_variance::() + + var_glwe.get_modular_variance::()) + * (var_s_w + square(mean_s_w)); + + let res_5 = var_s_w * (1. / 4. * square(1. - n * K::expectation_key_coefficient())); + + Variance::from_modular_variance::(res_1 + res_3 + res_5) +} diff --git a/concrete-optimizer/src/optimization/mod.rs b/concrete-optimizer/src/optimization/mod.rs index b18d26ead..38011bd76 100644 --- a/concrete-optimizer/src/optimization/mod.rs +++ b/concrete-optimizer/src/optimization/mod.rs @@ -1,2 +1,3 @@ pub mod atomic_pattern; pub mod dag; +pub mod wop_atomic_pattern; diff --git a/concrete-optimizer/src/optimization/wop_atomic_pattern/mod.rs b/concrete-optimizer/src/optimization/wop_atomic_pattern/mod.rs new file mode 100644 index 000000000..f32d0e51d --- /dev/null +++ b/concrete-optimizer/src/optimization/wop_atomic_pattern/mod.rs @@ -0,0 +1,2 @@ +pub mod optimize; +pub(self) mod pareto; diff --git a/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs b/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs new file mode 100644 index 000000000..36355f0fb --- /dev/null +++ b/concrete-optimizer/src/optimization/wop_atomic_pattern/optimize.rs @@ -0,0 +1,654 @@ +use crate::computing_cost::complexity::Complexity; +use crate::computing_cost::operators::atomic_pattern as complexity_atomic_pattern; +use crate::computing_cost::operators::keyswitch_lwe::KeySwitchLWEComplexity; +use crate::computing_cost::operators::pbs::PbsComplexity; +use crate::noise_estimator::error::{ + error_probability_of_sigma_scale, sigma_scale_of_error_probability, +}; + +use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern; +use crate::noise_estimator::operators::wop_atomic_pattern::estimate_packing_private_keyswitch; + +use crate::optimization::atomic_pattern; +use crate::optimization::wop_atomic_pattern::pareto::{ + BR_BL, BR_BL_FOR_CB, CB_V1_BL, KS_BL, KS_BL_FOR_CB, +}; +use crate::parameters::{ + GlweParameters, KeyswitchParameters, KsDecompositionParameters, LweDimension, PbsParameters, +}; +use crate::security; +use crate::utils::square; + +use complexity_atomic_pattern::DEFAULT as DEFAULT_COMPLEXITY; +use concrete_commons::dispersion::{DispersionParameter, Variance}; +use concrete_commons::numeric::UnsignedInteger; +use std::collections::HashMap; + +pub fn find_p_error(kappa: f64, variance_max: f64, current_maximum_noise: f64) -> f64 { + let sigma = Variance(variance_max).get_standard_dev() * kappa; + let sigma_scale = sigma / Variance(current_maximum_noise).get_standard_dev(); + error_probability_of_sigma_scale(sigma_scale) +} + +#[derive(Clone, Debug)] +pub struct OptimizationState { + pub best_solution: Option, + pub count_domain: usize, +} + +#[derive(Clone, Debug)] +pub struct Solution { + pub input_lwe_dimension: u64, + //n_big + pub internal_ks_output_lwe_dimension: u64, + //n_small + pub ks_decomposition_level_count: u64, + //l(KS) + pub ks_decomposition_base_log: u64, + //b(KS) + pub glwe_polynomial_size: u64, + //N + pub glwe_dimension: u64, + //k + pub br_decomposition_level_count: u64, + //l(BR) + pub br_decomposition_base_log: u64, + //b(BR) + pub complexity: f64, + pub noise_max: f64, + pub p_error: f64, + // error probability + pub cb_decomposition_level_count: Option, + pub cb_decomposition_base_log: Option, +} + +impl Solution { + pub fn init() -> Self { + Self { + input_lwe_dimension: 0, + internal_ks_output_lwe_dimension: 0, + ks_decomposition_level_count: 0, + ks_decomposition_base_log: 0, + glwe_polynomial_size: 0, + glwe_dimension: 0, + br_decomposition_level_count: 0, + br_decomposition_base_log: 0, + complexity: 0., + noise_max: 0.0, + p_error: 0.0, + cb_decomposition_level_count: None, + cb_decomposition_base_log: None, + } + } +} + +#[allow(clippy::type_complexity)] +#[derive(Debug)] +pub struct Tab { + pbs: HashMap<(u64, u64, u64, u64, u64), (f64, Complexity)>, + modulus_switching: HashMap<(u64, u64), (f64, f64)>, + key_switching: HashMap<(u64, u64, u64, u64, u64), (f64, Complexity)>, + // NEW VALUE MEMOIZED + pp_switching: HashMap<(u64, u64, u64, u64), (f64, Complexity)>, +} + +#[allow(clippy::too_many_lines)] +pub fn tabulate_circuit_bootstrap( + security_level: u64, + maximum_acceptable_error_probability: f64, + glwe_log_polynomial_sizes: &[u64], + glwe_dimensions: &[u64], + internal_lwe_dimensions: &[u64], +) -> Tab { + assert_eq!(security_level, 128); + assert!(0.0 < maximum_acceptable_error_probability); + assert!(maximum_acceptable_error_probability < 1.0); + + let ciphertext_modulus_log = W::BITS as u64; + let mut noise_cost_pbs = HashMap::new(); + let mut noise_cost_modulus_switching = HashMap::new(); + let mut noise_cost_key_switching = HashMap::new(); + let mut noise_cost_pp_switching = HashMap::new(); + + for &glwe_dim in glwe_dimensions { + for &glwe_log_poly_size in glwe_log_polynomial_sizes { + assert!(8 <= glwe_log_poly_size); + assert!(glwe_log_poly_size < 18); + let glwe_poly_size = 1 << glwe_log_poly_size; + + if glwe_dim * glwe_poly_size <= 1 << 13 { + let glwe_params = GlweParameters { + log2_polynomial_size: glwe_log_poly_size, + glwe_dimension: glwe_dim, + }; + let variance_bsk = security::glwe::minimal_variance( + glwe_params, + ciphertext_modulus_log, + security_level, + ); + + for &internal_dim in internal_lwe_dimensions { + assert!(256 < internal_dim); + + let variance_ksk = noise_atomic_pattern::variance_ksk( + internal_dim, + ciphertext_modulus_log, + security_level, + ); + let noise_modulus_switching = + noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key::( + internal_dim, + glwe_params.polynomial_size(), + ) + .get_variance(); + let _ = noise_cost_modulus_switching.insert( + (internal_dim, glwe_poly_size), + (noise_modulus_switching, 0.), + ); + + for &br_decomposition_parameter in BR_BL.iter() { + let pbs_parameters = PbsParameters { + internal_lwe_dimension: LweDimension(internal_dim), + br_decomposition_parameter, + output_glwe_params: glwe_params, + }; + + let complexity_pbs = DEFAULT_COMPLEXITY + .pbs + .complexity(pbs_parameters, ciphertext_modulus_log); + + // let complexity_cmux = + // complexity_pbs / (pbs_parameters.internal_lwe_dimension.0 as f64); + + // PBS of the first layer of the CB + let base_noise = noise_atomic_pattern::variance_bootstrap::( + pbs_parameters, + ciphertext_modulus_log, + variance_bsk, + ) + .get_variance(); + + let _ = noise_cost_pbs.insert( + ( + glwe_dim, + glwe_poly_size, + internal_dim, + br_decomposition_parameter.log2_base, + br_decomposition_parameter.level, + ), + (base_noise, complexity_pbs), + ); + } + + for &ks_decomposition_parameter in KS_BL_FOR_CB.iter() { + let keyswitch_parameter = KeyswitchParameters { + input_lwe_dimension: LweDimension(glwe_poly_size * glwe_dim), + output_lwe_dimension: LweDimension(internal_dim), + ks_decomposition_parameter, + }; + let complexity_keyswitch = DEFAULT_COMPLEXITY + .ks_lwe + .complexity(keyswitch_parameter, ciphertext_modulus_log); + // Keyswitch before bootstrap + let noise_keyswitch = noise_atomic_pattern::variance_keyswitch::( + keyswitch_parameter, + ciphertext_modulus_log, + variance_ksk, + ) + .get_variance(); + let _ = noise_cost_key_switching.insert( + ( + glwe_dim, + glwe_poly_size, + internal_dim, + ks_decomposition_parameter.log2_base, + ks_decomposition_parameter.level, + ), + (noise_keyswitch, complexity_keyswitch), + ); + } + + // let pp_ks_decomposition_parameter = pbs_parameters.br_decomposition_parameter; + for &pp_ks_decomposition_parameter in BR_BL.iter() { + let ppks_parameter = PbsParameters { + internal_lwe_dimension: LweDimension( + glwe_params.glwe_dimension * glwe_params.polynomial_size(), + ), + br_decomposition_parameter: pp_ks_decomposition_parameter, + output_glwe_params: glwe_params, + }; + // We assume the packing KS and theexternal product in a PBSto have + // the same parameters (base, level) + let noise_private_packing_ks = estimate_packing_private_keyswitch::( + Variance(0.), + variance_bsk, + ppks_parameter, + ) + .get_variance(); + + let ppks_parameter_complexity = KeyswitchParameters { + input_lwe_dimension: LweDimension( + glwe_params.glwe_dimension * glwe_params.polynomial_size(), + ), + output_lwe_dimension: LweDimension( + glwe_params.glwe_dimension * glwe_params.polynomial_size(), + ), + ks_decomposition_parameter: KsDecompositionParameters { + level: pp_ks_decomposition_parameter.level, + log2_base: pp_ks_decomposition_parameter.log2_base, + }, + }; + let complexity_ppks = DEFAULT_COMPLEXITY + .ks_lwe + .complexity(ppks_parameter_complexity, ciphertext_modulus_log); + let _ = noise_cost_pp_switching.insert( + ( + glwe_dim, + glwe_poly_size, + pp_ks_decomposition_parameter.log2_base, + pp_ks_decomposition_parameter.level, + ), + (noise_private_packing_ks, complexity_ppks), + ); + } + } + } + } + } + Tab { + pbs: noise_cost_pbs, + modulus_switching: noise_cost_modulus_switching, + key_switching: noise_cost_key_switching, + pp_switching: noise_cost_pp_switching, + } +} + +const BITS_PADDING_WITHOUT_NOISE: u64 = 1; + +#[allow(clippy::expect_fun_call)] +#[allow(clippy::identity_op)] +#[allow(clippy::too_many_lines)] +pub fn optimise_one_with_memo( + precision: u64, // max precision of a word + log_norm: f64, // ?? norm2 of noise multisum, complexity of multisum is neglected + _security_level: u64, + maximum_acceptable_error_probability: f64, + glwe_log_polynomial_sizes: &[u64], + glwe_dimensions: &[u64], + internal_lwe_dimensions: &[u64], + n_functions_log: u64, // Many functions at the same time, stay at 1 for start + memo: &Tab, + n_inputs: u64, // Tau (nb blocks) +) -> OptimizationState { + assert!(n_functions_log == 0); // update complexity scaling + assert!(0.0 < maximum_acceptable_error_probability); + assert!(maximum_acceptable_error_probability < 1.0); + + let ciphertext_modulus_log = W::BITS as u64; + + // Circuit BS bound + // 1 bit of message only here =) + let no_noise_bits = 0 + 1 + BITS_PADDING_WITHOUT_NOISE; + let noise_bits = ciphertext_modulus_log - no_noise_bits; + let fatal_noise_limit = (1_u64 << noise_bits) as f64; + let kappa: f64 = sigma_scale_of_error_probability(maximum_acceptable_error_probability); + let safe_sigma = fatal_noise_limit / kappa; + // Bound for first bit extract in BitExtract (dominate others) + let variance_max = Variance::from_modular_variance::(square(safe_sigma)).get_variance(); + + let mut state = OptimizationState { + best_solution: None, + count_domain: glwe_dimensions.len() + * glwe_log_polynomial_sizes.len() + * internal_lwe_dimensions.len() + * KS_BL.len() + * BR_BL.len(), + }; + + let mut best_complexity = f64::INFINITY; + + for &glwe_dim in glwe_dimensions { + for &glwe_log_poly_size in glwe_log_polynomial_sizes { + let glwe_poly_size = 1 << glwe_log_poly_size; + + if glwe_dim * glwe_poly_size <= 1 << 13 { + // Manual experimental CUT + let glwe_params = GlweParameters { + log2_polynomial_size: glwe_log_poly_size, + glwe_dimension: glwe_dim, + }; + + for &internal_dim in internal_lwe_dimensions { + let &(noise_modulus_switching, _) = memo + .modulus_switching + .get(&(internal_dim, glwe_poly_size)) + .expect(&format!( + "Internal_dim : {} ; glwe poly size: {}", + internal_dim, glwe_poly_size + )); + + // BlindRotate dans Circuit BS + for &br_decomposition_parameter in BR_BL_FOR_CB.iter() { + // Pbs dans BitExtract et Circuit BS et FP-KS (partagés) + // TODO: choisir indépendemment(separate FP-KS) + let pbs_parameters = PbsParameters { + internal_lwe_dimension: LweDimension(internal_dim), + br_decomposition_parameter, + output_glwe_params: glwe_params, + }; + + let &(base_noise, complexity_pbs) = memo + .pbs + .get(&( + glwe_dim, + glwe_poly_size, + internal_dim, + br_decomposition_parameter.log2_base, + br_decomposition_parameter.level, + )) + .unwrap(); + + // CircuitBootstrap: new parameters l,b + for &circuit_pbs_decomposition_parameter in CB_V1_BL.iter() { + // Hybrid packing + let nb_cmux = 1_u64; + let cmux_tree_blind_rotate_parameters = PbsParameters { + internal_lwe_dimension: LweDimension(nb_cmux), // complexity for 1 cmux + br_decomposition_parameter: circuit_pbs_decomposition_parameter, + output_glwe_params: pbs_parameters.output_glwe_params, + }; + + // Hybrid packing (rename) + let complexity_cmux_for_cb = DEFAULT_COMPLEXITY.pbs.complexity( + cmux_tree_blind_rotate_parameters, + ciphertext_modulus_log, + ); // TODO: missing fft transform + + // Hybrid packing (Do we have 1 or 2 groups) + #[allow(clippy::precedence)] + let complexity_cmux_tree = if precision * n_inputs as u64 // sum of precisions + > pbs_parameters.output_glwe_params.log2_polynomial_size + { + // 2 groups + complexity_cmux_for_cb + * (1 << (precision * n_inputs + - pbs_parameters.output_glwe_params.log2_polynomial_size) + - 1) as f64 + // * (f64::exp2( + // (precision * n_inputs + // - pbs_parameters + // .output_glwe_params + // .log2_polynomial_size) + // as f64, + // ) - 1.) + } else { + // 1 group, no cmux tree + 0. + }; + // Hybrid packing blind rotate + let complexity_g_br = complexity_cmux_for_cb + * f64::min( + (pbs_parameters.output_glwe_params.log2_polynomial_size) as f64, + (precision * n_inputs) as f64, + ); + + // private packing keyswitch, <=> FP-KS (Circuit Boostrap) + let pp_ks_decomposition_parameter = + pbs_parameters.br_decomposition_parameter; + // for &pp_ks_decomposition_parameter in PP_KS_BL.iter() { // independant params for FP-KS + // Circuit Boostrap + let &(mut noise_private_packing_ks, complexity_ppks) = memo + .pp_switching + .get(&( + glwe_dim, + glwe_poly_size, + pp_ks_decomposition_parameter.log2_base, + pp_ks_decomposition_parameter.level, + )) + .expect(&format!( + "{}, {}, {}, {}", + glwe_dim, + glwe_poly_size, + pp_ks_decomposition_parameter.log2_base, + pp_ks_decomposition_parameter.level, + )); + noise_private_packing_ks += base_noise / 2.; + + // Circuit Boostrap + if noise_private_packing_ks + noise_modulus_switching > variance_max + || (precision - 1) as f64 * complexity_pbs + complexity_ppks + > best_complexity + { + continue; + } + + let noise_ggsw = noise_private_packing_ks; + + let noise_one_external_product_for_cmux_tree = + noise_atomic_pattern::variance_bootstrap::( + cmux_tree_blind_rotate_parameters, + ciphertext_modulus_log, + Variance::from_variance(noise_ggsw), + ) + .get_variance(); + + // all fp-ks + let complexity_all_ppks = + ((pbs_parameters.output_glwe_params.glwe_dimension + 1) + * circuit_pbs_decomposition_parameter.level + * precision) as f64 + * complexity_ppks; + + // final out noise hybrid packing + let noise_cmux_tree_blind_rotate = + noise_one_external_product_for_cmux_tree + * (precision * n_inputs) as f64; + + let noise_multisum = + (2_f64.powf(2. * log_norm as f64)) * noise_cmux_tree_blind_rotate; // out noise * weights + + // Shared by all pbs (like brs) + for &ks_decomposition_parameter in KS_BL_FOR_CB.iter() { + let keyswitch_parameter = KeyswitchParameters { + input_lwe_dimension: LweDimension(glwe_poly_size * glwe_dim), + output_lwe_dimension: LweDimension(internal_dim), + ks_decomposition_parameter, + }; + + let &(noise_keyswitch, complexity_keyswitch) = memo + .key_switching + .get(&( + glwe_dim, + glwe_poly_size, + internal_dim, + ks_decomposition_parameter.log2_base, + ks_decomposition_parameter.level, + )) + .unwrap(); + let complexity_all_ks = precision as f64 * complexity_keyswitch; + if noise_private_packing_ks + + noise_modulus_switching + + noise_keyswitch + > variance_max + || (precision - 1) as f64 * complexity_pbs + + complexity_ppks + + precision as f64 * complexity_keyswitch + > best_complexity + { + continue; + } + + // new pbs key for the bit extract pbs, shared + let bit_extract_decomposition_parameter = + br_decomposition_parameter; + + let &(_bit_extract_base_noise, complexity_bit_extract_pbs) = memo + .pbs + .get(&( + glwe_dim, + glwe_poly_size, + internal_dim, + bit_extract_decomposition_parameter.log2_base, + bit_extract_decomposition_parameter.level, + )) + .unwrap(); + + // noise_multisum = dot + let current_maximal_noise = noise_multisum + * (1 << (2 * (precision - 1))) as f64 + + noise_keyswitch + + noise_modulus_switching; + + let complexity_all_pbs = + (precision * circuit_pbs_decomposition_parameter.level) as f64 + * complexity_pbs + + (precision - 1) as f64 * complexity_bit_extract_pbs; + + let complexity_bias = + (complexity_all_ppks + complexity_all_pbs + complexity_all_ks) + * n_inputs as f64; + + let complexity_slope = complexity_cmux_tree + complexity_g_br; + + let current_complexity = complexity_slope + * (1 << n_functions_log) as f64 + + complexity_bias; + + if current_complexity < best_complexity + && current_maximal_noise < variance_max + { + best_complexity = current_complexity; + state.best_solution = Some(Solution { + input_lwe_dimension: pbs_parameters + .output_glwe_params + .glwe_dimension + * pbs_parameters.output_glwe_params.polynomial_size(), + internal_ks_output_lwe_dimension: keyswitch_parameter + .output_lwe_dimension + .0, + ks_decomposition_level_count: keyswitch_parameter + .ks_decomposition_parameter + .level, + ks_decomposition_base_log: keyswitch_parameter + .ks_decomposition_parameter + .log2_base, + glwe_polynomial_size: pbs_parameters + .output_glwe_params + .polynomial_size(), + glwe_dimension: pbs_parameters + .output_glwe_params + .glwe_dimension, + br_decomposition_level_count: pbs_parameters + .br_decomposition_parameter + .level, + br_decomposition_base_log: pbs_parameters + .br_decomposition_parameter + .log2_base, + noise_max: current_maximal_noise, + complexity: current_complexity, + p_error: find_p_error( + kappa, + variance_max, + current_maximal_noise, + ), // consts.maximum_acceptable_error_probability, + cb_decomposition_level_count: Some( + circuit_pbs_decomposition_parameter.level, + ), + cb_decomposition_base_log: Some( + circuit_pbs_decomposition_parameter.log2_base, + ), + }); + } else if current_complexity > best_complexity { + // next level is more costly + break; + } + } + } + } + } + } + } + } + + state +} + +#[allow(clippy::too_many_lines)] +pub fn optimize_one( + _sum_size: u64, + precision: u64, + security_level: u64, + noise_factor: f64, + maximum_acceptable_error_probability: f64, + glwe_log_polynomial_sizes: &[u64], + glwe_dimensions: &[u64], + internal_lwe_dimensions: &[u64], + memo_opt: &mut Option, +) -> atomic_pattern::OptimizationState { + // Basic heuristic to split in several word + let no_sol = atomic_pattern::OptimizationState { + best_solution: None, + count_domain: 0, + }; + #[allow(clippy::match_same_arms)] + let (nb_words, max_word_precision) = match precision { + 1 => (1, 1), + 2 => (1, 2), + 3 => (2, 2), + 4 => (2, 3), + 5 => (2, 3), + 6 => (3, 3), + 7 => (3, 3), + 8 => (3, 3), + 9 => (3, 4), + 10 => (3, 4), + 11 => (3, 4), + 12 => (4, 4), + 13 => (4, 4), + 14 => (4, 4), + 15 => (4, 4), + 16 => (4, 5), + _ => return no_sol, + }; + let log_norm = noise_factor.log2(); + let n_functions_log = 0; + let memo = memo_opt.get_or_insert_with(|| { + tabulate_circuit_bootstrap::( + security_level, + maximum_acceptable_error_probability, + glwe_log_polynomial_sizes, + glwe_dimensions, + internal_lwe_dimensions, + ) + }); + let result = optimise_one_with_memo::( + max_word_precision, + log_norm, + security_level, + maximum_acceptable_error_probability, + glwe_log_polynomial_sizes, + glwe_dimensions, + internal_lwe_dimensions, + n_functions_log, + memo, + nb_words, // Tau + ); + let best_solution = result.best_solution.map(|sol| atomic_pattern::Solution { + input_lwe_dimension: sol.input_lwe_dimension, + internal_ks_output_lwe_dimension: sol.internal_ks_output_lwe_dimension, + ks_decomposition_level_count: sol.ks_decomposition_level_count, + ks_decomposition_base_log: sol.ks_decomposition_base_log, + glwe_polynomial_size: sol.glwe_polynomial_size, + glwe_dimension: sol.glwe_dimension, + br_decomposition_level_count: sol.br_decomposition_level_count, + br_decomposition_base_log: sol.br_decomposition_base_log, + complexity: sol.complexity, + lut_complexity: sol.complexity, + noise_max: sol.noise_max, + p_error: sol.p_error, + }); + atomic_pattern::OptimizationState { + best_solution, + count_domain: result.count_domain, + } +} diff --git a/concrete-optimizer/src/optimization/wop_atomic_pattern/pareto.rs b/concrete-optimizer/src/optimization/wop_atomic_pattern/pareto.rs new file mode 100644 index 000000000..05ee903e4 --- /dev/null +++ b/concrete-optimizer/src/optimization/wop_atomic_pattern/pareto.rs @@ -0,0 +1,408 @@ +use crate::parameters::{BrDecompositionParameters, KsDecompositionParameters}; + +#[rustfmt::skip] +pub const BR_BL: &[BrDecompositionParameters; 71] = &[BrDecompositionParameters { level: 1, log2_base: 2 }, BrDecompositionParameters { level: 1, log2_base: 5 }, BrDecompositionParameters { level: 1, log2_base: 9 }, BrDecompositionParameters { level: 1, log2_base: 12 }, BrDecompositionParameters { level: 1, log2_base: 19 }, BrDecompositionParameters { level: 1, log2_base: 22 }, BrDecompositionParameters { level: 1, log2_base: 23 }, BrDecompositionParameters { level: 1, log2_base: 24 }, BrDecompositionParameters { level: 2, log2_base: 1 }, BrDecompositionParameters { level: 2, log2_base: 3 }, BrDecompositionParameters { level: 2, log2_base: 6 }, BrDecompositionParameters { level: 2, log2_base: 8 }, BrDecompositionParameters { level: 2, log2_base: 12 }, BrDecompositionParameters { level: 2, log2_base: 15 }, BrDecompositionParameters { level: 2, log2_base: 16 }, BrDecompositionParameters { level: 3, log2_base: 3 }, BrDecompositionParameters { level: 3, log2_base: 4 }, BrDecompositionParameters { level: 3, log2_base: 6 }, BrDecompositionParameters { level: 3, log2_base: 9 }, BrDecompositionParameters { level: 3, log2_base: 11 }, BrDecompositionParameters { level: 3, log2_base: 12 }, BrDecompositionParameters { level: 4, log2_base: 2 }, BrDecompositionParameters { level: 4, log2_base: 4 }, BrDecompositionParameters { level: 4, log2_base: 5 }, BrDecompositionParameters { level: 4, log2_base: 8 }, BrDecompositionParameters { level: 4, log2_base: 9 }, BrDecompositionParameters { level: 4, log2_base: 10 }, BrDecompositionParameters { level: 5, log2_base: 2 }, BrDecompositionParameters { level: 5, log2_base: 3 }, BrDecompositionParameters { level: 5, log2_base: 4 }, BrDecompositionParameters { level: 5, log2_base: 6 }, BrDecompositionParameters { level: 5, log2_base: 8 }, BrDecompositionParameters { level: 6, log2_base: 6 }, BrDecompositionParameters { level: 6, log2_base: 7 }, BrDecompositionParameters { level: 7, log2_base: 2 }, BrDecompositionParameters { level: 7, log2_base: 3 }, BrDecompositionParameters { level: 7, log2_base: 5 }, BrDecompositionParameters { level: 7, log2_base: 6 }, BrDecompositionParameters { level: 8, log2_base: 1 }, BrDecompositionParameters { level: 8, log2_base: 2 }, BrDecompositionParameters { level: 8, log2_base: 4 }, BrDecompositionParameters { level: 8, log2_base: 5 }, BrDecompositionParameters { level: 9, log2_base: 1 }, BrDecompositionParameters { level: 9, log2_base: 4 }, BrDecompositionParameters { level: 9, log2_base: 5 }, BrDecompositionParameters { level: 10, log2_base: 2 }, BrDecompositionParameters { level: 10, log2_base: 4 }, BrDecompositionParameters { level: 11, log2_base: 2 }, BrDecompositionParameters { level: 11, log2_base: 3 }, BrDecompositionParameters { level: 11, log2_base: 4 }, BrDecompositionParameters { level: 12, log2_base: 3 }, BrDecompositionParameters { level: 14, log2_base: 3 }, BrDecompositionParameters { level: 15, log2_base: 1 }, BrDecompositionParameters { level: 15, log2_base: 3 }, BrDecompositionParameters { level: 16, log2_base: 1 }, BrDecompositionParameters { level: 17, log2_base: 2 }, BrDecompositionParameters { level: 18, log2_base: 2 }, BrDecompositionParameters { level: 21, log2_base: 1 }, BrDecompositionParameters { level: 21, log2_base: 2 }, BrDecompositionParameters { level: 22, log2_base: 1 }, BrDecompositionParameters { level: 22, log2_base: 2 }, BrDecompositionParameters { level: 23, log2_base: 1 }, BrDecompositionParameters { level: 23, log2_base: 2 }, BrDecompositionParameters { level: 34, log2_base: 1 }, BrDecompositionParameters { level: 35, log2_base: 1 }, BrDecompositionParameters { level: 36, log2_base: 1 }, BrDecompositionParameters { level: 42, log2_base: 1 }, BrDecompositionParameters { level: 43, log2_base: 1 }, BrDecompositionParameters { level: 44, log2_base: 1 }, BrDecompositionParameters { level: 45, log2_base: 1 }, BrDecompositionParameters { level: 46, log2_base: 1 }]; +#[rustfmt::skip] +pub const BR_BL_FOR_CB: &[BrDecompositionParameters; 71] = &[ + BrDecompositionParameters { + level: 1, + log2_base: 2, + }, + BrDecompositionParameters { + level: 1, + log2_base: 5, + }, + BrDecompositionParameters { + level: 1, + log2_base: 9, + }, + BrDecompositionParameters { + level: 1, + log2_base: 12, + }, + BrDecompositionParameters { + level: 1, + log2_base: 19, + }, + BrDecompositionParameters { + level: 1, + log2_base: 22, + }, + BrDecompositionParameters { + level: 1, + log2_base: 23, + }, + BrDecompositionParameters { + level: 1, + log2_base: 24, + }, + BrDecompositionParameters { + level: 2, + log2_base: 1, + }, + BrDecompositionParameters { + level: 2, + log2_base: 3, + }, + BrDecompositionParameters { + level: 2, + log2_base: 6, + }, + BrDecompositionParameters { + level: 2, + log2_base: 8, + }, + BrDecompositionParameters { + level: 2, + log2_base: 12, + }, + BrDecompositionParameters { + level: 2, + log2_base: 15, + }, + BrDecompositionParameters { + level: 2, + log2_base: 16, + }, + BrDecompositionParameters { + level: 3, + log2_base: 3, + }, + BrDecompositionParameters { + level: 3, + log2_base: 4, + }, + BrDecompositionParameters { + level: 3, + log2_base: 6, + }, + BrDecompositionParameters { + level: 3, + log2_base: 9, + }, + BrDecompositionParameters { + level: 3, + log2_base: 11, + }, + BrDecompositionParameters { + level: 3, + log2_base: 12, + }, + BrDecompositionParameters { + level: 4, + log2_base: 2, + }, + BrDecompositionParameters { + level: 4, + log2_base: 4, + }, + BrDecompositionParameters { + level: 4, + log2_base: 5, + }, + BrDecompositionParameters { + level: 4, + log2_base: 8, + }, + BrDecompositionParameters { + level: 4, + log2_base: 9, + }, + BrDecompositionParameters { + level: 4, + log2_base: 10, + }, + BrDecompositionParameters { + level: 5, + log2_base: 2, + }, + BrDecompositionParameters { + level: 5, + log2_base: 3, + }, + BrDecompositionParameters { + level: 5, + log2_base: 4, + }, + BrDecompositionParameters { + level: 5, + log2_base: 6, + }, + BrDecompositionParameters { + level: 5, + log2_base: 8, + }, + BrDecompositionParameters { + level: 6, + log2_base: 6, + }, + BrDecompositionParameters { + level: 6, + log2_base: 7, + }, + BrDecompositionParameters { + level: 7, + log2_base: 2, + }, + BrDecompositionParameters { + level: 7, + log2_base: 3, + }, + BrDecompositionParameters { + level: 7, + log2_base: 5, + }, + BrDecompositionParameters { + level: 7, + log2_base: 6, + }, + BrDecompositionParameters { + level: 8, + log2_base: 1, + }, + BrDecompositionParameters { + level: 8, + log2_base: 2, + }, + BrDecompositionParameters { + level: 8, + log2_base: 4, + }, + BrDecompositionParameters { + level: 8, + log2_base: 5, + }, + BrDecompositionParameters { + level: 9, + log2_base: 1, + }, + BrDecompositionParameters { + level: 9, + log2_base: 4, + }, + BrDecompositionParameters { + level: 9, + log2_base: 5, + }, + BrDecompositionParameters { + level: 10, + log2_base: 2, + }, + BrDecompositionParameters { + level: 10, + log2_base: 4, + }, + BrDecompositionParameters { + level: 11, + log2_base: 2, + }, + BrDecompositionParameters { + level: 11, + log2_base: 3, + }, + BrDecompositionParameters { + level: 11, + log2_base: 4, + }, + BrDecompositionParameters { + level: 12, + log2_base: 3, + }, + BrDecompositionParameters { + level: 14, + log2_base: 3, + }, + BrDecompositionParameters { + level: 15, + log2_base: 1, + }, + BrDecompositionParameters { + level: 15, + log2_base: 3, + }, + BrDecompositionParameters { + level: 16, + log2_base: 1, + }, + BrDecompositionParameters { + level: 17, + log2_base: 2, + }, + BrDecompositionParameters { + level: 18, + log2_base: 2, + }, + BrDecompositionParameters { + level: 21, + log2_base: 1, + }, + BrDecompositionParameters { + level: 21, + log2_base: 2, + }, + BrDecompositionParameters { + level: 22, + log2_base: 1, + }, + BrDecompositionParameters { + level: 22, + log2_base: 2, + }, + BrDecompositionParameters { + level: 23, + log2_base: 1, + }, + BrDecompositionParameters { + level: 23, + log2_base: 2, + }, + BrDecompositionParameters { + level: 34, + log2_base: 1, + }, + BrDecompositionParameters { + level: 35, + log2_base: 1, + }, + BrDecompositionParameters { + level: 36, + log2_base: 1, + }, + BrDecompositionParameters { + level: 42, + log2_base: 1, + }, + BrDecompositionParameters { + level: 43, + log2_base: 1, + }, + BrDecompositionParameters { + level: 44, + log2_base: 1, + }, + BrDecompositionParameters { + level: 45, + log2_base: 1, + }, + BrDecompositionParameters { + level: 46, + log2_base: 1, + }, +]; + +#[rustfmt::skip] +pub const KS_BL: &[KsDecompositionParameters; 50] = &[KsDecompositionParameters { level: 1, log2_base: 5 }, KsDecompositionParameters { level: 1, log2_base: 6 }, KsDecompositionParameters { level: 1, log2_base: 7 }, KsDecompositionParameters { level: 1, log2_base: 8 }, KsDecompositionParameters { level: 1, log2_base: 9 }, KsDecompositionParameters { level: 1, log2_base: 10 }, KsDecompositionParameters { level: 1, log2_base: 11 }, KsDecompositionParameters { level: 1, log2_base: 12 }, KsDecompositionParameters { level: 2, log2_base: 4 }, KsDecompositionParameters { level: 2, log2_base: 5 }, KsDecompositionParameters { level: 2, log2_base: 6 }, KsDecompositionParameters { level: 2, log2_base: 7 }, KsDecompositionParameters { level: 2, log2_base: 8 }, KsDecompositionParameters { level: 3, log2_base: 3 }, KsDecompositionParameters { level: 3, log2_base: 4 }, KsDecompositionParameters { level: 3, log2_base: 5 }, KsDecompositionParameters { level: 3, log2_base: 6 }, KsDecompositionParameters { level: 4, log2_base: 2 }, KsDecompositionParameters { level: 4, log2_base: 3 }, KsDecompositionParameters { level: 4, log2_base: 4 }, KsDecompositionParameters { level: 4, log2_base: 5 }, KsDecompositionParameters { level: 5, log2_base: 2 }, KsDecompositionParameters { level: 5, log2_base: 3 }, KsDecompositionParameters { level: 5, log2_base: 4 }, KsDecompositionParameters { level: 6, log2_base: 2 }, KsDecompositionParameters { level: 6, log2_base: 3 }, KsDecompositionParameters { level: 6, log2_base: 4 }, KsDecompositionParameters { level: 7, log2_base: 2 }, KsDecompositionParameters { level: 7, log2_base: 3 }, KsDecompositionParameters { level: 8, log2_base: 2 }, KsDecompositionParameters { level: 8, log2_base: 3 }, KsDecompositionParameters { level: 9, log2_base: 1 }, KsDecompositionParameters { level: 9, log2_base: 2 }, KsDecompositionParameters { level: 10, log2_base: 1 }, KsDecompositionParameters { level: 10, log2_base: 2 }, KsDecompositionParameters { level: 11, log2_base: 1 }, KsDecompositionParameters { level: 11, log2_base: 2 }, KsDecompositionParameters { level: 12, log2_base: 1 }, KsDecompositionParameters { level: 12, log2_base: 2 }, KsDecompositionParameters { level: 13, log2_base: 1 }, KsDecompositionParameters { level: 14, log2_base: 1 }, KsDecompositionParameters { level: 15, log2_base: 1 }, KsDecompositionParameters { level: 16, log2_base: 1 }, KsDecompositionParameters { level: 17, log2_base: 1 }, KsDecompositionParameters { level: 18, log2_base: 1 }, KsDecompositionParameters { level: 19, log2_base: 1 }, KsDecompositionParameters { level: 20, log2_base: 1 }, KsDecompositionParameters { level: 21, log2_base: 1 }, KsDecompositionParameters { level: 22, log2_base: 1 }, KsDecompositionParameters { level: 23, log2_base: 1 }]; +#[rustfmt::skip] +pub const KS_BL_FOR_CB: &[KsDecompositionParameters; 27] = &[ + KsDecompositionParameters { + level: 1, + log2_base: 4, + }, + KsDecompositionParameters { + level: 1, + log2_base: 5, + }, + KsDecompositionParameters { + level: 1, + log2_base: 6, + }, + KsDecompositionParameters { + level: 1, + log2_base: 7, + }, + KsDecompositionParameters { + level: 1, + log2_base: 8, + }, + KsDecompositionParameters { + level: 2, + log2_base: 3, + }, + KsDecompositionParameters { + level: 2, + log2_base: 4, + }, + KsDecompositionParameters { + level: 2, + log2_base: 5, + }, + KsDecompositionParameters { + level: 3, + log2_base: 2, + }, + KsDecompositionParameters { + level: 3, + log2_base: 3, + }, + KsDecompositionParameters { + level: 3, + log2_base: 4, + }, + KsDecompositionParameters { + level: 4, + log2_base: 2, + }, + KsDecompositionParameters { + level: 4, + log2_base: 3, + }, + KsDecompositionParameters { + level: 5, + log2_base: 2, + }, + KsDecompositionParameters { + level: 5, + log2_base: 3, + }, + KsDecompositionParameters { + level: 6, + log2_base: 1, + }, + KsDecompositionParameters { + level: 6, + log2_base: 2, + }, + KsDecompositionParameters { + level: 7, + log2_base: 1, + }, + KsDecompositionParameters { + level: 7, + log2_base: 2, + }, + KsDecompositionParameters { + level: 8, + log2_base: 1, + }, + KsDecompositionParameters { + level: 9, + log2_base: 1, + }, + KsDecompositionParameters { + level: 10, + log2_base: 1, + }, + KsDecompositionParameters { + level: 11, + log2_base: 1, + }, + KsDecompositionParameters { + level: 12, + log2_base: 1, + }, + KsDecompositionParameters { + level: 13, + log2_base: 1, + }, + KsDecompositionParameters { + level: 14, + log2_base: 1, + }, + KsDecompositionParameters { + level: 15, + log2_base: 1, + }, +]; + +#[rustfmt::skip] +pub const CB_V1_BL: &[BrDecompositionParameters; 75] = &[BrDecompositionParameters { level: 1, log2_base: 1 }, BrDecompositionParameters { level: 1, log2_base: 2 }, BrDecompositionParameters { level: 1, log2_base: 3 }, BrDecompositionParameters { level: 1, log2_base: 4 }, BrDecompositionParameters { level: 1, log2_base: 5 }, BrDecompositionParameters { level: 1, log2_base: 6 }, BrDecompositionParameters { level: 2, log2_base: 1 }, BrDecompositionParameters { level: 2, log2_base: 2 }, BrDecompositionParameters { level: 2, log2_base: 3 }, BrDecompositionParameters { level: 2, log2_base: 4 }, BrDecompositionParameters { level: 2, log2_base: 5 }, BrDecompositionParameters { level: 3, log2_base: 1 }, BrDecompositionParameters { level: 3, log2_base: 2 }, BrDecompositionParameters { level: 3, log2_base: 3 }, BrDecompositionParameters { level: 3, log2_base: 4 }, BrDecompositionParameters { level: 3, log2_base: 5 }, BrDecompositionParameters { level: 3, log2_base: 6 }, BrDecompositionParameters { level: 4, log2_base: 1 }, BrDecompositionParameters { level: 4, log2_base: 2 }, BrDecompositionParameters { level: 4, log2_base: 3 }, BrDecompositionParameters { level: 4, log2_base: 4 }, BrDecompositionParameters { level: 4, log2_base: 5 }, BrDecompositionParameters { level: 5, log2_base: 1 }, BrDecompositionParameters { level: 5, log2_base: 2 }, BrDecompositionParameters { level: 5, log2_base: 3 }, BrDecompositionParameters { level: 5, log2_base: 4 }, BrDecompositionParameters { level: 6, log2_base: 1 }, BrDecompositionParameters { level: 6, log2_base: 2 }, BrDecompositionParameters { level: 6, log2_base: 3 }, BrDecompositionParameters { level: 6, log2_base: 4 }, BrDecompositionParameters { level: 7, log2_base: 1 }, BrDecompositionParameters { level: 7, log2_base: 2 }, BrDecompositionParameters { level: 7, log2_base: 3 }, BrDecompositionParameters { level: 7, log2_base: 4 }, BrDecompositionParameters { level: 8, log2_base: 1 }, BrDecompositionParameters { level: 8, log2_base: 2 }, BrDecompositionParameters { level: 8, log2_base: 3 }, BrDecompositionParameters { level: 9, log2_base: 1 }, BrDecompositionParameters { level: 9, log2_base: 2 }, BrDecompositionParameters { level: 9, log2_base: 3 }, BrDecompositionParameters { level: 10, log2_base: 1 }, BrDecompositionParameters { level: 10, log2_base: 2 }, BrDecompositionParameters { level: 10, log2_base: 3 }, BrDecompositionParameters { level: 11, log2_base: 1 }, BrDecompositionParameters { level: 11, log2_base: 2 }, BrDecompositionParameters { level: 12, log2_base: 1 }, BrDecompositionParameters { level: 12, log2_base: 2 }, BrDecompositionParameters { level: 13, log2_base: 1 }, BrDecompositionParameters { level: 13, log2_base: 2 }, BrDecompositionParameters { level: 14, log2_base: 1 }, BrDecompositionParameters { level: 14, log2_base: 2 }, BrDecompositionParameters { level: 15, log2_base: 1 }, BrDecompositionParameters { level: 15, log2_base: 2 }, BrDecompositionParameters { level: 16, log2_base: 1 }, BrDecompositionParameters { level: 16, log2_base: 2 }, BrDecompositionParameters { level: 17, log2_base: 1 }, BrDecompositionParameters { level: 17, log2_base: 2 }, BrDecompositionParameters { level: 18, log2_base: 1 }, BrDecompositionParameters { level: 19, log2_base: 1 }, BrDecompositionParameters { level: 20, log2_base: 1 }, BrDecompositionParameters { level: 21, log2_base: 1 }, BrDecompositionParameters { level: 22, log2_base: 1 }, BrDecompositionParameters { level: 23, log2_base: 1 }, BrDecompositionParameters { level: 24, log2_base: 1 }, BrDecompositionParameters { level: 25, log2_base: 1 }, BrDecompositionParameters { level: 26, log2_base: 1 }, BrDecompositionParameters { level: 27, log2_base: 1 }, BrDecompositionParameters { level: 28, log2_base: 1 }, BrDecompositionParameters { level: 29, log2_base: 1 }, BrDecompositionParameters { level: 30, log2_base: 1 }, BrDecompositionParameters { level: 31, log2_base: 1 }, BrDecompositionParameters { level: 32, log2_base: 1 }, BrDecompositionParameters { level: 33, log2_base: 1 }, BrDecompositionParameters { level: 34, log2_base: 1 }, BrDecompositionParameters { level: 35, log2_base: 1 }]; diff --git a/v0-parameters/src/main.rs b/v0-parameters/src/main.rs index cbdfd64cf..d58a22253 100644 --- a/v0-parameters/src/main.rs +++ b/v0-parameters/src/main.rs @@ -8,6 +8,7 @@ use clap::Parser; use concrete_optimizer::global_parameters::DEFAUT_DOMAINS; use concrete_optimizer::optimization::atomic_pattern as optimize_atomic_pattern; +use concrete_optimizer::optimization::wop_atomic_pattern::optimize as optimize_wop_atomic_pattern; use rayon_cond::CondIterator; const _4_SIGMA: f64 = 1.0 - 0.999_936_657_516; @@ -60,6 +61,9 @@ struct Args { #[clap(long)] no_parallelize: bool, + + #[clap(long)] + wop_pbs: bool, } fn main() { @@ -79,7 +83,11 @@ fn main() { (args.min_intern_lwe_dim..=args.max_intern_lwe_dim).collect(); let precisions = args.min_precision..=args.max_precision; - let manps = 0..=31; + let manps = if args.wop_pbs { + vec![0, 2, 4, 6, 8, 10, 12] + } else { + (0..=31).collect() + }; // let guard = pprof::ProfilerGuard::new(100).unwrap(); @@ -88,19 +96,34 @@ fn main() { #[rustfmt::skip] let all_results = precisions_iter.map(|precision| { let mut last_solution = None; - manps.clone().map(|manp| { + let mut memo = None; + manps.iter().map(|&manp| { let noise_scale = 2_f64.powi(manp); - let result = optimize_atomic_pattern::optimize_one::( - sum_size, - precision, - security_level, - noise_scale, - p_error, - &glwe_log_polynomial_sizes, - &glwe_dimensions, - &internal_lwe_dimensions, - last_solution, // 33% gains - ); + let result = if args.wop_pbs { + optimize_wop_atomic_pattern::optimize_one::( + sum_size, + precision, + security_level, + noise_scale, + p_error, + &glwe_log_polynomial_sizes, + &glwe_dimensions, + &internal_lwe_dimensions, + &mut memo, + ) + } else { + optimize_atomic_pattern::optimize_one::( + sum_size, + precision, + security_level, + noise_scale, + p_error, + &glwe_log_polynomial_sizes, + &glwe_dimensions, + &internal_lwe_dimensions, + last_solution, // 33% gains + ) + }; last_solution = result.best_solution; result }) @@ -120,7 +143,7 @@ fn main() { println!("{{ /* {:1.1e} errors */", p_error); for (precision_i, precision) in precisions.enumerate() { println!("{{ /* precision {:2} */", precision); - for (manp_i, manp) in manps.clone().enumerate() { + for (manp_i, manp) in manps.clone().iter().enumerate() { let solution = all_results[precision_i][manp_i].best_solution; match solution { Some(solution) => { @@ -170,4 +193,36 @@ mod tests { text_diff::assert_diff(&expected_output, actual_output, CMP_LINES, EXACT_EQUALITY); } + + #[test] + fn test_reference_wop_output() { + const REF_FILE: &str = "src/wop_parameters.ref-15-06-2022"; + const V0_PARAMETERS_EXE: &str = "../target/release/v0-parameters"; + const CMP_LINES: &str = "\n"; + const EXACT_EQUALITY: i32 = 0; + let _ = std::process::Command::new("cargo") + .args(["build", "--release", "-q"]) + .status() + .expect("Can't build"); + assert!(std::path::Path::new(V0_PARAMETERS_EXE).exists()); + + #[rustfmt::skip] + let actual_output = std::process::Command::new(V0_PARAMETERS_EXE) + .args([ + "--wop-pbs", + "--min-intern-lwe-dim", "257", + "--min-precision", "16", + "--max-precision", "16", + "--min-log-poly-size", "10", + "--max-log-poly-size", "12", + "--" + ]) + .output() + .expect("failed to execute process"); + let actual_output = std::str::from_utf8(&actual_output.stdout).expect("Bad content"); + + let expected_output = std::fs::read_to_string(REF_FILE).expect("Can't read reference file"); + + text_diff::assert_diff(&expected_output, actual_output, CMP_LINES, EXACT_EQUALITY); + } } diff --git a/v0-parameters/src/wop_parameters.ref-15-06-2022 b/v0-parameters/src/wop_parameters.ref-15-06-2022 new file mode 100644 index 000000000..279f20b00 --- /dev/null +++ b/v0-parameters/src/wop_parameters.ref-15-06-2022 @@ -0,0 +1,11 @@ +{ /* 6.3e-5 errors */ +{ /* precision 16 */ + /* 0 */ V0Parameter( 1, 11, 482, 2, 16, 9, 1), // 8041 mops, 6.3e-5 errors + /* 2 */ V0Parameter( 1, 11, 491, 2, 15, 9, 1), // 10343 mops, 6.0e-5 errors + /* 4 */ V0Parameter( 1, 11, 491, 3, 12, 9, 1), // 11155 mops, 6.3e-5 errors + /* 6 */ V0Parameter( 1, 11, 520, 3, 12, 10, 1), // 14850 mops, 6.0e-5 errors + /* 8 */ V0Parameter( 1, 11, 486, 4, 9, 9, 1), // 25684 mops, 6.0e-5 errors + /* 10 */ V0Parameter( 1, 11, 503, 5, 8, 10, 1), // 32012 mops, 5.6e-5 errors + /* 12 */ V0Parameter( 1, 11, 503, 7, 6, 10, 1), // 49916 mops, 5.7e-5 errors + }, +}