✅ test: proving to myself that string interning is a good idea
							parent
							
								
									bba98043c7
								
							
						
					
					
						commit
						247d6b7a24
					
				|  | @ -0,0 +1,443 @@ | |||
| use std::{ | ||||
| 	collections::{BTreeMap, HashMap}, | ||||
| 	time::Instant, | ||||
| }; | ||||
| 
 | ||||
| fn main () { | ||||
| 	// PUC Lua is 250 ms
 | ||||
| 	// I'm using AOT Rust here so anything more than that 
 | ||||
| 	// is simply embarrassing
 | ||||
| 	
 | ||||
| 	fn timer <F: Fn ()> (f: F, label: &str) { | ||||
| 		let start = Instant::now (); | ||||
| 		f (); | ||||
| 		let stop = Instant::now (); | ||||
| 		println! ("{}: {} ms", label, (stop - start).as_millis ()); | ||||
| 	} | ||||
| 	
 | ||||
| 	timer (|| n_body::<BTreeTable> (100000), "BTreeTable"); | ||||
| 	timer (|| n_body::<BTreeTable2> (100000), "BTreeTable2"); | ||||
| 	timer (|| n_body::<HashTable> (100000), "HashTable"); | ||||
| 	timer (|| n_body_2::<HashTable2> (100000), "HashTable2"); | ||||
| 	timer (|| n_body_2::<BTreeTable3> (100000), "BTreeTable3"); | ||||
| } | ||||
| 
 | ||||
