polynomial_solver/
lib.rs

1//!polynomial is a set of tools to perform various tasks involving polynomials. It was created
2
3
4
5pub struct Monomial{
6        a: f64,
7        n: u64,
8}
9
10impl Monomial{
11    ///Creates a new monomial with the leading coefficient a and degree n
12    pub fn new(a: f64, n:u64) -> Monomial{
13        Monomial{
14            a,
15            n
16        }
17    }
18    ///Returns the coefficient of the monomial
19    pub fn coefficient(&self) -> f64{
20        self.a
21    }
22    ///Returns the degree of the monomial
23    pub fn degree(&self) -> u64{
24        self.n
25    }
26    ///Returns the value of the monomial at the point given
27    pub fn evaluate(&self, arg: f64) -> f64{
28        self.a*arg.powf(self.n as f64)
29    }
30}
31
32impl Monomial{
33    ///Returns the derivative of the monomial
34    pub fn derivative(&self) -> Monomial {
35        Monomial{
36            a: self.a*(self.n as f64),
37            n: match self.n{
38                0 => 0,
39                _ => self.n-1,
40            },
41        }
42    }
43    ///Turns the monomial into its own derivative
44    pub fn make_derivative(&mut self) {
45        self.a *= self.n as f64;
46        self.n = match self.n {
47            0 => 0,
48            _ => self.n-1,
49        }
50    }
51}
52
53pub struct Polynomial{
54    terms: Vec<Monomial>,
55}
56
57impl Polynomial{
58    ///Creates a new polynomial from a vector of monomials
59    pub fn new(terms: Vec<Monomial>) -> Polynomial{
60        Polynomial{
61            terms,
62        }
63    }
64    ///Creates a new polynomial from a vector of (f64, u64) tuples representing monomials 
65    pub fn from(terms: Vec<(f64, u64)>) -> Polynomial{
66        Polynomial::new(terms.iter().map(|x| Monomial::new(x.0,x.1)).collect())
67    }
68    ///Returns the value of the polynomial at a particular point
69    pub fn evaluate(&self, arg: f64) -> f64{
70        self.terms.iter().map(|x| x.evaluate(arg)).sum()
71    }
72}
73impl Polynomial{
74    ///returns the derivative of the polynomial
75    pub fn derivative(&self) -> Polynomial{
76        Polynomial::new(self.terms.iter().map(|x| x.derivative()).collect())
77        
78    }
79
80    ///Uses the Newton-Raphson method to approximate the solution to the polynomial with a certain
81    ///starting guess and a certain number of iterations.
82    pub fn solve(&self, guess: f64, iterations: u64) -> f64{
83        let mut x = guess;
84        let prime = self.derivative();
85        for _i in 0..iterations{
86            x = x - self.evaluate(x)/prime.evaluate(x);
87        }
88        x
89    }
90    
91    ///Uses the Newton-Raphson method until the answer shows no significant change. Can lead to an
92    ///error if the functino has no solution among the reals or the starting guess leads to a
93    ///division by zero somewhere.
94    pub fn solve_accurately(&self, guess: f64) -> Result<f64, &str> {
95        let mut difference = 1.0;
96        let mut x = guess;
97        let mut count = 0;
98        while difference > 1e-10 {
99            if count > 100 {
100                return Err("Iteration count exceeded limit- perhaps no solution exists among the reals?");
101            }
102            let old_x = x;
103            x = self.solve(x,1);
104            difference = (x - old_x).abs();
105            count += 1;
106        }
107        if x.is_nan(){
108            return Err("Answer is NaN- try with a different guess?");
109        }
110        Ok(x)
111    }
112}
113
114impl Monomial{
115    ///Creates a monomial from a string
116    fn parse_monomial(string: String) -> Result<Monomial, String>{
117        let mut error = false;
118        let parts: Vec<f64> = string.split("x^").map(|x| match x.parse::<f64>(){
119            Ok(t) => t,
120            Err(_) => {
121                error = true;
122                0.0
123            }
124        }
125        ).collect();
126        if error {
127            return Err("Could not parse expression".to_string());
128        }
129        Ok(Monomial::new(parts[0], parts[1] as u64))
130    }
131}
132
133impl Polynomial{
134    
135    ///Creates a polynomial from a string representing the polynomial
136    pub fn from_string(argstring: String) -> Result<Polynomial, String> {
137        let mut terms: Vec<String> = Vec::new();
138        let mut count = -1;
139         
140        for i in argstring.chars().enumerate(){
141            if i.1 == '+' || i.1 == '-' || i.0 == 0{
142                terms.push(i.1.to_string());
143                count += 1;
144            }
145            else {
146                terms[count as usize].push(i.1); 
147            }
148        }
149        
150        if !terms[0].starts_with('-'){
151            terms[0].insert(0, '+');
152        }
153
154        for i in terms.iter_mut(){
155            if i.starts_with("+x") || i.starts_with("-x") {
156                i.insert(1, '1');
157            }
158    
159            match i.find("x"){
160                Some(_) => {},
161                None    => i.push_str("x^0"),
162            }
163    
164            match i.find("^"){
165                Some(_) => {},
166                None    => i.push_str("^1"),
167            }
168        }
169
170        let mut monomials = Vec::new();
171        for i in terms{
172            monomials.push(Monomial::parse_monomial(i.to_string())?);
173        }
174        Ok(Polynomial::new(monomials))
175    }
176
177}
178