[feat] Implement PolynomialTraits for Polynomial#81
[feat] Implement PolynomialTraits for Polynomial#81shri-acha wants to merge 19 commits intolignum-vitae:mainfrom
Conversation
* 0^x -> 0 when x != 0 * Added additional tests
dawnandrew100
left a comment
There was a problem hiding this comment.
When PolynomialTraits is eventually implemented for the Polynomial struct, I can see that this evaluation function has almost the same signature as the eval_multivariate function, so it can be a drop in function (similar to that of the IntermediatePolynomial struct; func and impl), but for the eval_univariate function, a similar work around will probably need to be added where the struct itself holds all of the unique variables and if the length of the unique variables is greater than 1, then an error is returned.
And for the evaluation function itself, an error should be returned if a variable in the struct is not defined in the variables map parameter of the function.
So to kind of clarify the intent of this issue/PR, the logic used to get the end result can and should be unique to the struct at hand, but the result returned should be the same as PolynomialTraits so that the function can be used in the implementation.
I know that working on parsing, evaluation, derivation, and integration at once can be challenging, so initially, you can do this
impl Polynomial{
fn parse(input: &str) -> Result<Self, PolynomialError> { }
fn eval_univariate<F>(&self, point: F) -> Result<f64, PolynomialError> { }
fn eval_multivariate<V, S, F>(&self, vars: &V) -> Result<f64, PolynomialError> { }
}as you're working through the individual parts
But, in the end, in the structs/advanced.rs file, there should be this
impl PolynomialTraits for Polynomial{
fn parse(input: &str) -> Result<Self, PolynomialError> { }
fn eval_univariate<F>(&self, point: F) -> Result<f64, PolynomialError> { }
fn eval_multivariate<V, S, F>(&self, vars: &V) -> Result<f64, PolynomialError> { }
fn derivate_univariate(&self) -> Result<Self, PolynomialError> { }
fn derivate_multivariate<S>(&self, var: S) -> Self { }
fn indefinite_integral_univariate(&self) -> Result<Self, PolynomialError> { }
fn indefinite_integral_multivariate<S>(&self, var: S) -> Self { }
}That's so that this struct is able to be used in the math portion of this crate without needing to write special work arounds for each of the three available structs.
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| fn eval_advanced_polynomial<V, S, F>(poly: &Polynomial, variables: V) -> Polynomial |
There was a problem hiding this comment.
The eval function should output a value, not a struct
fn eval_univariate<F>(&self, point: F) -> Result<f64, PolynomialError> {}
fn eval_multivariate<V, S, F>(&self, vars: &V) -> Result<f64, PolynomialError> {}|
I do understand what you mean with the variable field in the Polynomial, But I think there is also another way of implementing this, which is by partial application of the variables, and this would be able to trace lack of sufficient variables in case of multivariate or univariate expressions. Each pass iterates through each variable mapping and gives us an expression with substituted value and a final pass checks for above mentioned conditions and gives us a result. Let me know what you think of this idea @dawnandrew100. |
|
@shri-acha It sounds like you want to iterate over the entire parsed expression for each variable to swap it with the relevant value. So, for example, with your second example, you'd iterate over Instead, would it be possible to go through the parsed AST directly and if there's a variable encountered, you can With But, in the |
|
@dawnandrew100, I'm not sure what base for the |
|
@shri-acha Also, I noticed that |
|
yeah, i forgot to get rid of the dependency, I just implemented it by myself. |
dawnandrew100
left a comment
There was a problem hiding this comment.
Everything's looking good so far! In addition to the two minor changes, tests including evaluation of functions and constants should be added to make sure that those work as expected as well.
identify_univariate -> extract_univariate_variable\n removed statrs
…to polynomial_traits
|
@shri-acha And with the rules for integration, how do you best think we should represent the |
I mean, with our current architecture, I believe implementation of product or quotient rule should be straight forward. We can just walk through the AST and replace or just build a new equation with traversal. I'll try to look if I can minimize the creations with just mutating the existing equation. i'm not totally sure about it though.
I think we could just add a constant, called maybe 'C' with an arbitrary value. |
|
@shri-acha Sounds good! #[derive(Debug, PartialEq, Clone)]
pub enum Token {
Number(f64),
Variable(String),
Operator(Operators),
Function(Functions),
Constant(Constants),
LParen,
RParen,
IntegrationConstant, <-
}Then, when the expression is being evaluated, there can be an optional way to define this constant such that it can be included in the calculation OR if it's not defined, it can just be ignored (ie C = 0). |
|
You're right, I'll try looking into something that would work for this scenario, maybe we could add a integration pool while integration and have a state track the integration constant taken out. Which would simplify the process of state tracking for the integration constant. |
|
@shri-acha in an effort to merge this PR without this single PR having to deal with all the nuances of all the functions in You're welcome to also tackle the other issues as well, but I'll merge this PR in the context of it addressing two of those four parts of issue #65. |
| let _ = expr.clone().map(&mut |e| match &e { | ||
| Expr::Variable(v) => { | ||
| variables.insert(v.to_string()); | ||
| Ok(e) | ||
| } | ||
| expr => Ok(expr.clone()), | ||
| }); |
There was a problem hiding this comment.
Instead of cloning the entire expression tree, is there another way to traverse the tree without needing to clone (like using the visitor pattern for example)
| }) | ||
| } else { | ||
| variables | ||
| .clone() |
There was a problem hiding this comment.
Is there a way to remove this clone?
| } | ||
| } | ||
|
|
||
| pub fn extract_univariate_variable(expr: &Expr) -> Result<String, PolynomialError> { |
There was a problem hiding this comment.
We should also probably take a look at the scoping of these various functions. Like this function might be good as pub(crate) instead of just pub, but this can be discussed whether that's a good idea or not
There was a problem hiding this comment.
yeah, I mean, are we expecting on introducing the api seperately? If so, then this would be fine, else I'll have to scope it down for pub (crate).
There was a problem hiding this comment.
What specifically do you mean by introducing the API separately??
| F: Into<f64>, | ||
| { | ||
| let vars_map: HashMap<String, f64> = variables | ||
| .clone() |
There was a problem hiding this comment.
We might be able to replace this clone too if we implement the visitor pattern mentioned in one of my other comments
| expr: &Expr, | ||
| vars: &HashMap<String, f64>, | ||
| ) -> Result<Expr, PolynomialError> { | ||
| expr.clone().map(&mut |e| match e { |
There was a problem hiding this comment.
Another clone that might be removed
|
i'm sorry i have been a little too busy currently because of my academics, i'll try to get back to it when I can. As for the reviews for the current PR, I'll try to work on it soon. |
|
@shri-acha no worries! I've also been busy over the past month so haven't had a ton of time to really do any coding but I'm trying to get back into the swing of things I'll also start working on solving some of the comments so that we can get this PR merged hopefully within the next few days |
Added explicit match arms for eval univariate Changed extended polynomial tests to intermediate polynomial tests
Currently the implementation of
PolynomialTraitsforPolynomialis missing.This PR intends to solve the issue: #65
By implementing the
PolynomialTraitsforPolynomial