| trait Table { | ||||
| 	fn get (&self, key: &str) -> f64; | ||||
| 	fn set (&mut self, key: &'static str, value: f64); | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct BTreeTable (BTreeMap <String, f64>); | ||||
| 
 | ||||
| impl Table for BTreeTable { | ||||
| 	fn get (&self, key: &str) -> f64 { | ||||
| 		*self.0.get (key).unwrap () | ||||
| 	} | ||||
| 	
 | ||||
| 	fn set (&mut self, key: &str, value: f64) { | ||||
| 		self.0.insert (key.to_string (), value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct BTreeTable2 (BTreeMap <&'static str, f64>); | ||||
| 
 | ||||
| impl Table for BTreeTable2 { | ||||
| 	fn get (&self, key: &str) -> f64 { | ||||
| 		*self.0.get (key).unwrap () | ||||
| 	} | ||||
| 	
 | ||||
| 	fn set (&mut self, key: &'static str, value: f64) { | ||||
| 		self.0.insert (key, value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct HashTable (HashMap <String, f64>); | ||||
| 
 | ||||
| impl Table for HashTable { | ||||
| 	fn get (&self, key: &str) -> f64 { | ||||
| 		*self.0.get (key).unwrap () | ||||
| 	} | ||||
| 	
 | ||||
| 	fn set (&mut self, key: &str, value: f64) { | ||||
| 		self.0.insert (key.to_string (), value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const PI: f64 = 3.141592653589793f64; | ||||
| const SOLAR_MASS: f64 = 4.0 * PI * PI; | ||||
| 
 | ||||
| fn n_body <T: Default + Table> (num_iters: usize) { | ||||
| 	const X: &str = "x"; | ||||
| 	const Y: &str = "y"; | ||||
| 	const Z: &str = "z"; | ||||
| 	const VX: &str = "vx"; | ||||
| 	const VY: &str = "vy"; | ||||
| 	const VZ: &str = "vz"; | ||||
| 	const MASS: &str = "mass"; | ||||
| 	
 | ||||
| 	let days_per_year = 365.24; | ||||
| 	
 | ||||
| 	let mut bodies = vec! []; | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 0.0); | ||||
| 		t.set (Y, 0.0); | ||||
| 		t.set (Z, 0.0); | ||||
| 		t.set (VX, 0.0); | ||||
| 		t.set (VY, 0.0); | ||||
| 		t.set (VZ, 0.0); | ||||
| 		t.set (MASS, SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 4.84143144246472090e+00); | ||||
| 		t.set (Y, -1.16032004402742839e+00); | ||||
| 		t.set (Z, -1.03622044471123109e-01); | ||||
| 		t.set (VX, 1.66007664274403694e-03 * days_per_year); | ||||
| 		t.set (VY, 7.69901118419740425e-03 * days_per_year); | ||||
| 		t.set (VZ, -6.90460016972063023e-05 * days_per_year); | ||||
| 		t.set (MASS, 9.54791938424326609e-04 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 8.34336671824457987e+00); | ||||
| 		t.set (Y, 4.12479856412430479e+00); | ||||
| 		t.set (Z, -4.03523417114321381e-01); | ||||
| 		t.set (VX, -2.76742510726862411e-03 * days_per_year); | ||||
| 		t.set (VY, 4.99852801234917238e-03 * days_per_year); | ||||
| 		t.set (VZ, 2.30417297573763929e-05 * days_per_year); | ||||
| 		t.set (MASS, 2.85885980666130812e-04 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 1.28943695621391310e+01); | ||||
| 		t.set (Y, -1.51111514016986312e+01); | ||||
| 		t.set (Z, -2.23307578892655734e-01); | ||||
| 		t.set (VX, 2.96460137564761618e-03 * days_per_year); | ||||
| 		t.set (VY, 2.37847173959480950e-03 * days_per_year); | ||||
| 		t.set (VZ, -2.96589568540237556e-05 * days_per_year); | ||||
| 		t.set (MASS, 4.36624404335156298e-05 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 1.53796971148509165e+01); | ||||
| 		t.set (Y, -2.59193146099879641e+01); | ||||
| 		t.set (Z, 1.79258772950371181e-01); | ||||
| 		t.set (VX, 2.68067772490389322e-03 * days_per_year); | ||||
| 		t.set (VY, 1.62824170038242295e-03 * days_per_year); | ||||
| 		t.set (VZ, -9.51592254519715870e-05 * days_per_year); | ||||
| 		t.set (MASS, 5.15138902046611451e-05 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	
 | ||||
| 	fn advance <T: Table> (bodies: &mut [T], dt: f64) { | ||||
| 		let nbody = bodies.len (); | ||||
| 		
 | ||||
| 		for i in 0..nbody { | ||||
| 			let bix; | ||||
| 			let biy; | ||||
| 			let biz; | ||||
| 			let bimass; | ||||
| 			let mut bivx; | ||||
| 			let mut bivy; | ||||
| 			let mut bivz; | ||||
| 			{ | ||||
| 				let bi = &mut bodies [i]; | ||||
| 				bix = bi.get (X); | ||||
| 				biy = bi.get (Y); | ||||
| 				biz = bi.get (Z); | ||||
| 				bimass = bi.get (MASS); | ||||
| 				bivx = bi.get (VX); | ||||
| 				bivy = bi.get (VY); | ||||
| 				bivz = bi.get (VZ); | ||||
| 			} | ||||
| 			
 | ||||
| 			for j in i + 1..nbody { | ||||
| 				let bj = &mut bodies [j]; | ||||
| 				let dx = bix - bj.get (X); | ||||
| 				let dy = biy - bj.get (Y); | ||||
| 				let dz = biz - bj.get (Z); | ||||
| 				let mut mag = (dx * dx + dy * dy + dz * dz).sqrt (); | ||||
| 				mag = dt / (mag * mag * mag); | ||||
| 				let mut bm = bj.get (MASS) * mag; | ||||
| 				bivx -= dx * bm; | ||||
| 				bivy -= dy * bm; | ||||
| 				bivz -= dz * bm; | ||||
| 				bm = bimass * mag; | ||||
| 				bj.set (VX, bj.get (VX) + dx * bm); | ||||
| 				bj.set (VY, bj.get (VY) + dy * bm); | ||||
| 				bj.set (VZ, bj.get (VZ) + dz * bm); | ||||
| 			} | ||||
| 			
 | ||||
| 			let bi = &mut bodies [i]; | ||||
| 			bi.set (VX, bivx); | ||||
| 			bi.set (VY, bivy); | ||||
| 			bi.set (VZ, bivz); | ||||
| 			bi.set (X, bix + dt * bivx); | ||||
| 			bi.set (Y, biy + dt * bivy); | ||||
| 			bi.set (Z, biz + dt * bivz); | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	fn energy <T: Table> (bodies: &[T]) -> f64 { | ||||
| 		let mut e = 0.0; | ||||
| 		for (i, bi) in bodies.iter ().enumerate () { | ||||
| 			let vx = bi.get (VX); | ||||
| 			let vy = bi.get (VY); | ||||
| 			let vz = bi.get (VZ); | ||||
| 			let bim = bi.get (MASS); | ||||
| 			
 | ||||
| 			e += 0.5 * bim * (vx * vx + vy * vy + vz * vz); | ||||
| 			
 | ||||
| 			for j in i + 1..bodies.len () { | ||||
| 				let bj = &bodies [j]; | ||||
| 				let dx = bi.get (X) - bj.get (X); | ||||
| 				let dy = bi.get (Y) - bj.get (Y); | ||||
| 				let dz = bi.get (Z) - bj.get (Z); | ||||
| 				let distance = (dx * dx + dy * dy + dz * dz).sqrt (); | ||||
| 				e -= (bim * bj.get (MASS)) / distance; | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		e | ||||
| 	} | ||||
| 	
 | ||||
| 	fn offset_momentum <T: Table> (b: &mut [T]) { | ||||
| 		let mut px = 0.0; | ||||
| 		let mut py = 0.0; | ||||
| 		let mut pz = 0.0; | ||||
| 		
 | ||||
| 		for bi in b.iter () { | ||||
| 			let bim = bi.get (MASS); | ||||
| 			px += bi.get (VX) * bim; | ||||
| 			py += bi.get (VY) * bim; | ||||
| 			pz += bi.get (VZ) * bim; | ||||
| 		} | ||||
| 		
 | ||||
| 		let bimass = b [0].get (MASS); | ||||
| 		b [0].set (VX, -px / bimass); | ||||
| 		b [0].set (VY, -py / bimass); | ||||
| 		b [0].set (VZ, -pz / bimass); | ||||
| 	} | ||||
| 	
 | ||||
| 	offset_momentum (&mut bodies); | ||||
| 	println! ("{:0.9}", energy (&bodies)); | ||||
| 	for _ in 0..num_iters { | ||||
| 		advance (&mut bodies, 0.01); | ||||
| 	} | ||||
| 	println! ("{:0.9}", energy (&bodies)); | ||||
| } | ||||
| 
 | ||||
| trait Table2 { | ||||
| 	fn get (&self, key: i64) -> f64; | ||||
| 	fn set (&mut self, key: i64, value: f64); | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct BTreeTable3 (BTreeMap <i64, f64>); | ||||
| 
 | ||||
| impl Table2 for BTreeTable3 { | ||||
| 	fn get (&self, key: i64) -> f64 { | ||||
| 		*self.0.get (&key).unwrap () | ||||
| 	} | ||||
| 	
 | ||||
| 	fn set (&mut self, key: i64, value: f64) { | ||||
| 		self.0.insert (key, value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct HashTable2 (HashMap <i64, f64>); | ||||
| 
 | ||||
| impl Table2 for HashTable2 { | ||||
| 	fn get (&self, key: i64) -> f64 { | ||||
| 		*self.0.get (&key).unwrap () | ||||
| 	} | ||||
| 	
 | ||||
| 	fn set (&mut self, key: i64, value: f64) { | ||||
| 		self.0.insert (key, value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn n_body_2 <T: Default + Table2> (num_iters: usize) { | ||||
| 	const X: i64 = 1; | ||||
| 	const Y: i64 = 2; | ||||
| 	const Z: i64 = 3; | ||||
| 	const VX: i64 = 4; | ||||
| 	const VY: i64 = 5; | ||||
| 	const VZ: i64 = 6; | ||||
| 	const MASS: i64 = 7; | ||||
| 	
 | ||||
| 	let days_per_year = 365.24; | ||||
| 	
 | ||||
| 	let mut bodies = vec! []; | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 0.0); | ||||
| 		t.set (Y, 0.0); | ||||
| 		t.set (Z, 0.0); | ||||
| 		t.set (VX, 0.0); | ||||
| 		t.set (VY, 0.0); | ||||
| 		t.set (VZ, 0.0); | ||||
| 		t.set (MASS, SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 4.84143144246472090e+00); | ||||
| 		t.set (Y, -1.16032004402742839e+00); | ||||
| 		t.set (Z, -1.03622044471123109e-01); | ||||
| 		t.set (VX, 1.66007664274403694e-03 * days_per_year); | ||||
| 		t.set (VY, 7.69901118419740425e-03 * days_per_year); | ||||
| 		t.set (VZ, -6.90460016972063023e-05 * days_per_year); | ||||
| 		t.set (MASS, 9.54791938424326609e-04 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 8.34336671824457987e+00); | ||||
| 		t.set (Y, 4.12479856412430479e+00); | ||||
| 		t.set (Z, -4.03523417114321381e-01); | ||||
| 		t.set (VX, -2.76742510726862411e-03 * days_per_year); | ||||
| 		t.set (VY, 4.99852801234917238e-03 * days_per_year); | ||||
| 		t.set (VZ, 2.30417297573763929e-05 * days_per_year); | ||||
| 		t.set (MASS, 2.85885980666130812e-04 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 1.28943695621391310e+01); | ||||
| 		t.set (Y, -1.51111514016986312e+01); | ||||
| 		t.set (Z, -2.23307578892655734e-01); | ||||
| 		t.set (VX, 2.96460137564761618e-03 * days_per_year); | ||||
| 		t.set (VY, 2.37847173959480950e-03 * days_per_year); | ||||
| 		t.set (VZ, -2.96589568540237556e-05 * days_per_year); | ||||
| 		t.set (MASS, 4.36624404335156298e-05 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	{ | ||||
| 		let mut t = T::default (); | ||||
| 		t.set (X, 1.53796971148509165e+01); | ||||
| 		t.set (Y, -2.59193146099879641e+01); | ||||
| 		t.set (Z, 1.79258772950371181e-01); | ||||
| 		t.set (VX, 2.68067772490389322e-03 * days_per_year); | ||||
| 		t.set (VY, 1.62824170038242295e-03 * days_per_year); | ||||
| 		t.set (VZ, -9.51592254519715870e-05 * days_per_year); | ||||
| 		t.set (MASS, 5.15138902046611451e-05 * SOLAR_MASS); | ||||
| 		
 | ||||
| 		bodies.push (t); | ||||
| 	} | ||||
| 	
 | ||||
| 	fn advance <T: Table2> (bodies: &mut [T], dt: f64) { | ||||
| 		let nbody = bodies.len (); | ||||
| 		
 | ||||
| 		for i in 0..nbody { | ||||
| 			let bix; | ||||
| 			let biy; | ||||
| 			let biz; | ||||
| 			let bimass; | ||||
| 			let mut bivx; | ||||
| 			let mut bivy; | ||||
| 			let mut bivz; | ||||
| 			{ | ||||
| 				let bi = &mut bodies [i]; | ||||
| 				bix = bi.get (X); | ||||
| 				biy = bi.get (Y); | ||||
| 				biz = bi.get (Z); | ||||
| 				bimass = bi.get (MASS); | ||||
| 				bivx = bi.get (VX); | ||||
| 				bivy = bi.get (VY); | ||||
| 				bivz = bi.get (VZ); | ||||
| 			} | ||||
| 			
 | ||||
| 			for j in i + 1..nbody { | ||||
| 				let bj = &mut bodies [j]; | ||||
| 				let dx = bix - bj.get (X); | ||||
| 				let dy = biy - bj.get (Y); | ||||
| 				let dz = biz - bj.get (Z); | ||||
| 				let mut mag = (dx * dx + dy * dy + dz * dz).sqrt (); | ||||
| 				mag = dt / (mag * mag * mag); | ||||
| 				let mut bm = bj.get (MASS) * mag; | ||||
| 				bivx -= dx * bm; | ||||
| 				bivy -= dy * bm; | ||||
| 				bivz -= dz * bm; | ||||
| 				bm = bimass * mag; | ||||
| 				bj.set (VX, bj.get (VX) + dx * bm); | ||||
| 				bj.set (VY, bj.get (VY) + dy * bm); | ||||
| 				bj.set (VZ, bj.get (VZ) + dz * bm); | ||||
| 			} | ||||
| 			
 | ||||
| 			let bi = &mut bodies [i]; | ||||
| 			bi.set (VX, bivx); | ||||
| 			bi.set (VY, bivy); | ||||
| 			bi.set (VZ, bivz); | ||||
| 			bi.set (X, bix + dt * bivx); | ||||
| 			bi.set (Y, biy + dt * bivy); | ||||
| 			bi.set (Z, biz + dt * bivz); | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	fn energy <T: Table2> (bodies: &[T]) -> f64 { | ||||
| 		let mut e = 0.0; | ||||
| 		for (i, bi) in bodies.iter ().enumerate () { | ||||
| 			let vx = bi.get (VX); | ||||
| 			let vy = bi.get (VY); | ||||
| 			let vz = bi.get (VZ); | ||||
| 			let bim = bi.get (MASS); | ||||
| 			
 | ||||
| 			e += 0.5 * bim * (vx * vx + vy * vy + vz * vz); | ||||
| 			
 | ||||
| 			for j in i + 1..bodies.len () { | ||||
| 				let bj = &bodies [j]; | ||||
| 				let dx = bi.get (X) - bj.get (X); | ||||
| 				let dy = bi.get (Y) - bj.get (Y); | ||||
| 				let dz = bi.get (Z) - bj.get (Z); | ||||
| 				let distance = (dx * dx + dy * dy + dz * dz).sqrt (); | ||||
| 				e -= (bim * bj.get (MASS)) / distance; | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		e | ||||
| 	} | ||||
| 	
 | ||||
| 	fn offset_momentum <T: Table2> (b: &mut [T]) { | ||||
| 		let mut px = 0.0; | ||||
| 		let mut py = 0.0; | ||||
| 		let mut pz = 0.0; | ||||
| 		
 | ||||
| 		for bi in b.iter () { | ||||
| 			let bim = bi.get (MASS); | ||||
| 			px += bi.get (VX) * bim; | ||||
| 			py += bi.get (VY) * bim; | ||||
| 			pz += bi.get (VZ) * bim; | ||||
| 		} | ||||
| 		
 | ||||
| 		let bimass = b [0].get (MASS); | ||||
| 		b [0].set (VX, -px / bimass); | ||||
| 		b [0].set (VY, -py / bimass); | ||||
| 		b [0].set (VZ, -pz / bimass); | ||||
| 	} | ||||
| 	
 | ||||
| 	offset_momentum (&mut bodies); | ||||
| 	println! ("{:0.9}", energy (&bodies)); | ||||
| 	for _ in 0..num_iters { | ||||
| 		advance (&mut bodies, 0.01); | ||||
| 	} | ||||
| 	println! ("{:0.9}", energy (&bodies)); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	 _
						_