use crate::algebra::abstr::One;
use crate::algebra::abstr::{Complex, Real};
use crate::elementary::exponential::Exponential;
use crate::elementary::power::Power;
use crate::elementary::trigonometry::Trigonometry;
pub trait Hyperbolic {
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn coth(self) -> Self;
fn sech(self) -> Self;
fn csch(self) -> Self;
fn arsinh(self) -> Self;
fn arcosh(self) -> Self;
fn artanh(self) -> Self;
fn arcoth(self) -> Self;
fn arsech(self) -> Self;
fn arcsch(self) -> Self;
}
macro_rules! hyperbolic_impl {
($t:ty) => {
impl Hyperbolic for $t {
fn sinh(self) -> Self {
self.sinh()
}
fn cosh(self) -> Self {
self.cosh()
}
fn tanh(self) -> Self {
self.tanh()
}
fn coth(self) -> Self {
if self == 0.0 {
panic!();
}
self.cosh() / self.sinh()
}
fn sech(self) -> Self {
1.0 / self.cosh()
}
fn csch(self) -> Self {
if self == 0.0 {
panic!();
}
1.0 / self.sinh()
}
fn arsinh(self) -> Self {
self.asinh()
}
fn arcosh(self) -> Self {
self.acosh()
}
fn artanh(self) -> Self {
if -1.0 >= self || self >= 1.0 {
panic!();
}
self.atanh()
}
fn arcoth(self) -> Self {
if (-1.0..=1.0).contains(&self) {
panic!();
}
((self + 1.0) / (self - 1.0)).ln() / 2.0
}
fn arsech(self) -> Self {
if 0.0 >= self || self > 1.0 {
panic!();
}
(1.0 / self).arcosh()
}
fn arcsch(self) -> Self {
(1.0 / self).arsinh()
}
}
};
}
hyperbolic_impl!(f32);
hyperbolic_impl!(f64);
impl<T> Hyperbolic for Complex<T>
where
T: Real,
{
fn sinh(self) -> Self {
Complex::new(T::zero(), -T::one()) * Complex::new(-self.im, self.re).sin()
}
fn cosh(self) -> Self {
Complex::new(-self.im, self.re).cos()
}
fn tanh(self) -> Self {
self.sinh() / self.cosh()
}
fn coth(self) -> Self {
self.cosh() / self.sinh()
}
fn sech(self) -> Self {
Complex::new(-self.im, self.re).sec()
}
fn csch(self) -> Self {
Complex::new(T::zero(), -T::one()) * Complex::new(-self.im, self.re).csc()
}
fn arsinh(self) -> Self {
let p: Complex<T> = Complex::new(T::one() / (T::one() + T::one()), T::zero());
(self + (self * self + Complex::one()).pow(p)).ln()
}
fn arcosh(self) -> Self {
let p: Complex<T> = Complex::new(T::one() / (T::one() + T::one()), T::zero());
(self + (self * self - Complex::one()).pow(p)).ln()
}
fn artanh(self) -> Self {
let f: Complex<T> = Complex::new(T::one() / (T::one() + T::one()), T::zero());
((Complex::one() + self) / (Complex::one() - self)).ln() * f
}
fn arcoth(self) -> Self {
let f: Complex<T> = Complex::new(T::one() / (T::one() + T::one()), T::zero());
((self + Complex::one()) / (self - Complex::one())).ln() * f
}
fn arsech(self) -> Self {
(Complex::one() / self).arcosh()
}
fn arcsch(self) -> Self {
(Complex::one() / self).arsinh()
}
}