commit 45d8935738a3296773fe764ce12d3d227186c327 Author: mii443 Date: Tue Jul 8 20:30:10 2025 +0900 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..69cccd4 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,333 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "independent_randomized_projections" +version = "0.1.0" +dependencies = [ + "nalgebra", + "rand", + "rand_chacha", + "rand_distr", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "nalgebra" +version = "0.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "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-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3502dff --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "independent_randomized_projections" +version = "0.1.0" +edition = "2024" + +[dependencies] +nalgebra = "0.33.2" +rand = "0.9.1" +rand_chacha = "0.9.0" +rand_distr = "0.5.1" diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..7ec7080 --- /dev/null +++ b/src/client.rs @@ -0,0 +1,44 @@ +use nalgebra::SMatrix; + +use crate::{ + common, + constant::{GRID_SIZE, NUM_OF_PROJECTIONS}, +}; + +pub struct Client { + pub i: usize, + pub projection_matrix: Vec>, +} + +impl Client { + pub fn new(i: usize, projection_matrix: Vec>) -> Self { + Client { + i, + projection_matrix, + } + } + + pub fn observe(&mut self, current_grid: (usize, usize)) -> (usize, f32) { + let index = common::grid_to_index(current_grid); + let projection = &self.projection_matrix[self.i]; + + let observation = projection[(index, 0)]; + + let result = (self.i, observation); + + if self.i < NUM_OF_PROJECTIONS { + self.i += 1; + } else { + self.i = 0; + } + + result + } + + pub fn observe_quantized(&mut self, current_grid: (usize, usize)) -> (usize, i8) { + let normal_observation = self.observe(current_grid); + let quantized_observation = common::quantize(normal_observation.1); + + (normal_observation.0, quantized_observation) + } +} diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..a8fab05 --- /dev/null +++ b/src/common.rs @@ -0,0 +1,24 @@ +use crate::constant::{GRID_SIZE, GRID_WIDTH}; + +pub fn quantize(value: f32) -> i8 { + let std_dev = 1.0 / (GRID_SIZE as f32).sqrt(); + + let three_sigma = 3.0 * std_dev; + + let scale_factor = 120.0 / three_sigma; + + let scaled = value * scale_factor; + let clamped = scaled.clamp(-128.0, 127.0); + + clamped.round() as i8 +} + +pub fn grid_to_index(grid: (usize, usize)) -> usize { + grid.0 * GRID_WIDTH + grid.1 +} + +pub fn index_to_grid(index: usize) -> (usize, usize) { + let x = index / GRID_WIDTH; + let y = index % GRID_WIDTH; + (x, y) +} diff --git a/src/constant.rs b/src/constant.rs new file mode 100644 index 0000000..7dace7b --- /dev/null +++ b/src/constant.rs @@ -0,0 +1,5 @@ +pub const GRID_HEIGHT: usize = 500; +pub const GRID_WIDTH: usize = 500; +pub const GRID_SIZE: usize = GRID_HEIGHT * GRID_WIDTH; + +pub const NUM_OF_PROJECTIONS: usize = 256; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..04e5053 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,55 @@ +use std::collections::HashMap; + +use rand::seq::IndexedRandom; + +use crate::constant::NUM_OF_PROJECTIONS; + +pub mod client; +pub mod common; +pub mod constant; +pub mod server; + +fn main() { + println!("Generating projections..."); + let projections = server::generate_projection_matrix(); + + println!("Generating fingerprint database..."); + let fingerprint_database = server::generate_fingerprint_database(projections.clone()); + + let mut client = client::Client::new(0, projections); + + let grid_candidates: Vec<(usize, usize)> = vec![(5, 5), (120, 50), (200, 200), (10, 5)]; + + let mut rng = rand::rng(); + + let mut count: HashMap = HashMap::new(); + for i in 0..NUM_OF_PROJECTIONS { + let current_grid = *grid_candidates.choose(&mut rng).unwrap(); + + let (index, observation) = client.observe_quantized(current_grid); + println!("Observation {i}: index = {index}, observation = {observation}"); + let predictions = server::predict_location_from_database_quantized( + &fingerprint_database, + (index, observation), + ); + for location in predictions.iter() { + count.entry(*location).and_modify(|e| *e += 1).or_insert(1); + } + } + + let sorted = count.iter().collect::>(); + let mut sorted = sorted + .into_iter() + .map(|(k, v)| (*k, *v)) + .collect::>(); + sorted.sort_by(|a, b| b.1.cmp(&a.1)); + + println!("Top 10 locations:"); + for (i, (location, count)) in sorted.iter().take(10).enumerate() { + println!( + "Rank {}: Location: {:?}, Count: {count}", + i + 1, + common::index_to_grid(*location) + ); + } +} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..6784798 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,79 @@ +use std::collections::HashMap; + +use nalgebra::SMatrix; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; +use rand_distr::{Distribution, Normal}; + +use crate::{ + common, + constant::{GRID_SIZE, NUM_OF_PROJECTIONS}, +}; + +pub fn generate_projection_matrix() -> Vec> { + let mut rng = ChaCha20Rng::from_rng(&mut rand::rng()); + + let std_dev = 1.0 / (GRID_SIZE as f64).sqrt(); + let normal = Normal::new(0.0, std_dev).unwrap(); + + (0..NUM_OF_PROJECTIONS) + .map(|_| { + let mut projection = SMatrix::::zeros(); + for i in 0..GRID_SIZE { + projection[(i, 0)] = normal.sample(&mut rng) as f32; + } + projection + }) + .collect() +} + +pub fn generate_fingerprint_database( + projections: Vec>, +) -> HashMap)> { + let mut fingerprint_database = HashMap::new(); + + for (i, projection) in projections.iter().enumerate() { + let mut fingerprint = Vec::with_capacity(GRID_SIZE); + for j in 0..GRID_SIZE { + let observation = projection[(j, 0)]; + fingerprint.push(observation); + } + fingerprint_database.insert(i, (i, fingerprint)); + } + + fingerprint_database +} + +pub fn predict_location_from_database( + fingerprint_database: &HashMap)>, + observation: (usize, f32), +) -> usize { + let ideal_observation = fingerprint_database.get(&observation.0).unwrap(); + let mut min_distance = f32::MAX; + let mut predicted_location = None; + for (i, ideal) in ideal_observation.1.iter().enumerate() { + let distance = (ideal - observation.1).abs(); + if distance < min_distance { + min_distance = distance; + predicted_location = Some(i); + } + } + + predicted_location.unwrap() +} + +pub fn predict_location_from_database_quantized( + fingerprint_database: &HashMap)>, + observation: (usize, i8), +) -> Vec { + let ideal_observation = fingerprint_database.get(&observation.0).unwrap(); + let locations: Vec = ideal_observation + .1 + .iter() + .map(|o| common::quantize(*o)) + .enumerate() + .filter(|(_, quantized)| *quantized == observation.1) + .map(|(i, _)| i) + .collect(); + + locations +}