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

Optionally borrow polynomial coefficients #237

Merged
merged 2 commits into from
Oct 29, 2024
Merged

Optionally borrow polynomial coefficients #237

merged 2 commits into from
Oct 29, 2024

Conversation

jan-ferdinand
Copy link
Member

@jan-ferdinand jan-ferdinand commented Oct 18, 2024

Refactor polynomials to (a) make their innards private and (b) turn their innards into a clone-on-write slice, reducing the number of allocations needed for read-only operations like polynomial evaluation.

Pros

  • Certain functions, like evaluation, can happen without owning the coefficients, which reduces memory consumption.
  • There are fewer sneaky memory allocations, i.e., it is more obvious in calling code whether allocations are happening. 1

Cons

  • Explicit lifetimes are required more often.
  • Polynomial's implementations of traits Zero and One are less usable now. Should poly.is_zero() be unusable due to lifetime constraints (“poly escapes the method body”), you can use poly.degree() < 0 instead.

A lot of lines have changed only because of re-grouping to avoid multiple impl blocks with the same trait & lifetime bounds. Commit 65914d5 only makes the polynomial's innards private to simplify review.

Performance

The benchmark suite indicates some improvements, some regressions, and I can't seem to identify clear patterns. I will try to make sense of the results and report back in a separate comment.

Footnotes

  1. Methods taking &mut self, like scalar_mul_mut() or normalize(), are unfortunate exceptions if called on a Polynomial::new_borrowed(). I thought about making those methods consuming, and return a Polynomial<'static, FF>, but have decided against that for now. Let me know if you disagree with that decision.

Pros:
- Certain functions, like evaluation, can happen without owning the
  coefficients, which reduces memory consumption.
- Memory allocations are more visible in calling code.

Cons:
- Explicit lifetimes might be required more often.
- Polynomial's implementations of traits `Zero` and `One` are less
  usable now. Should `poly.is_zero()` be unusable due to lifetime
  constraints (“`poly` escapes the method body”), you can use
  `poly.degree() < 0` instead.
Previously, the coefficient list over which a polynomial was defined was
publicly accessible.

Now, the coefficient list is private. A reference to it can be accessed
using the new method `Polynomial::coefficients()`. This change
- makes upholding internal invariants easier, and
- allows changing the underlying representation without breaking
  downstream dependencies.
@jan-ferdinand jan-ferdinand added the ⏭️ breaking change Breaking change, will require an increment of the major version number. E.g: 0.3.0 -> 0.4.0 label Oct 18, 2024
@jan-ferdinand
Copy link
Member Author

@aszepieniec, @Sword-Smith, I have requested both of you for review only because I'm not sure who this is better suited for. 😌

@coveralls
Copy link

Coverage Status

coverage: 97.747% (-0.06%) from 97.81%
when pulling 65914d5 on poly_cow
into 4af2ffa on master.

@Sword-Smith
Copy link
Member

Let me know if/when you need me to run benchmarks.

Copy link
Collaborator

@aszepieniec aszepieniec left a comment

Choose a reason for hiding this comment

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

🐮

@jan-ferdinand
Copy link
Member Author

Performance

  • scaling a base-field polynomial by a base-field scalar is faster by about 9% (in use)
  • constructing a zerofier the “smart” way is slower by about 2% (not in use)
  • constructing a zerofier the “fast” way is faster for some instances, by about 5% (in use)
  • constructing a zerofier the “naive” way is faster for larger instances, by up to 8% for the largest instance (not in use)
  • other performance changes are less than 2%
  • most of those other performance changes are not consistent across instance sizes, making them less relevant in my eyes

In my eyes, this PR is ready to be merged.

@jan-ferdinand jan-ferdinand merged commit 65914d5 into master Oct 29, 2024
5 checks passed
@jan-ferdinand jan-ferdinand deleted the poly_cow branch October 29, 2024 09:25
@jan-ferdinand jan-ferdinand restored the poly_cow branch October 29, 2024 09:25
@jan-ferdinand jan-ferdinand deleted the poly_cow branch October 29, 2024 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⏭️ breaking change Breaking change, will require an increment of the major version number. E.g: 0.3.0 -> 0.4.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants