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

feat(scripts): polynomial and rational approximations #3620

Merged
merged 37 commits into from
Dec 10, 2022
Merged

Conversation

p0mvn
Copy link
Member

@p0mvn p0mvn commented Dec 5, 2022

Progress towards: #3013

Math Operations Approximations

Context

This is a set of scripts to approximate a mathematical operation using polynomial
and rational approximations.

The main script is in its respective function of main.py. It does the following:

  1. Computes polynomial and rational approximations of a given function (e^x by default),
    returning the coefficients.

  2. Computes (x,y) coordinates for every kind of approximation given the same x coordinates.
    Plots the results for rough comparison.

  3. Plots the results for rough comparison.

  4. Computes the max error for every approximation given the same x coordinates.

  5. Computes and plots max errors for every approximation with a varying number of parameters.

In other words, this script runs various approximation methods, plots their results and deltas
from actual function values. It can be configured to print the maximum error.
The exact behavior is controlled by the global variables at the top of main.py.

The following are the resources used to create this:

In main.py, there is also an exponent_approximation_choice script.

This is a shorter and simpler version of main that isolates the 13-parameter
Chebyshev Rational approximation of e^x. We are planning to use it in production.
Therefore, we need to perform coefficient truncations to 36 decimal points
(the max osmomath supported precision). This truncation is applied
to exponent_approximation_choice but not main.

Configuration

Several parameters can be changed on the needs basis at the
top of main.py.

Some of the parameters include the function we are approximating, the [x_start, x_end] range of
the approximation, and the number of terms to be used. For the full parameter list, see main.py.

Usage

Assuming that you are in the root of the repository and have Sympy installed:

# Create a virtual environment.
python3 -m venv ~/approx-venv

# Start the environment
source ~/approx-venv/bin/activate

# Install dependencies in the virtual environment.
pip install -r scripts/approximations/requirements.txt

# Run the script.
python3 scripts/approximations/main.py

# Run tests
python3 scripts/approximations/rational_test.py

Example Output

Plotting Functions

This script plots the results to sanity check that they look right.

On the screenshot below, "50000 terms Equispaced poly" aims to be the most accurate representation of the function $$e^x$$

Visually, the results are as expected where "Chebyshev Rational" is plotted as the most accurate, followed by "Chebyshev Poly" and, lastly, "Equispaced Poly".

image

Plotting Approximation Errors For Each Approximation

image

Plotting Chosen Approximation Errors

13 parameter Chebyshev Rational errors with coefficient truncations done to match osmomath.BigDec precision of 36:

image

@p0mvn p0mvn requested a review from ValarDragon December 5, 2022 15:16
@p0mvn p0mvn added V:state/compatible/backport State machine compatible PR, should be backported A:backport/v13.x backport patches to v13.x branch labels Dec 5, 2022
@p0mvn p0mvn marked this pull request as ready for review December 5, 2022 15:43
Comment on lines 33 to 41
def solve(x: np.ndarray, coeffs: np.ndarray) -> np.ndarray:
""" Solves the polynomial. Given a list of x coordinates and a list of coefficients, returns a list of
y coordinates, one for each x coordinate. The coefficients must be in ascending order.
"""
o = len(coeffs)
y = 0
for i in range(o):
y += coeffs[i]*x**i
return y
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is too slow, lmk, we can easily speed this up

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine and not noticeable. Out of curiosity - what would be your suggestion to speed this up? Horner's method or some kind of factorization trick?

@p0mvn
Copy link
Member Author

p0mvn commented Dec 6, 2022

The graph for errors is still TBD

@p0mvn
Copy link
Member Author

p0mvn commented Dec 6, 2022

The graph for errors is still TBD

In the latest commit 3cf279e, I added the ability to print the max error for each approximation. The result looks something like this:

Max Error on [0, 1]
10 coordinates equally spaced on the X axis
3 polynomial terms and (3, 3) rational terms used for approximations.


Equispaced Poly: 0.014336181311823015
Chebyshev Poly: 0.009865548570433536
Chebyshev Rational: 7.428807818232741e-06

Please let me know if this is sufficient with regards to benchmarking errors

@p0mvn
Copy link
Member Author

p0mvn commented Dec 6, 2022

Made the suggested change to perform apples to apples comparison by having:

polynomial_num_terms = numerator_terms + denominator_terms

Now, working on better error plots across various combinations of terms to determine the optimal one

p0mvn and others added 2 commits December 9, 2022 18:50
… tests at max spot price (#3676)

* feat(osmomath): BigDec power function with integer exponent, overflow tests at max spot price

* euler's number

* nolint

* more tests

* changelog
Copy link
Member

@ValarDragon ValarDragon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@ValarDragon
Copy link
Member

LGTM, just need an issue to measure truncating the solved coefficients before plotting/computing error. Happy to merge now and track that in an issue

@p0mvn
Copy link
Member Author

p0mvn commented Dec 10, 2022

LGTM, just need an issue to measure truncating the solved coefficients before plotting/computing error. Happy to merge now and track that in an issue

This should already be achieved here:

# Truncate the coefficients to osmomath precision.
coef_numerator = [sp.Float(sp.N(coef, osmomath_precision + 1), osmomath_precision + 1) for coef in coef_numerator]
coef_denominator = [sp.Float(sp.N(coef, osmomath_precision + 1), osmomath_precision + 1) for coef in coef_denominator]

The 3rd plot in the PR description is made from that.

I'm in the process of writing Go code right now. In that PR, I will also hard code the coefficients I'm using in this script and replot the error graph

@p0mvn p0mvn merged commit 5f55d1b into main Dec 10, 2022
@p0mvn p0mvn deleted the roman/improved-pow branch December 10, 2022 20:07
mergify bot pushed a commit that referenced this pull request Dec 10, 2022
* feat(scripts): polynomial and rational approximations

* typos

* md lint

* osmomath things

* rename solve -> evaluate

* terminology corrections for actual function

* correct terminology for rational matrix

* Revert "osmomath things"

This reverts commit 90f137e.

* compute and print max error

* increase num_points_plot

* polynomial_num_terms = numerator_terms + denominator_terms

* add ability to approximate errors

* clean up plot errors

* clean up

* clean up

* clean up

* clean up

* refactores equispaced with higher precision

* fix chebyshev poly

* refactor chebyshev rational

* clean up

* updates

* updates

* updates

* plot errors on range

* isolate exponent approximation choice with expected precision

* add comments in main.py

* README updates

* update readme and requirements

* requirements.txt and gitignore updates

* clean ups and docs

* readme

* update test test_construct_matrix_3_3

* feat(osmomath): BigDec power function with integer exponent, overflow tests at max spot price (#3676)

* feat(osmomath): BigDec power function with integer exponent, overflow tests at max spot price

* euler's number

* nolint

* more tests

* changelog

* feat(osmomath): mutative `PowerIntegerMut` function on `osmomath.BigDec` (#3680)

(cherry picked from commit 5f55d1b)

# Conflicts:
#	.gitignore
#	CHANGELOG.md
p0mvn added a commit that referenced this pull request Dec 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A:backport/v13.x backport patches to v13.x branch V:state/compatible/backport State machine compatible PR, should be backported
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants