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
80
81
use num_bigint::{BigInt, BigUint};
use num_complex::Complex64;
use num_irrational::QuadraticSurd;
use num_modular::{MontgomeryBigint, MontgomeryInt};
use num_rational::{BigRational, Rational64};
use num_traits::FromPrimitive;
use std::{rc::Rc, ops::Sub, convert::TryInto};

/// A general `suan` object (su-bject) containing all possible numeric types involved in the calculation
pub enum Subject {
    /// Small integer
    Int(i64),
    /// Multi-precision integer
    BInt(Rc<BigInt>),
    /// Small real number
    Real(f64),
    /// Multi-precision real number
    BReal(), // TODO: available if enable rug feature
    /// Rational number
    Rational(Rational64),
    /// Multi-precision Rational number
    BRational(BigRational),
    /// Complex number
    Complex(Complex64),
    /// Multi-precision Complex number
    BComplex(), // TODO: available if enable rug feature
    /// Small integer in modulo ring
    IntMod(MontgomeryInt<u64>),
    /// Multi-precision integer in modulo ring
    BIntMod(), // TODO: MontgomeryBigint<BigUint>
    /// Quadratic number
    Quad(QuadraticSurd<i64>), // TODO: Quadratic64
    /// Multi-precision Quadratic number
    BQuad(QuadraticSurd<BigInt>), // TODO: BigQuadratic
}

impl From<i64> for Subject {
    fn from(v: i64) -> Self {
        Subject::Int(v)
    }
}

impl From<u64> for Subject {
    fn from(v: u64) -> Self {
        match v.try_into() {
            Ok(u) => Subject::Int(u),
            Err(_) => Subject::BInt(Rc::new(BigInt::from_u64(v).unwrap()))
        }
    }
}

impl From<usize> for Subject {
    fn from(v: usize) -> Self {
        match v.try_into() {
            Ok(u) => Subject::Int(u),
            Err(_) => Subject::BInt(Rc::new(BigInt::from_usize(v).unwrap()))
        }
    }
}

impl From<BigInt> for Subject {
    fn from(v: BigInt) -> Self {
        Subject::BInt(Rc::new(v))
    }
}

impl From<BigUint> for Subject {
    fn from(v: BigUint) -> Self {
        Subject::BInt(Rc::new(BigInt::from(v)))
    }
}

// TODO: add method to convert between the variants:
// .int(), .real(), .rational(), .intmod(), .quad(), .complex()
// .int should accept a 'rounding' parameter with default mode as nearest.
// .real and .rational should accept a 'precision' parameter for determine the (least) precision (in bits)
// .real and .rational should also accept a 'digits' parameter for determine the (least) decimal precision
// .intmod shoud accept a 'modulus' parameter to specify the modulus

// TODO: add method .precision() to set precision, .digits() to set decimal precision. If None is given as the argument, then fallback to f64.
// these two methods should also have a rounding mode parameter.