diff --git a/comptime/Cargo.lock b/comptime/Cargo.lock new file mode 100644 index 0000000..37b24fd --- /dev/null +++ b/comptime/Cargo.lock @@ -0,0 +1,59 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "comptime" +version = "0.1.0" +dependencies = [ + "hex", + "lazy_static", + "num-bigint", + "num-traits", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/comptime/Cargo.toml b/comptime/Cargo.toml new file mode 100644 index 0000000..9c3fb04 --- /dev/null +++ b/comptime/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "comptime" +version = "0.1.0" +edition = "2021" + +[dependencies] +hex = "0.4.3" +lazy_static = "1.5.0" +num-bigint = "0.4.6" +num-traits = "0.2.19" diff --git a/comptime/src/lib.rs b/comptime/src/lib.rs new file mode 100644 index 0000000..3f2b208 --- /dev/null +++ b/comptime/src/lib.rs @@ -0,0 +1,661 @@ +use num_bigint::{BigUint, ToBigUint}; +use num_traits::{Num}; +use std::default::Default; +use std::ops::{Add, Mul, Sub}; +use std::str::FromStr; + +pub type FieldElement = BigUint; + +lazy_static::lazy_static! { + static ref FIELD_MODULUS: FieldElement = FieldElement::from_str( + "21888242871839275222246405745257275088696311157297823662689037894645226208583" + ).unwrap(); +} + +pub trait ToU32 { + fn to_u32(&self) -> u32; +} + +// Implement for BigUint +impl ToU32 for BigUint { + fn to_u32(&self) -> u32 { + self.to_u32_digits()[0] + } +} + +#[derive(Debug)] +pub struct SortResult { + pub sorted: Vec, + pub sort_indices: Vec, +} + +#[derive(Debug)] +pub struct SparseArray +where + T: std::fmt::Debug, +{ + keys: Vec, + values: Vec, + maximum: FieldElement, +} + +impl SparseArray +where + T: Default + + Clone + + std::fmt::Debug + + From + + ToU32 + + Add + + Sub + + Mul + + PartialEq + + PartialOrd, +{ + pub fn create(keys: &[FieldElement], values: &[T], size: FieldElement) -> Self { + let n = keys.len(); + println!("Key length: {}", n); + assert_eq!(n, values.len(), "Keys and values must have the same length"); + + let maximum = size.clone() - FieldElement::from(1u32); + + // Create vectors with capacity for n+2 keys and n+3 values + let mut result = SparseArray { + keys: Vec::with_capacity(n + 2), + values: vec![T::default(); n + 3], + maximum: maximum.clone(), + }; + + // Sort the keys + let sorted = sort_advanced(keys); + + // Insert start and endpoints + result.keys.push(FieldElement::from(0u32)); + result.keys.extend(sorted.sorted.iter().cloned()); + result.keys.push(maximum.clone()); + + // Populate values based on the sorted keys + for i in 0..n { + result.values[sorted.sort_indices[i] + 2] = values[i].clone(); + } + + // Handle initial and final values + result.values[0] = T::default(); // default value for non-existent keys + + // Set initial value (value[1] maps to keys[0] which is 0) + let initial_value = if keys[0] == FieldElement::from(0u32) { + values[0].clone() + } else { + T::default() + }; + result.values[1] = initial_value; + + // Set final value (value[n+2] maps to keys[n+1] which is maximum) + let final_value = if keys[n - 1] == maximum { + values[n - 1].clone() + } else { + T::default() + }; + result.values[n + 2] = final_value; + + // Boundary checks + assert!( + &sorted.sorted[0] < &*FIELD_MODULUS, + "Key exceeds field modulus" + ); + assert!(&maximum < &*FIELD_MODULUS, "Maximum exceeds field modulus"); + assert!(&maximum >= &sorted.sorted[n - 1], "Key exceeds maximum"); + + result + } + + pub fn create_packed(table: &[T], max_size: u32) -> Self { + let mut small_keys = Vec::new(); + let mut small_values = Vec::new(); + let mut keys = Vec::new(); + let mut values = Vec::new(); + + // Find max value and collect non-zero entries + let mut max_value = T::default(); + for i in 0..table.len() { + // Convert to u32 for comparison + if &table[i] > &max_value { + max_value = table[i].clone(); + } + + if table[i] != T::from(0) { + keys.push(FieldElement::from(i as u32)); + values.push(table[i].clone()); + + if i < 256 { + small_keys.push(FieldElement::from(i as u32)); + small_values.push(table[i].clone()); + } + } + } + + // Combine values according to the dual encoding scheme + for i in 0..small_keys.len() { + let target_value = small_values[i].clone() * T::from(256); + + // Use the full max_value range exactly like the original + for j in 0..max_value.to_u32() { + let target_key = + FieldElement::from(j) * FieldElement::from(256u32) + small_keys[i].clone(); + let mut found_key = false; + + for k in 0..keys.len() { + if keys[k] == target_key { + values[k] = values[k].clone() + target_value.clone(); + found_key = true; + break; + } + } + + if !found_key { + keys.push(target_key); + values.push(target_value.clone()); + } + } + } + + // Print the number of entries for debugging + let num_entries = keys.len(); + println!("Number of entries: {}", num_entries); + + // Create the SparseArray using the create method + Self::create(&keys, &values, FieldElement::from(max_size)) + } + + pub fn to_noir_string(&self, generic_name: Option<&str>) -> String + where + T: ToString, + { + let keys_str = self + .keys + .iter() + .map(|k| format!("0x{:08x}", k)) + .collect::>() + .join(", "); + + let values_str = self + .values + .iter() + .map(|v| format!("0x{:08x}", v.to_string().parse::().unwrap())) + .collect::>() + .join(", "); + + let generic_name = generic_name.unwrap_or("Field"); + let table_length: usize = self.keys.len() - 2; + + format!( + "SparseArray<{}, {}> = SparseArray {{\n \ + keys: [{}],\n \ + values: [{}],\n \ + maximum: 0x{:08x}\n\ + }};", + table_length, generic_name, keys_str, values_str, self.maximum + ) + } + + pub fn get(&self, index: &FieldElement) -> &T { + // If index is greater than maximum, return default value + if index > &self.maximum { + return &self.values[0]; + } + + let mut left = 0; + let mut right = self.keys.len() - 1; + + while left + 1 < right { + let mid = (left + right) / 2; + if &self.keys[mid] <= index { + left = mid; + } else { + right = mid; + } + } + + // Found the interval [left, right) that contains index + // Check if index exactly matches the left boundary + if &self.keys[left] == index { + &self.values[left + 1] + } else { + // If not an exact match, return default value + &self.values[0] + } + } + + pub fn get_maximum(&self) -> &FieldElement { + &self.maximum + } +} + +fn sort_advanced(input: &[FieldElement]) -> SortResult { + let mut sorted = input.to_vec(); + quicksort(&mut sorted, &|a, b| a < b); + + let sort_indices = get_shuffle_indices(input, &sorted); + + // Verify sorting + for i in 0..(sorted.len() - 1) { + assert!(!(&sorted[i + 1] < &sorted[i]), "Array not properly sorted"); + } + + SortResult { + sorted, + sort_indices, + } +} + +fn get_shuffle_indices(lhs: &[FieldElement], rhs: &[FieldElement]) -> Vec { + let n = lhs.len(); + let mut shuffle_indices = vec![0usize; n]; + let mut shuffle_mask = vec![false; n]; + + for i in 0..n { + let mut found = false; + for j in 0..n { + if !shuffle_mask[j] && !found && lhs[i] == rhs[j] { + found = true; + shuffle_indices[i] = j; + shuffle_mask[j] = true; + } + } + assert!(found, "Arrays do not contain equivalent values"); + } + + shuffle_indices +} + +// Keeping the existing partition and quicksort functions as they already work with slices +fn partition( + arr: &mut [T], + low: usize, + high: usize, + compare: &impl Fn(&T, &T) -> bool, +) -> usize { + let pivot = high; + let mut i = low; + + for j in low..high { + if compare(&arr[j], &arr[pivot]) { + arr.swap(i, j); + i += 1; + } + } + arr.swap(i, pivot); + i +} + +fn quicksort_recursive( + arr: &mut [T], + low: usize, + high: usize, + compare: &impl Fn(&T, &T) -> bool, +) { + if low < high { + let pivot_index = partition(arr, low, high, compare); + if pivot_index > 0 { + quicksort_recursive(arr, low, pivot_index - 1, compare); + } + if pivot_index < high { + quicksort_recursive(arr, pivot_index + 1, high, compare); + } + } +} + +fn quicksort(arr: &mut [T], compare: &impl Fn(&T, &T) -> bool) { + if arr.len() > 1 { + quicksort_recursive(arr, 0, arr.len() - 1, compare); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn field(s: &str) -> FieldElement { + match s.starts_with("0x") { + true => FieldElement::from_str_radix(&s[2..], 16).unwrap(), + false => FieldElement::from_str(s).unwrap(), + } + } + + #[test] + fn test_sparse_lookup() { + let keys = vec![field("1"), field("99"), field("7"), field("5")]; + let values = vec![123i32, 101112, 789, 456]; + let example = SparseArray::create(&keys, &values, field("100")); + + // Test exact matches + assert_eq!(*example.get(&field("1")), 123); + assert_eq!(*example.get(&field("5")), 456); + assert_eq!(*example.get(&field("7")), 789); + assert_eq!(*example.get(&field("99")), 101112); + + // Test values between keys + assert_eq!(*example.get(&field("0")), 0); + assert_eq!(*example.get(&field("2")), 0); + assert_eq!(*example.get(&field("6")), 0); + assert_eq!(*example.get(&field("8")), 0); + assert_eq!(*example.get(&field("98")), 0); + + // Test all values systematically + for i in 0u32..100 { + let i_field = FieldElement::from(i); + if i_field != field("1") + && i_field != field("5") + && i_field != field("7") + && i_field != field("99") + { + assert_eq!(*example.get(&i_field), 0); + } + } + } + + #[test] + fn test_sparse_lookup_boundary_cases() { + // what about when keys[0] = 0 and keys[N-1] = 2^32 - 1? + let keys = vec![ + field("0"), + field("99999"), + field("7"), + field("4294967295"), // 0xffffffff = 2^32 - 1 + ]; + let values = vec![123, 101112, 789, 456]; + let example = SparseArray::create( + &keys, + &values, + field("4294967296"), // 0x100000000 = 2^32 + ); + + assert_eq!(*example.get(&field("0")), 123); + assert_eq!(*example.get(&field("99999")), 101112); + assert_eq!(*example.get(&field("7")), 789); + assert_eq!(*example.get(&field("4294967295")), 456); // 0xffffffff + assert_eq!(*example.get(&field("4294967294")), 0); // 0xfffffffe + } + + #[test] + #[should_panic(expected = "Maximum exceeds field modulus")] + fn test_sparse_lookup_overflow() { + let keys = vec![field("1"), field("5"), field("7"), field("99999")]; + let values = vec![123i32, 456, 789, 101112]; + let _example = SparseArray::create( + &keys, + &values, + FIELD_MODULUS.clone() + FieldElement::from(1u32), + ); + } + + #[test] + #[should_panic(expected = "Maximum exceeds field modulus")] + fn test_sparse_lookup_boundary_case_overflow() { + let keys = vec![ + field("0"), + field("5"), + field("7"), + field("115792089237316195423570985008687907853269984665640564039457584007913129639935"), + ]; + let values = vec![123i32, 456, 789, 101112]; + let _example = SparseArray::create( + &keys, + &values, + FIELD_MODULUS.clone() + FieldElement::from(1u32), + ); + } + + #[derive(Debug, Clone, PartialEq)] + struct F { + foo: [FieldElement; 3], + } + + impl Default for F { + fn default() -> Self { + F { + foo: std::array::from_fn(|_| FieldElement::from(0u32)), + } + } + } + + #[test] + fn test_sparse_lookup_struct() { + let values = vec![ + F { + foo: [field("1"), field("2"), field("3")], + }, + F { + foo: [field("4"), field("5"), field("6")], + }, + F { + foo: [field("7"), field("8"), field("9")], + }, + F { + foo: [field("10"), field("11"), field("12")], + }, + ]; + let keys = vec![field("1"), field("99"), field("7"), field("5")]; + let example = SparseArray::create(&keys, &values, field("100000")); + + assert_eq!(*example.get(&field("1")), values[0]); + assert_eq!(*example.get(&field("5")), values[3]); + assert_eq!(*example.get(&field("7")), values[2]); + assert_eq!(*example.get(&field("99")), values[1]); + + for i in 0u32..100 { + let i_field = FieldElement::from(i); + if i_field != field("1") + && i_field != field("5") + && i_field != field("7") + && i_field != field("99") + { + assert_eq!(*example.get(&i_field), F::default()); + } + } + } + + #[test] + fn test_sparse_array_noir_representation() { + let keys = vec![ + field("0"), + field("99999"), + field("7"), + field("4294967295"), // 0xffffffff + ]; + let values = vec![123, 101112, 789, 456]; + let example = SparseArray::create( + &keys, + &values, + field("4294967296"), // 0x100000000 + ); + + let noir_str = example.to_noir_string(None); + println!("\n\n===\n{}\n\n", noir_str); + let expected = "\ + sparse_array::SparseArray = sparse_array::SparseArray {\n \ + keys: [0x00000000, 0x00000000, 0x00000007, 0x0001869f, 0xffffffff, 0xffffffff],\n \ + values: [0x00000000, 0x0000007b, 0x0000007b, 0x00000315, 0x00018af8, 0x000001c8, 0x000001c8],\n \ + maximum: 0xffffffff\n\ + };"; + + assert_eq!(noir_str, expected); + } + + // Test cases for console output + // #[test] + // fn print_sparse_array_10_random() { + // let keys = vec![ + // field("0x33333"), + // field("0x1234"), + // field("0xFFFFF"), + // field("0x5678"), + // field("0x22222"), + // field("0xDEF0"), + // field("0x11111"), + // field("0x9ABC"), + // field("0x44444"), + // field("0x55555"), + // ]; + + // let values = vec![700, 100, 1000, 200, 600, 400, 500, 300, 800, 900]; + // let example = SparseArray::create(&keys, &values, field("0x100000")); + // println!( + // "Array size 10 (randomized):\n{}", + // example.to_noir_string(None) + // ); + // } + + // #[test] + // fn print_sparse_array_25_random() { + // let keys = vec![ + // field("0xE000"), + // field("0x1000"), + // field("0x50000"), + // field("0x8000"), + // field("0x20000"), + // field("0xA000"), + // field("0x30000"), + // field("0x6000"), + // field("0x90000"), + // field("0xF000"), + // field("0x40000"), + // field("0x100"), + // field("0xB000"), + // field("0x70000"), + // field("0x2000"), + // field("0xC000"), + // field("0x3000"), + // field("0x80000"), + // field("0x4000"), + // field("0xD000"), + // field("0x5000"), + // field("0x10000"), + // field("0x7000"), + // field("0x60000"), + // field("0x9000"), + // ]; + // let values = vec![ + // 7777, 222, 33333, 888, 11111, 2222, 22222, 777, 77777, 8888, 44444, 111, 3333, 55555, + // 333, 4444, 444, 66666, 555, 5555, 666, 9999, 999, 44444, 1111, + // ]; + // let example = SparseArray::create(&keys, &values, field("0x100000")); + // println!( + // "Array size 25 (randomized):\n{}", + // example.to_noir_string(None) + // ); + // } + + #[test] + fn print_sparse_array_50_random() { + let keys = vec![ + field("0x3700"), + field("0x100"), + field("0x2200"), + field("0x4300"), + field("0x1800"), + field("0x3300"), + field("0x900"), + field("0x2800"), + field("0x4400"), + field("0x1400"), + field("0x2F00"), + field("0xE00"), + field("0x2500"), + field("0x3F00"), + field("0x1B00"), + field("0x3600"), + field("0xC00"), + field("0x2B00"), + field("0x4000"), + field("0x1700"), + field("0x3200"), + field("0x800"), + field("0x2100"), + field("0x3C00"), + field("0x1300"), + field("0x2D00"), + field("0x400"), + field("0x1900"), + field("0x3800"), + field("0xF00"), + field("0x2600"), + field("0x200"), + field("0x1500"), + field("0x3400"), + field("0xB00"), + field("0x2A00"), + field("0x4100"), + field("0x1600"), + field("0x3100"), + field("0x700"), + field("0x2000"), + field("0x3900"), + field("0x1200"), + field("0x2C00"), + field("0x4200"), + field("0x1A00"), + field("0x3500"), + field("0xD00"), + field("0x2700"), + field("0x3000"), + ]; + let values = vec![ + field("3700"), + field("100"), + field("2200"), + field("4300"), + field("1800"), + field("3300"), + field("900"), + field("2800"), + field("4400"), + field("1400"), + field("2900"), + field("1300"), + field("2500"), + field("3900"), + field("1900"), + field("3600"), + field("1200"), + field("2700"), + field("4000"), + field("1700"), + field("3200"), + field("800"), + field("2100"), + field("3800"), + field("1300"), + field("2800"), + field("400"), + field("1900"), + field("3700"), + field("1500"), + field("2600"), + field("200"), + field("1500"), + field("3400"), + field("1100"), + field("2600"), + field("4100"), + field("1600"), + field("3100"), + field("700"), + field("2000"), + field("3900"), + field("1200"), + field("2700"), + field("4200"), + field("1800"), + field("3500"), + field("1300"), + field("2700"), + field("3000"), + ]; + let example = SparseArray::create(&keys, &values, field("0x5000")); + println!( + "Array size 50 (randomized):\n{}", + example.to_noir_string(None) + ); + } +} diff --git a/src/lib.nr b/src/lib.nr index 555aba6..a266468 100644 --- a/src/lib.nr +++ b/src/lib.nr @@ -184,6 +184,14 @@ mod test { } } + #[test] + fn test_2() { + let keys = [0, 99999, 7, 4294967295]; + let values = [123, 101112, 789, 456]; + let example = SparseArray::create(keys, values, 0x100000000); + println(example); + } + #[test] fn test_sparse_lookup_boundary_cases() { // what about when keys[0] = 0 and keys[N-1] = 2^32 - 1? @@ -193,6 +201,9 @@ mod test { 0x100000000, ); + println("keys"); + println(example.keys); + assert(example.get(0) == 123); assert(example.get(99999) == 101112); assert(example.get(7) == 789); @@ -276,4 +287,146 @@ mod test { } } } + + #[test] + fn test_codegen_length_10() { + let example_10 = SparseArray::create( + [0x33333, 0x1234, 0xFFFFF, 0x5678, 0x22222, 0xDEF0, 0x11111, 0x9ABC, 0x44444, 0x55555], + [700, 100, 1000, 200, 600, 400, 500, 300, 800, 900], + 0x100000, + ); + + let table: SparseArray<10, Field> = SparseArray { + keys: [ + 0x00000000, 0x00001234, 0x00005678, 0x00009abc, 0x0000def0, 0x00011111, 0x00022222, + 0x00033333, 0x00044444, 0x00055555, 0x000fffff, 0x000fffff, + ], + values: [ + 0x00000000, 0x00000000, 0x000001f4, 0x000002bc, 0x00000384, 0x00000064, 0x00000190, + 0x000000c8, 0x00000258, 0x000003e8, 0x0000012c, 0x00000320, 0x00000000, + ], + maximum: 0x000fffff, + }; + + // sample blank space + for i in 0..(0x100000 / 0x00100) { + let index = (i * 0x00100) as Field; + assert(example_10.get(index) == table.get(index)); + } + + // check all keys + for i in 0..example_10.keys.len() { + let key = example_10.keys[i]; + assert(example_10.get(key) == table.get(key)); + } + + // check maximum + assert_eq(table.maximum, example_10.maximum); + } + + #[test] + fn test_codegen_length_25() { + let example_25 = SparseArray::create( + [ + 0xE000, 0x1000, 0x50000, 0x8000, 0x20000, 0xA000, 0x30000, 0x6000, 0x90000, 0xF000, + 0x40000, 0x100, 0xB000, 0x70000, 0x2000, 0xC000, 0x3000, 0x80000, 0x4000, 0xD000, + 0x5000, 0x10000, 0x7000, 0x60000, 0x9000, + ], + [ + 7777, 222, 33333, 888, 11111, 2222, 22222, 777, 77777, 8888, 44444, 111, 3333, + 55555, 333, 4444, 444, 66666, 555, 5555, 666, 9999, 999, 44444, 1111, + ], + 0x100000, + ); + + let table: SparseArray<25, Field> = SparseArray { + keys: [ + 0x00000000, 0x00000100, 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, + 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, + 0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00020000, 0x00030000, 0x00040000, + 0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x00100000, + ], + values: [ + 0x00000000, 0x00000000, 0x0000014d, 0x000000de, 0x0000029a, 0x00012fd1, 0x0001046a, + 0x0000ad9c, 0x0000022b, 0x000056ce, 0x00000457, 0x0000115c, 0x000015b3, 0x00001e61, + 0x0000006f, 0x000003e7, 0x00008235, 0x00000d05, 0x00000378, 0x0000ad9c, 0x00002b67, + 0x0000d903, 0x000008ae, 0x000001bc, 0x00000309, 0x0000270f, 0x000022b8, 0x00000000, + ], + maximum: 0x000fffff, + }; + + // sample blank space + for i in 0..(0x100000 / 0x00100) { + let index = (i * 0x00100) as Field; + assert(example_25.get(index) == table.get(index)); + } + + // check all keys + for i in 0..example_25.keys.len() { + let key = example_25.keys[i]; + assert(example_25.get(key) == table.get(key)); + } + + // check maximum + assert_eq(table.maximum, example_25.maximum); + } + + #[test] + fn test_codegen_length_50() { + let example_50 = SparseArray::create( + [ + 0x3700, 0x100, 0x2200, 0x4300, 0x1800, 0x3300, 0x900, 0x2800, 0x4400, 0x1400, + 0x2F00, 0xE00, 0x2500, 0x3F00, 0x1B00, 0x3600, 0xC00, 0x2B00, 0x4000, 0x1700, + 0x3200, 0x800, 0x2100, 0x3C00, 0x1300, 0x2D00, 0x400, 0x1900, 0x3800, 0xF00, 0x2600, + 0x200, 0x1500, 0x3400, 0xB00, 0x2A00, 0x4100, 0x1600, 0x3100, 0x700, 0x2000, 0x3900, + 0x1200, 0x2C00, 0x4200, 0x1A00, 0x3500, 0xD00, 0x2700, 0x3000, + ], + [ + 3700, 100, 2200, 4300, 1800, 3300, 900, 2800, 4400, 1400, 2900, 1300, 2500, 3900, + 1900, 3600, 1200, 2700, 4000, 1700, 3200, 800, 2100, 3800, 1300, 2800, 400, 1900, + 3700, 1500, 2600, 200, 1500, 3400, 1100, 2600, 4100, 1600, 3100, 700, 2000, 3900, + 1200, 2700, 4200, 1800, 3500, 1300, 2700, 3000, + ], + 0x5000, + ); + + let table: SparseArray<50, Field> = SparseArray { + keys: [ + 0x00000000, 0x00000100, 0x00000200, 0x00000400, 0x00000700, 0x00000800, 0x00000900, + 0x00000b00, 0x00000c00, 0x00000d00, 0x00000e00, 0x00000f00, 0x00001200, 0x00001300, + 0x00001400, 0x00001500, 0x00001600, 0x00001700, 0x00001800, 0x00001900, 0x00001a00, + 0x00001b00, 0x00002000, 0x00002100, 0x00002200, 0x00002500, 0x00002600, 0x00002700, + 0x00002800, 0x00002a00, 0x00002b00, 0x00002c00, 0x00002d00, 0x00002f00, 0x00003000, + 0x00003100, 0x00003200, 0x00003300, 0x00003400, 0x00003500, 0x00003600, 0x00003700, + 0x00003800, 0x00003900, 0x00003c00, 0x00003f00, 0x00004000, 0x00004100, 0x00004200, + 0x00004300, 0x00004400, 0x00004fff, + ], + values: [ + 0x00000000, 0x00000000, 0x000007d0, 0x00000e74, 0x00000ed8, 0x00000a8c, 0x00000a8c, + 0x00001004, 0x00000ce4, 0x0000076c, 0x00000bb8, 0x00000f3c, 0x000005dc, 0x00000578, + 0x00000514, 0x00001068, 0x00000c80, 0x000002bc, 0x00000af0, 0x000005dc, 0x00000708, + 0x000004b0, 0x00000a28, 0x00000708, 0x00000834, 0x00000a8c, 0x000009c4, 0x000000c8, + 0x00000898, 0x00000fa0, 0x00000f3c, 0x00000b54, 0x00000af0, 0x00000064, 0x0000076c, + 0x00000640, 0x00000384, 0x00000e74, 0x00000dac, 0x00000e10, 0x0000044c, 0x000010cc, + 0x00000320, 0x000004b0, 0x00000514, 0x00000a28, 0x00000514, 0x000006a4, 0x00000c1c, + 0x00001130, 0x00000190, 0x00000d48, 0x00000000, + ], + maximum: 0x00004fff, + }; + + // sample blank space + for i in 0..(0x00005000 / 0x0010) { + let index = (i * 0x0010) as Field; + assert(example_50.get(index) == table.get(index)); + } + + // check all keys + for i in 0..example_50.keys.len() { + let key = example_50.keys[i]; + assert(example_50.get(key) == table.get(key)); + } + + // check maximum + assert_eq(table.maximum, example_50.maximum); + } } diff --git a/src/mut_sparse_array.nr b/src/mut_sparse_array.nr index 962aa60..5a247e7 100644 --- a/src/mut_sparse_array.nr +++ b/src/mut_sparse_array.nr @@ -207,7 +207,7 @@ where fn get(self, idx: Field) -> T { let (found, found_index) = unsafe { self.search_for_key(idx) }; - println(f"f {found} fi {found_index}"); + // println(f"f {found} fi {found_index}"); assert(found * found == found); let lhs_index = found_index;