Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to intermediate numerical evaluation #32

Open
MasonProtter opened this issue Aug 15, 2018 · 7 comments
Open

Improvements to intermediate numerical evaluation #32

MasonProtter opened this issue Aug 15, 2018 · 7 comments
Labels
improvement Improvement to existing feature

Comments

@MasonProtter
Copy link
Contributor

One can do things like

julia> normalize(@term 10*10)
@term(100)

and have the answer simplified but it seems to not with with non-unity exponents:

julia> normalize(@term 10^2)
@term(10 ^ 2)

julia> normalize(@term 10^1)
@term(10)
@HarrisonGrodin
Copy link
Owner

This is due to us including an EvalRule for multiplication, but not for exponentiation, in an attempt to retain precision where possible. For example, if the user is dealing purely with symbolic algebra, it would likely be best to leave 3 ^ 0.5 as sqrt(3). Alternatively, if the user wants increased numerical precision, we may be hindering the result by immediately evaluating a non-integral power:

julia> 2^0.5 * 2^0.5
2.0000000000000004

julia> 2^(0.5 + 0.5)
2.0

Generally, EvalRule is in need of some serious rearchitecting:

  • It currently isn't possible to include the necessary nuances/conditionals typically associated with intermediate evaluation. For example, we should probably evaluate ("small"?) integral powers.
  • We should probably only use EvalRules as a "last resort", since unnecessary evaluations (which would be cancelled out via symbolic rewrite rules) just cost us time.

It seems like the best first steps to solving this larger issue (fixing this specific instance, at least) would be adding conditionals to EvalRules, probably based on an specified image set. I should be able to take care of that soon, but a PR would be welcomed if you beat me to it.

@MasonProtter
Copy link
Contributor Author

MasonProtter commented Aug 15, 2018

Perhaps there could be an optional argument passed to normalize such that when it's active, if normalize is called on a @term consisting of purely numeric arguments, it evaluates using standard Julia evaluation.

ie.

julia> normalize((@term 2^0.5 * 2^0.5), :EvalNumeric)
2.0000000000000004

@HarrisonGrodin
Copy link
Owner

HarrisonGrodin commented Aug 15, 2018

It seems good to have something in that direction. Since additional arguments to normalize are interpreted as rule sets, though, maybe it could be a keyword argument?

function normalize(ex, rs...; eval::Bool = false)
     # ...
end
# true: always evaluate
# false: only evaluate based on EvalRule

Also, the evaluation procedure should probably used as a "last resort", only executing when all rules have been exhausted. (e.g. if there is a rule (x^0.5 + x^0.5) => x, it would first apply that.)

@MasonProtter
Copy link
Contributor Author

MasonProtter commented Aug 15, 2018

Yeah, that'd be nice. Maybe having one mode where all math is done with BigInt and BigFloat to get arbitrary precision would be advantageous as well. This is what most CAS do by default, so it should at least be an option.

Another thought is that Rewrite could try and symbolically simplify purely numerical expressions before evaluating them. For instance,

normalize(@term 2^0.5 * 2^0.5)
   ->  normalize(@term 2^(0.5 + 0.5))
   ->  normalize(@term 2^(1.0))
   ->  normalize(@term 2)
   ->  @term 2

I believe this is what Mathematica does as it seems to get 2. even to 100 decimal places.

In[1]:= NumberForm[2^0.5 2^0.5, 100]

Out[1]= 2.

@HarrisonGrodin HarrisonGrodin changed the title normalize not normalizing exponents on numbers. Evaluate arbitrary constant calls Aug 15, 2018
@HarrisonGrodin HarrisonGrodin added the feature New feature or request label Aug 15, 2018
@HarrisonGrodin HarrisonGrodin changed the title Evaluate arbitrary constant calls Improvements to intermediate numerical evaluation Aug 15, 2018
@HarrisonGrodin HarrisonGrodin added improvement Improvement to existing feature and removed feature New feature or request labels Aug 15, 2018
@HarrisonGrodin
Copy link
Owner

We should probably prefer Big* when possible, but it still comes with its imprecisions:

julia> big"2"^0.5 * big"2"^0.5
1.999999999999999999999999999999999999999999999999999999999999999999999999999983

I like the preference towards symbolic rewriting (before considering evaluation); it seems like it should necessarily lead to the most precise results, in contrast with the standard evaluative interpretation provided by Julia.

@MasonProtter
Copy link
Contributor Author

The smallest possible length scale in the universe (Planck length) is ~10^-35 meters across whereas the largest known structure in the universe, the Hercules–Corona Borealis Great Wall is 10,000,000,000 ly across or 10^26 meters. Dividing those gives a difference in scale from the largest to smallest lengths in the universe as ~10^61. The above numerical result is correct to one part in 10^77. It's pretty good, but yes, not exact 😛.

Would it be a big overhaul to allow symbolic rewriting of numeric expressions?

@HarrisonGrodin
Copy link
Owner

No, not at all! In fact, it's already supported! 😀

julia> normalize(@term sin(2)^2 + cos(2)^2)
@term(1)

julia> normalize(@term log(2, 2))
@term(1)

Note that those are purely symbolic, since you'd numerically get 1.0 from each. (Not necessarily a good thing that we don't give that exact result, but that's another issue. #19)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement Improvement to existing feature
Projects
None yet
Development

No branches or pull requests

2 participants