diff --git a/src/electronics/coulombs_law.rs b/src/electronics/coulombs_law.rs new file mode 100644 index 00000000000..5704a0dbea3 --- /dev/null +++ b/src/electronics/coulombs_law.rs @@ -0,0 +1,183 @@ +/// Apply Coulomb's Law on any three given values. These can be force, charge1, +/// charge2, or distance, and then in a Python dict return name/value pair of +/// the zero value. +/// +/// Coulomb's Law states that the magnitude of the electrostatic force of +/// attraction or repulsion between two point charges is directly proportional +/// to the product of the magnitudes of charges and inversely proportional to +/// the square of the distance between them. +/// +/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Coulomb%27s_law + +const COULOMBS_CONSTANT: f64 = 8.9875517923e9; +#[derive(PartialEq, Eq, Debug)] +pub enum CoulombsLawError { + ExtraZeroArg(String), + NegativeDistance(String), +} +pub fn coulombs_law( + force: f64, + charge1: f64, + charge2: f64, + distance: f64, +) -> Result { + let charge_product = (charge1 * charge2).abs(); + + if invalid_arguments(force, charge1, charge2, distance) { + return Err(CoulombsLawError::ExtraZeroArg(String::from( + "One and only one argument must be 0", + ))); + } + + if distance < 0.0 { + return Err(CoulombsLawError::NegativeDistance(String::from( + "Distance cannot be negative", + ))); + } + + if force == 0.0 { + return Ok(format!( + "force: {}", + calculate_force(charge_product, distance) + )); + } else if charge1 == 0.0 { + return Ok(format!( + "charge1: {}", + calculate_charge(charge2, force, distance) + )); + } else if charge2 == 0.0 { + return Ok(format!( + "charge2: {}", + calculate_charge(charge1, force, distance) + )); + } + Ok(format!( + "distance: {}", + calculate_distance(charge_product, force) + )) +} +fn calculate_distance(charge_product: f64, force: f64) -> f64 { + (COULOMBS_CONSTANT * charge_product / force.abs()).sqrt() +} +fn calculate_charge(charge: f64, force: f64, distance: f64) -> f64 { + force.abs() * distance.powi(2) / (COULOMBS_CONSTANT * charge) +} +fn calculate_force(charge_product: f64, distance: f64) -> f64 { + COULOMBS_CONSTANT * charge_product / distance.powi(2) +} + +fn invalid_arguments(force: f64, charge1: f64, charge2: f64, distance: f64) -> bool { + [force, charge1, charge2, distance] + .iter() + .filter(|&&x| x == 0.0) + .count() + != 1 +} + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! test_calculate_force { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((charge_product,distance), expected) = $inputs; + assert_eq!(calculate_force(charge_product,distance), expected); + } + )* + } + } + + macro_rules! test_calculate_charge { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((charge,force,distance), expected) = $inputs; + assert_eq!(calculate_charge(charge,force,distance), expected); + } + )* + } + } + macro_rules! test_calculate_distance { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((charge_product,force), expected) = $inputs; + assert_eq!(calculate_distance(charge_product,force), expected); + } + )* + } + } + + macro_rules! test_invalid_arguments { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((force,charge1,charge2,distance), expected) = $inputs; + assert_eq!(invalid_arguments(force,charge1,charge2,distance), expected); + } + )* + } + } + macro_rules! test_coulombs_law { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((force,charge1,charge2,distance), expected) = $inputs; + assert_eq!(coulombs_law(force,charge1,charge2,distance).unwrap(), String::from(expected)); + } + )* + } + } + + macro_rules! test_coulombs_law_err { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((force,charge1,charge2,distance), expected) = $inputs; + assert_eq!(coulombs_law(force,charge1,charge2,distance).unwrap_err(), expected); + } + )* + } + } + + test_coulombs_law! { + general_inputs1:((0.0, 3.0, 5.0, 2000.0), "force: 33703.319221125"), + general_inputs2:((10.0, 3.0, 5.0, 0.0), "distance: 116109.11974711547"), + general_inputs3:((10.0, 0.0, 5.0, 2000.0), "charge1: 0.0008901200443544508"), + general_inputs4:((10.0, 5.0,0.0 , 2000.0), "charge2: 0.0008901200443544508"), + } + + test_coulombs_law_err! { + extra_zero_arg_err: ((0.0, 3.0, 0.0, 2000.0), CoulombsLawError::ExtraZeroArg(String::from("One and only one argument must be 0"))), + negative_distance_err: ((0.0, 3.0, 5.0, -2000.0), CoulombsLawError::NegativeDistance(String::from("Distance cannot be negative"))), + } + + test_invalid_arguments! { + valid_argument_input: ((0.0, 3.0, 5.0, 2000.0), false), + invalid_argument_input: ((0.0, 0.0, 5.0, 2000.0), true), + all_argument_zero: ((0.0, 0.0, 0.0, 0.0), true), + } + + test_calculate_force! { + force_test1: ((15.0,2000.0),33703.319221125), + force_test2: ((18.0,0.12),11234439740375.0), + } + + test_calculate_charge! { + charge_test1: ((15.0,6.0,2000.0),0.00017802400887089018), + charge_test2: ((18.0,3.0,0.12),2.6703601330633526e-13), + } + + test_calculate_distance! { + distance_test1: ((15.0,5.0),164203.09186157244), + distance_test2: ((18.0,11.0),121272.02040394374), + } +} diff --git a/src/electronics/mod.rs b/src/electronics/mod.rs new file mode 100644 index 00000000000..2681de2cc05 --- /dev/null +++ b/src/electronics/mod.rs @@ -0,0 +1,2 @@ +mod coulombs_law; +pub use coulombs_law::coulombs_law; diff --git a/src/lib.rs b/src/lib.rs index fb64d09282a..ba5b3b529ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ pub mod compression; pub mod conversions; pub mod data_structures; pub mod dynamic_programming; +pub mod electronics; pub mod financial; pub mod general; pub mod geometry; @@ -15,6 +16,7 @@ pub mod graph; pub mod greedy; pub mod machine_learning; pub mod math; +pub mod matrix; pub mod navigation; pub mod number_theory; pub mod searching; diff --git a/src/matrix/mod.rs b/src/matrix/mod.rs new file mode 100644 index 00000000000..ba394113d3a --- /dev/null +++ b/src/matrix/mod.rs @@ -0,0 +1,2 @@ +mod search_in_a_sorted_matrix; +pub use search_in_a_sorted_matrix::search_in_a_sorted_matrix; diff --git a/src/matrix/search_in_a_sorted_matrix.rs b/src/matrix/search_in_a_sorted_matrix.rs new file mode 100644 index 00000000000..3af78101c0c --- /dev/null +++ b/src/matrix/search_in_a_sorted_matrix.rs @@ -0,0 +1,97 @@ +///find row and column of given key in given matrix +/// m is row count and n is column count +#[derive(PartialEq, Eq, Debug)] +pub struct SortedMatrixResult { + pub column: i64, + pub row: i64, +} +#[derive(PartialEq, Eq, Debug)] +pub enum SortedMatrixErr { + KeyNotFound, + InvalidArgument(String), +} +pub fn search_in_a_sorted_matrix( + mat: Vec>, + m: usize, + n: usize, + key: f64, +) -> Result { + if m < 1 { + return Err(SortedMatrixErr::InvalidArgument(String::from( + "m must be greater than or equal to 1", + ))); + } + + if n < 1 { + return Err(SortedMatrixErr::InvalidArgument(String::from( + "n must be greater than or equal to 1", + ))); + } + + if mat.is_empty() { + return Err(SortedMatrixErr::InvalidArgument(String::from( + "mat must be non-empty", + ))); + } + + let (mut i, mut j) = (m - 1, 0); + + while j < n { + if (mat[i][j] - key).abs() < f64::EPSILON { + return Ok(SortedMatrixResult { + column: (j + 1) as i64, + row: (i + 1) as i64, + }); + } + if key < mat[i][j] { + i -= 1; + } else { + j += 1; + } + } + Err(SortedMatrixErr::KeyNotFound) +} +#[cfg(test)] +mod tests { + use super::*; + macro_rules! test_search_in_a_sorted_matrix_err { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((mat,m,n,key), expected) = $inputs; + assert_eq!(search_in_a_sorted_matrix(mat,m,n,key).unwrap_err(), expected); + } + )* + } + } + macro_rules! test_search_in_a_sorted_matrix { + ($($name:ident: $inputs:expr,)*) => { + $( + #[test] + fn $name() { + let ((mat,m,n,key), expected) = $inputs; + assert_eq!(search_in_a_sorted_matrix(mat,m,n,key).unwrap(), expected); + } + )* + } + } + + test_search_in_a_sorted_matrix_err! { + key_not_found_test: ((vec![vec![1.0,1.0],vec![1.0,1.0]],2,2,4.0), SortedMatrixErr::KeyNotFound), + invalid_m_test: ((vec![vec![1.0,1.0],vec![1.0,1.0]],0,2,4.0), SortedMatrixErr::InvalidArgument(String::from("m must be greater than or equal to 1"))), + invalid_n_test: ((vec![vec![1.0,1.0],vec![1.0,1.0]],2,0,4.0), SortedMatrixErr::InvalidArgument(String::from("n must be greater than or equal to 1"))), + invalid_mat_test: ((vec![],2,1,4.0), SortedMatrixErr::InvalidArgument(String::from("mat must be non-empty"))), + } + + test_search_in_a_sorted_matrix! { + kgeneral_test1: ((vec![vec![2.1, 5.0, 7.0], vec![4.0, 8.0, 13.0], vec![9.0, 11.0, 15.0], vec![12.0, 17.0, 20.0]], 3, 3, 2.1), SortedMatrixResult{ + row:1, + column:1 + }), + kgeneral_test2: (( vec![vec![2.0, 5.0, 7.0], vec![4.0, 8.0, 13.0], vec![9.0, 11.0, 15.0], vec![12.0, 17.0, 20.0]], 3, 3, 5.0), SortedMatrixResult{ + row:1, + column:2 + }), + } +}