first commit

This commit is contained in:
mii443
2025-07-08 20:30:10 +09:00
commit 45d8935738
8 changed files with 551 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

333
Cargo.lock generated Normal file
View File

@ -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",
]

10
Cargo.toml Normal file
View File

@ -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"

44
src/client.rs Normal file
View File

@ -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<SMatrix<f32, GRID_SIZE, 1>>,
}
impl Client {
pub fn new(i: usize, projection_matrix: Vec<SMatrix<f32, GRID_SIZE, 1>>) -> 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)
}
}

24
src/common.rs Normal file
View File

@ -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)
}

5
src/constant.rs Normal file
View File

@ -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;

55
src/main.rs Normal file
View File

@ -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<usize, usize> = 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::<Vec<_>>();
let mut sorted = sorted
.into_iter()
.map(|(k, v)| (*k, *v))
.collect::<Vec<_>>();
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)
);
}
}

79
src/server.rs Normal file
View File

@ -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<SMatrix<f32, GRID_SIZE, 1>> {
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::<f32, GRID_SIZE, 1>::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<SMatrix<f32, GRID_SIZE, 1>>,
) -> HashMap<usize, (usize, Vec<f32>)> {
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<usize, (usize, Vec<f32>)>,
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<usize, (usize, Vec<f32>)>,
observation: (usize, i8),
) -> Vec<usize> {
let ideal_observation = fingerprint_database.get(&observation.0).unwrap();
let locations: Vec<usize> = ideal_observation
.1
.iter()
.map(|o| common::quantize(*o))
.enumerate()
.filter(|(_, quantized)| *quantized == observation.1)
.map(|(i, _)| i)
.collect();
locations
}