Skip to content

Commit

Permalink
tests structure and 98 % coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
tomtuamnuq committed Mar 28, 2024
1 parent 647250b commit b8af3c4
Show file tree
Hide file tree
Showing 8 changed files with 661 additions and 474 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["Tom Krüger"]
description = "Perplex (hyperbolic or split-complex) numbers based on num-traits"
documentation = "https://docs.rs/perplex_num"
homepage = "https://github.com/tomtuamnuq/perplex_num"
keywords = ["perplex-numbers", "hyperbolic-geometry", "algebra", "split-complex", "mathematics", "numerics", "scientific-computing"]
keywords = ["perplex-numbers", "hyperbolic-geometry", "algebra", "split-complex", "minkowski", "mathematics", "numerics", "scientific-computing"]
categories = ["algorithms", "science::mathematics", "simulation"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/tomtuamnuq/perplex_num"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# perplex_num
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE-MIT) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE-APACHE) [![minimum rustc 1.76](https://img.shields.io/badge/rustc-1.76+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE-MIT) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE-APACHE) [![minimum rustc 1.76](https://img.shields.io/badge/rustc-1.76+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)[![codecov](https://codecov.io/gh/tomtuamnuq/perplex_num/graph/badge.svg?token=EGEEP9PBHX)](https://codecov.io/gh/tomtuamnuq/perplex_num)

## Overview
`perplex_num` is a Rust crate that provides an implementation of perplex numbers, based on the numerical abstractions of the [num_traits](https://docs.rs/num-traits) crate. This library supports various mathematical functions such as `pow`, `sqrt`, `exp`, `ln`, `sinh`, `sin`, `cosh`, and `tan`. Additionally, the crate offers a hyperbolic polar form for representing and manipulating numbers in the hyperbolic plane, as well as a matrix form representation feature based on [nalgebra](https://docs.rs/nalgebra).
Expand Down Expand Up @@ -64,7 +64,7 @@ fn main() {

## Coverage

Test coverage report is generated with [cargo tarpaulin](https://github.com/xd009642/tarpaulin) invoke it with:
Test coverage report is generated with [cargo tarpaulin](https://github.com/xd009642/tarpaulin). Invoke it with:
```sh
cargo tarpaulin --verbose --all-targets --skip-clean --exclude-files "examples/*.rs" "benches/*.rs"
```
Expand Down
204 changes: 197 additions & 7 deletions src/binary_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
//!
//! This module is dedicated to implementing traits from both the standard library and the `num_traits` crate for the `Perplex` struct. It provides the foundational binary operations necessary for working with two perplex numbers. See `Properties of the Perplex Numbers` in [Fundamental Theorems of Algebra for the Perplexes](https://doi.org/10.4169/074683409X475643)
//!
//! ## Traits from `std::ops`
//! The module includes implementations for basic arithmetic operations between `Perplex` structs, such as:
//! - `Add`: Trait for the addition operator.
//! - `Sub`: Trait for the subtraction operator.
//! - `Mul`: Trait for the multiplication operator.
//! - `Div`: Trait for the division operator.
//! - Tertiary operation `MulAdd` from the `num_traits` crate.
//!
//! Additionally, it supports assignment variants of these operations for mutable references of `Perplex` structs, which are:
//! - `AddAssign`: Trait for addition assignment.
//! - `SubAssign`: Trait for subtraction assignment.
//! - `MulAssign`: Trait for multiplication assignment.
//! - `DivAssign`: Trait for division assignment.
//! - Tertiary operation `MulAddAssign` from the `num_traits` crate.
//!
//! ## Support for Floating-Point Types
//! The module also includes implementations for interactions between `Perplex` structs and the generic floating point type (`f32` or `f64`).

use super::Perplex;
use num_traits::{Num, NumAssign};
use num_traits::{MulAdd, MulAddAssign, Num, NumAssign};
use std::ops::{Add, Div, Mul, Sub};
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};

Expand Down Expand Up @@ -74,6 +74,7 @@ impl<T: Copy + NumAssign> MulAssign for Perplex<T> {

impl<T: Copy + Num> Div for Perplex<T> {
type Output = Option<Self>;
/// Divides `self` by `rhs`. Division by a light-like number yields `None`, otherwise `Some(self / rhs)`.
#[inline]
fn div(self, rhs: Self) -> Self::Output {
let Self { t: t2, x: x2 } = rhs;
Expand All @@ -90,13 +91,10 @@ impl<T: Copy + Num> Div for Perplex<T> {
}
}
impl<T: Copy + NumAssign> DivAssign for Perplex<T> {
/// Divides `self` by `rhs` in place. Division by a light-like number yields a Perplex number with NaN components.
fn div_assign(&mut self, rhs: Self) {
let Self { t: t2, x: x2 } = rhs;
let norm_squared_2 = t2 * t2 - x2 * x2;
if norm_squared_2 == T::zero() {
// light-like
return;
}
let t = self.t;
self.t *= t2;
self.t -= self.x * x2;
Expand Down Expand Up @@ -163,3 +161,195 @@ impl<T: Copy + NumAssign> DivAssign<T> for Perplex<T> {
self.x /= rhs;
}
}

// tertiary ops between three Perplex
impl<T: Copy + Num + MulAdd<Output = T>> MulAdd<Perplex<T>> for Perplex<T> {
type Output = Perplex<T>;
#[inline]
fn mul_add(self, other: Perplex<T>, add: Perplex<T>) -> Self {
let t = self.t * other.t + self.x * other.x + add.t;
let x = other.t * self.x + self.t * other.x + add.x;
Self::new(t, x)
}
}
impl<T: Copy + NumAssign + MulAddAssign> MulAddAssign for Perplex<T> {
fn mul_add_assign(&mut self, other: Self, add: Self) {
let t = self.t;
self.t *= other.t;
self.t += self.x * other.x + add.t;
self.x *= other.t;
self.x += t * other.x + add.x;
}
}

#[cfg(test)]
mod tests {
use super::*;
use num_traits::*;
#[test]
fn test_add() {
let z1 = Perplex::new(1.0, 2.0);
let one = Perplex::one();
let zero = Perplex::zero();
assert_eq!(
z1 + one + zero,
Perplex::new(2.0, 2.0),
"Componentwise addition!"
);
assert_eq!(
z1 + z1.conj(),
Perplex::new(2.0, 0.0),
"Addition of conjugate zeros the hyperbolic part!"
);
let mut z2 = Perplex::new(-3.0, 2.0);
let z12 = z1 + z2;
z2 += z1;
assert_eq!(z12, z2, "AddAssign yields same result as Add!");
}
#[test]
fn test_sub() {
let z1 = Perplex::new(1.0, 2.0);
let one = Perplex::one();
let zero = Perplex::zero();
assert_eq!(
z1 - one - zero,
Perplex::new(0.0, 2.0),
"Componentwise subtraction!"
);
assert_eq!(
z1 - z1.conj(),
Perplex::new(0.0, 4.0),
"Subtraction of conjugate doubles the hyperbolic part!"
);
let mut z2 = Perplex::new(-3.0, 2.0);
let z12 = z2 - z1;
z2 -= z1;
assert_eq!(z12, z2, "SubAssign yields same result as Sub!");
}
#[test]
fn test_mul() {
let z1 = Perplex::new(1.0, 2.0);
let one = Perplex::one();
let zero = Perplex::zero();
assert_eq!(
z1 * one,
z1,
"Neutral element of multiplication yields same element!"
);
assert_eq!(z1 * zero, zero, "Neutral element of addition yields zero!");
let mut z2 = Perplex::new(-1.0, 2.0);
let z12 = z1 * z2;
z2 *= z1;
assert_eq!(z2, Perplex::new(3.0, 0.0), "Multiplication formula!");
assert_eq!(z12, z2, "MulAssign yields same result as Mul!");
}
#[test]
fn test_div() {
let z1 = Perplex::new(1.0, 2.0);
let one = Perplex::one();
let zero = Perplex::zero();
assert_eq!(
(z1 / one).unwrap(),
z1,
"Division of neutral element of multiplication yields same element!"
);
assert!(
(z1 / zero).is_none(),
"Division of neutral element of addition yields none!"
);
let z2 = Perplex::new(-1.0, 2.0);
let mut z12 = z1 * z2;
let div_result = z12 / z2;
assert!(
div_result.is_some(),
"Division of product by multiplier is valid!"
);
assert_eq!(
div_result.unwrap(),
z1,
"Division of product by multiplier gives multiplicand."
);
z12 /= z2;
assert_eq!(z12, z1, "DivAssign yields same result as Div!");

let z2 = Perplex::new(-1.0, 1.0);
let mut z12 = z1 * z2;
assert_eq!(z12, Perplex::new(1.0, -1.0), "Multiplication formula!");
assert!(z2.is_light_like(), "-1 + j is light-like!");
assert!(
(z12 / z2).is_none(),
"Division is not defined for light-like numbers!"
);
z12 /= z2;
assert!(
z12.t.is_nan() && z12.x.is_nan(),
"DivAssign for light-like number yields NaN!"
);
}
#[test]
fn test_scalar() {
let z1 = Perplex::new(1.0, 2.0);
assert_eq!(
z1 + 2.0,
Perplex::new(3.0, 2.0),
"Addition of scalar only on time component!"
);
assert_eq!(
z1 - 2.0,
Perplex::new(-1.0, 2.0),
"Subtraction of scalar only on time component!"
);
assert_eq!(
z1 * 2.0,
Perplex::new(2.0, 4.0),
"Componentwise scalar multiplication!"
);
assert_eq!(
z1 / 2.0,
Perplex::new(0.5, 1.0),
"Componentwise scalar division!"
);
}
#[test]
fn test_scalar_assign() {
let mut z1 = Perplex::new(1.0, 2.0);
z1 += 2.0;
assert_eq!(
z1,
Perplex::new(3.0, 2.0),
"AddAssign of scalar only on time component!"
);
z1 -= 2.0;
assert_eq!(
z1,
Perplex::new(1.0, 2.0),
"SubAssign of scalar only on time component!"
);
z1 *= 2.0;
assert_eq!(
z1,
Perplex::new(2.0, 4.0),
"MulAssign componentwise scalar multiplication!"
);
z1 /= 2.0;
assert_eq!(
z1,
Perplex::new(1.0, 2.0),
"DivAssign componentwise scalar division!"
);
}
#[test]
fn test_mul_add() {
let mut z1 = Perplex::new(1.0, 2.0);
let z_mul = Perplex::new(-1.0, 2.0);
let z_add = Perplex::new(-2.0, 1.0);
let z = z1.mul_add(z_mul, z_add);
z1.mul_add_assign(z_mul, z_add);
assert_eq!(
z,
Perplex::new(1.0, 1.0),
"Multiplication formula and addition!"
);
assert_eq!(z, z1, "MulAddAssign yields same result as MulAdd!");
}
}
Loading

0 comments on commit b8af3c4

Please sign in to comment.