1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Missing operations & comprehensive number structures
//!
//! ## `Real` trait
//!
//! * `Real` is a trait for binding `f64`, `AD`
//! * `Real` requires `PowOps, TrigOps, ExpLogOps` & `std::Ops<Self>` & `std::Ops<f64>`
//!
//!     ```rust
//!     extern crate peroxide;
//!     use peroxide::fuga::*;
//!
//!     fn main() {
//!         let x_f64 = 2f64;
//!         let x_ad1 = AD1(2f64,1f64);
//!         let x_ad2 = AD2(2f64, 1f64, 0f64);
//!
//!         f(x_f64).print();
//!         f(x_ad1).print();
//!         f(x_ad2).print();
//!     }
//!
//!     fn f<T: Real>(x: T) -> T {
//!         return x.powi(2)
//!     }
//!     ```

use crate::structure::ad::AD;
use peroxide_num::{ExpLogOps, PowOps, TrigOps};
use std::ops::{Add, Div, Mul, Neg, Sub};

pub trait Real:
    PowOps
    + TrigOps
    + ExpLogOps
    + Neg
    + PartialOrd
    + Add<Output = Self>
    + Mul<Output = Self>
    + Div<Output = Self>
    + Sub<Output = Self>
    + Add<f64, Output = Self>
    + Mul<f64, Output = Self>
    + Div<f64, Output = Self>
    + Sub<f64, Output = Self>
    + Clone
    + Copy
{
    fn to_f64(&self) -> f64;
    fn from_f64(f: f64) -> Self;
    fn to_ad(&self) -> AD;
}

impl Real for f64 {
    fn to_f64(&self) -> f64 {
        *self
    }

    fn from_f64(f: f64) -> Self {
        f
    }

    fn to_ad(&self) -> AD {
        AD::from(*self)
    }
}

impl Real for AD {
    fn to_f64(&self) -> f64 {
        self.x()
    }

    fn from_f64(f: f64) -> Self {
        AD::from(f)
    }

    fn to_ad(&self) -> AD {
        *self
    }
}