diff --git a/src/circuit/ops/layouts.rs b/src/circuit/ops/layouts.rs index c9d9c8e94..20524d9eb 100644 --- a/src/circuit/ops/layouts.rs +++ b/src/circuit/ops/layouts.rs @@ -71,31 +71,29 @@ fn optimum_convex_function, region: &mut RegionCtx, x: &ValTensor, - ignore_mask: &Option>, f: impl Fn(&BaseConfig, &mut RegionCtx, &ValTensor) -> Result, CircuitError>, ) -> Result<(), CircuitError> { - let two = create_constant_tensor(F::from(2), 1); - let two = region.assign(&config.custom_gates.inputs[1], &two)?; - region.increment(two.len()); + let one = create_constant_tensor(F::from(1), 1); + let one = region.assign(&config.custom_gates.inputs[1], &one)?; + region.increment(one.len()); let f_x = f(config, region, x)?; - let x_plus_2 = pairwise(config, region, &[x.clone(), two.clone()], BaseOp::Add)?; - let f_x_plus_2 = f(config, region, &x_plus_2)?; + let x_plus_1 = pairwise(config, region, &[x.clone(), one.clone()], BaseOp::Add)?; + let f_x_plus_1 = f(config, region, &x_plus_1)?; - let x_minus_2 = pairwise(config, region, &[x.clone(), two.clone()], BaseOp::Sub)?; - let f_x_minus_2 = f(config, region, &x_minus_2)?; + let x_minus_1 = pairwise(config, region, &[x.clone(), one.clone()], BaseOp::Sub)?; + let f_x_minus_1 = f(config, region, &x_minus_1)?; - // because the function is convex, we the result should be the minimum of the three - // not that we offset the x by 2 to get the other two points that due to the convexity of the function and symmetry of convex function, there can be 2 - let f_x_is_opt_rhs = less(config, region, &[f_x.clone(), f_x_plus_2])?; - let f_x_is_opt_lhs = less(config, region, &[f_x.clone(), f_x_minus_2])?; + // because the function is convex, the result should be the minimum of the three + // not that we offset the x by 1 to get the next value + // f(x) <= f(x+1) and f(x) <= f(x-1) + // the result is 1 if the function is optimal solely because of the convexity of the function + // the distances can be equal but this is only possible if f(x) and f(x+1) are both optimal (or f(x) and f(x-1)). + let f_x_is_opt_rhs = less_equal(config, region, &[f_x.clone(), f_x_plus_1])?; + let f_x_is_opt_lhs = less_equal(config, region, &[f_x.clone(), f_x_minus_1])?; - let mut is_opt = and(config, region, &[f_x_is_opt_lhs, f_x_is_opt_rhs])?; - - if let Some(ignore_mask) = ignore_mask { - is_opt = or(config, region, &[is_opt.clone(), ignore_mask.clone()])?; - } + let is_opt = and(config, region, &[f_x_is_opt_lhs, f_x_is_opt_rhs])?; let mut comparison_unit = create_constant_tensor(integer_rep_to_felt(1), is_opt.len()); comparison_unit.reshape(is_opt.dims())?; @@ -160,7 +158,7 @@ pub(crate) fn div( Ok(distance) }; - optimum_convex_function(config, region, &claimed_output, &None, err_func)?; + optimum_convex_function(config, region, &claimed_output, err_func)?; Ok(claimed_output) } @@ -241,13 +239,7 @@ pub(crate) fn recip( Ok(distance) }; - optimum_convex_function( - config, - region, - &claimed_output, - &Some(equal_zero_mask), - err_func, - )?; + optimum_convex_function(config, region, &claimed_output, err_func)?; Ok(claimed_output) } @@ -329,7 +321,7 @@ pub fn sqrt( Ok(distance) }; - optimum_convex_function(config, region, &claimed_output, &None, err_func)?; + optimum_convex_function(config, region, &claimed_output, err_func)?; Ok(claimed_output) } @@ -4798,18 +4790,29 @@ pub fn ln( l1_distance(config, region, &[input.clone(), prior_pow2.clone()])?; // because we round up this can be equal - let is_closest_to_0: ValTensor = less_equal( + let is_closest_to_0: ValTensor = less( config, region, - &[abs_distance_to_claimed.clone(), abs_distance_to_next_pow2], + &[ + abs_distance_to_claimed.clone(), + abs_distance_to_next_pow2.clone(), + ], )?; + let is_closest_to_1 = less( config, region, - &[abs_distance_to_claimed.clone(), abs_distance_to_prior_pow2], + &[ + abs_distance_to_claimed.clone(), + abs_distance_to_prior_pow2.clone(), + ], )?; - let is_closest = and(config, region, &[is_closest_to_0, is_closest_to_1])?; + let is_closest = and( + config, + region, + &[is_closest_to_0.clone(), is_closest_to_1.clone()], + )?; let mut comparison_unit = create_constant_tensor(integer_rep_to_felt(1), is_closest.len()); comparison_unit.reshape(is_closest.dims())?; diff --git a/src/tensor/ops.rs b/src/tensor/ops.rs index 79f8eb8a7..7ac05cf9a 100644 --- a/src/tensor/ops.rs +++ b/src/tensor/ops.rs @@ -1546,9 +1546,17 @@ pub mod nonlinearities { pub fn ilog2(a: &Tensor, scale_input: f64) -> Tensor { a.par_enum_map(|_, a_i| { let kix = (a_i as f64) / scale_input; - let kix = (kix).log2(); - let rounded = kix.round(); - Ok::<_, TensorError>(rounded as IntegerRep) + let log = (kix).log2(); + let floor = log.floor(); + let ceil = log.ceil(); + let floor_dist = ((2.0_f64).powf(floor) - kix).abs(); + let ceil_dist = (kix - (2.0_f64).powf(ceil)).abs(); + + if floor_dist < ceil_dist { + Ok::<_, TensorError>(floor as IntegerRep) + } else { + Ok::<_, TensorError>(ceil as IntegerRep) + } }) .unwrap() } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index d1a9ac8c8..2f6363e4d 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -539,7 +539,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "fixed", "public", 1, "accuracy", None, 0.0); + mock(path, test.to_string(), "public", "fixed", "public", 1, "accuracy", None, 0.0, false); test_dir.close().unwrap(); } }); @@ -604,7 +604,17 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "private", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "private", "public", 1, "resources", None, 0.0, false); + test_dir.close().unwrap(); + } + + + #(#[test_case(TESTS[N])])* + fn mock_bounded_lookup_log(test: &str) { + crate::native_tests::init_binary(); + let test_dir = TempDir::new(test).unwrap(); + let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); + mock(path, test.to_string(), "private", "private", "public", 1, "resources", None, 0.0, true); test_dir.close().unwrap(); } @@ -615,7 +625,7 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); // gen random number between 0.0 and 1.0 let tolerance = rand::thread_rng().gen_range(0.0..1.0) * 100.0; - mock(path, test.to_string(), "private", "private", "public", 1, "resources", None, tolerance); + mock(path, test.to_string(), "private", "private", "public", 1, "resources", None, tolerance, false); test_dir.close().unwrap(); } @@ -630,7 +640,7 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let large_batch_dir = &format!("large_batches_{}", test); crate::native_tests::mk_data_batches_(path, test, &large_batch_dir, 10); - mock(path, large_batch_dir.to_string(), "private", "private", "public", 10, "resources", None, 0.0); + mock(path, large_batch_dir.to_string(), "private", "private", "public", 10, "resources", None, 0.0, false); test_dir.close().unwrap(); } } @@ -640,7 +650,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "private", "private", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "private", "private", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -649,7 +659,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "hashed", "private", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "hashed", "private", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -658,7 +668,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "fixed", "private", "private", 1, "resources", None, 0.0); + mock(path, test.to_string(), "fixed", "private", "private", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -667,7 +677,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "private", "fixed", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "private", "fixed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -676,7 +686,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "fixed", "private", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "fixed", "private", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -685,7 +695,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "hashed", "private", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "hashed", "private", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -694,7 +704,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "polycommit", "private", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "polycommit", "private", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -704,7 +714,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "hashed", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "hashed", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -714,7 +724,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "polycommit", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "polycommit", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -723,7 +733,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "private", "hashed", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "private", "hashed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -733,7 +743,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "private", "polycommit", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "private", "polycommit", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -742,7 +752,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "fixed", "hashed", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "fixed", "hashed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -752,7 +762,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "public", "polycommit", "hashed", 1, "resources", None, 0.0); + mock(path, test.to_string(), "public", "polycommit", "hashed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -762,7 +772,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "polycommit", "polycommit", "polycommit", 1, "resources", None, 0.0); + mock(path, test.to_string(), "polycommit", "polycommit", "polycommit", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -772,7 +782,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "hashed", "private", "hashed", 1, "resources", None, 0.0); + mock(path, test.to_string(), "hashed", "private", "hashed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -782,7 +792,7 @@ mod native_tests { let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); // needs an extra row for the large model - mock(path, test.to_string(),"hashed", "hashed", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(),"hashed", "hashed", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -792,7 +802,7 @@ mod native_tests { let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); // needs an extra row for the large model - mock(path, test.to_string(),"hashed", "hashed", "hashed", 1, "resources", None, 0.0); + mock(path, test.to_string(),"hashed", "hashed", "hashed", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } @@ -969,7 +979,7 @@ mod native_tests { crate::native_tests::init_binary(); let test_dir = TempDir::new(test).unwrap(); let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); - mock(path, test.to_string(), "private", "fixed", "public", 1, "resources", None, 0.0); + mock(path, test.to_string(), "private", "fixed", "public", 1, "resources", None, 0.0, false); test_dir.close().unwrap(); } }); @@ -1446,6 +1456,7 @@ mod native_tests { cal_target: &str, scales_to_use: Option>, tolerance: f32, + bounded_lookup_log: bool, ) { let mut tolerance = tolerance; gen_circuit_settings_and_witness( @@ -1461,6 +1472,7 @@ mod native_tests { &mut tolerance, Commitments::KZG, 2, + bounded_lookup_log, ); if tolerance > 0.0 { @@ -1601,8 +1613,9 @@ mod native_tests { tolerance: &mut f32, commitment: Commitments, lookup_safety_margin: usize, + bounded_lookup_log: bool, ) { - let args = vec![ + let mut args = vec![ "gen-settings".to_string(), "-M".to_string(), format!("{}/{}/network.onnx", test_dir, example_name), @@ -1619,6 +1632,10 @@ mod native_tests { format!("--commitment={}", commitment), ]; + if bounded_lookup_log { + args.push("--bounded-log-lookup".to_string()); + } + let status = Command::new(format!("{}/release/ezkl", *CARGO_TARGET_DIR)) .args(args) .status() @@ -1731,6 +1748,7 @@ mod native_tests { &mut 0.0, Commitments::KZG, 2, + false, ); println!( @@ -2014,6 +2032,7 @@ mod native_tests { &mut 0.0, commitment, lookup_safety_margin, + false, ); let settings_path = format!("{}/{}/settings.json", test_dir, example_name); @@ -2445,6 +2464,7 @@ mod native_tests { &mut 0.0, Commitments::KZG, 2, + false, ); let model_path = format!("{}/{}/network.compiled", test_dir, example_name);