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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//!polynomial is a set of tools to perform various tasks involving polynomials. It was created



pub struct Monomial{
        a: f64,
        n: u64,
}

impl Monomial{
    ///Creates a new monomial with the leading coefficient a and degree n
    pub fn new(a: f64, n:u64) -> Monomial{
        Monomial{
            a,
            n
        }
    }
    ///Returns the coefficient of the monomial
    pub fn coefficient(&self) -> f64{
        self.a
    }
    ///Returns the degree of the monomial
    pub fn degree(&self) -> u64{
        self.n
    }
    ///Returns the value of the monomial at the point given
    pub fn evaluate(&self, arg: f64) -> f64{
        self.a*arg.powf(self.n as f64)
    }
}

impl Monomial{
    ///Returns the derivative of the monomial
    pub fn derivative(&self) -> Monomial {
        Monomial{
            a: self.a*(self.n as f64),
            n: match self.n{
                0 => 0,
                _ => self.n-1,
            },
        }
    }
    ///Turns the monomial into its own derivative
    pub fn make_derivative(&mut self) {
        self.a *= self.n as f64;
        self.n = match self.n {
            0 => 0,
            _ => self.n-1,
        }
    }
}

pub struct Polynomial{
    terms: Vec<Monomial>,
}

impl Polynomial{
    ///Creates a new polynomial from a vector of monomials
    pub fn new(terms: Vec<Monomial>) -> Polynomial{
        Polynomial{
            terms,
        }
    }
    ///Creates a new polynomial from a vector of (f64, u64) tuples representing monomials 
    pub fn from(terms: Vec<(f64, u64)>) -> Polynomial{
        Polynomial::new(terms.iter().map(|x| Monomial::new(x.0,x.1)).collect())
    }
    ///Returns the value of the polynomial at a particular point
    pub fn evaluate(&self, arg: f64) -> f64{
        self.terms.iter().map(|x| x.evaluate(arg)).sum()
    }
}
impl Polynomial{
    ///returns the derivative of the polynomial
    pub fn derivative(&self) -> Polynomial{
        Polynomial::new(self.terms.iter().map(|x| x.derivative()).collect())
        
    }

    ///Uses the Newton-Raphson method to approximate the solution to the polynomial with a certain
    ///starting guess and a certain number of iterations.
    pub fn solve(&self, guess: f64, iterations: u64) -> f64{
        let mut x = guess;
        let prime = self.derivative();
        for _i in 0..iterations{
            x = x - self.evaluate(x)/prime.evaluate(x);
        }
        x
    }
    
    ///Uses the Newton-Raphson method until the answer shows no significant change. Can lead to an
    ///error if the functino has no solution among the reals or the starting guess leads to a
    ///division by zero somewhere.
    pub fn solve_accurately(&self, guess: f64) -> Result<f64, &str> {
        let mut difference = 1.0;
        let mut x = guess;
        let mut count = 0;
        while difference > 1e-10 {
            if count > 100 {
                return Err("Iteration count exceeded limit- perhaps no solution exists among the reals?");
            }
            let old_x = x;
            x = self.solve(x,1);
            difference = (x - old_x).abs();
            count += 1;
        }
        if x.is_nan(){
            return Err("Answer is NaN- try with a different guess?");
        }
        Ok(x)
    }
}

impl Monomial{
    ///Creates a monomial from a string
    fn parse_monomial(string: String) -> Result<Monomial, String>{
        let mut error = false;
        let parts: Vec<f64> = string.split("x^").map(|x| match x.parse::<f64>(){
            Ok(t) => t,
            Err(_) => {
                error = true;
                0.0
            }
        }
        ).collect();
        if error {
            return Err("Could not parse expression".to_string());
        }
        Ok(Monomial::new(parts[0], parts[1] as u64))
    }
}

impl Polynomial{
    
    ///Creates a polynomial from a string representing the polynomial
    pub fn from_string(argstring: String) -> Result<Polynomial, String> {
        let mut terms: Vec<String> = Vec::new();
        let mut count = -1;
         
        for i in argstring.chars().enumerate(){
            if i.1 == '+' || i.1 == '-' || i.0 == 0{
                terms.push(i.1.to_string());
                count += 1;
            }
            else {
                terms[count as usize].push(i.1); 
            }
        }
        
        if !terms[0].starts_with('-'){
            terms[0].insert(0, '+');
        }

        for i in terms.iter_mut(){
            if i.starts_with("+x") || i.starts_with("-x") {
                i.insert(1, '1');
            }
    
            match i.find("x"){
                Some(_) => {},
                None    => i.push_str("x^0"),
            }
    
            match i.find("^"){
                Some(_) => {},
                None    => i.push_str("^1"),
            }
        }

        let mut monomials = Vec::new();
        for i in terms{
            monomials.push(Monomial::parse_monomial(i.to_string())?);
        }
        Ok(Polynomial::new(monomials))
    }

}