Skip to content

Conversation

@vluo13
Copy link
Contributor

@vluo13 vluo13 commented Aug 20, 2025

Fixes #40611

Performance Measurement

Before

sage: sage: v = vector([1,2/3,pi]); w = vector([-2/3,pi^2,1])
sage: %timeit v._add_(w)
953 ns ± 24.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: sage: V = QQ^5
sage: sage: W = V.span([V.1, V.2])
sage: sage: %timeit W.0 - V.0
11.2 μs ± 148 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: R.<x> = QQ[]
sage: M = span([[x, x^2+1], [1/x, x^3]], R)
sage: %timeit x * M.basis()[0]
18.2 μs ± 228 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: %timeit M.basis()[0] * x
18.1 μs ± 280 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: v = vector([x,x^2,3*x]); w = vector([2*x,x,3+x])
sage: %timeit v.pairwise_product(w)
481 ns ± 4.86 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: sage: %timeit w.pairwise_product(v)
476 ns ± 2.45 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

After

sage: v = vector([1,2/3,pi]); w = vector([-2/3,pi^2,1])
sage: %timeit v._add_(w)
942 ns ± 6.55 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: V = QQ^5
sage: W = V.span([V.1, V.2])
sage: %timeit W.0 - V.0
11.2 μs ± 124 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: R.<x> = QQ[]
sage: M = span([[x, x^2+1], [1/x, x^3]], R)
sage: %timeit x * M.basis()[0]
18.4 μs ± 167 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: %timeit M.basis()[0] * x
18.3 μs ± 50.2 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
sage: v = vector([x,x^2,3*x]); w = vector([2*x,x,3+x])
sage: %timeit v.pairwise_product(w)
500 ns ± 3.55 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: %timeit w.pairwise_product(v)
502 ns ± 8.06 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

📝 Checklist

  • The title is concise and informative.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation and checked the documentation preview.

⌛ Dependencies

@vluo13 vluo13 marked this pull request as ready for review August 20, 2025 17:37
@whoami730
Copy link
Contributor

pairwise_product seems to incur a significant slowdown.

Before

sage: v = vector([x,x^2,3*x]); w = vector([2*x,x,3+x])
sage: %timeit v.pairwise_product(w)
481 ns ± 4.86 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: sage: %timeit w.pairwise_product(v)
476 ns ± 2.45 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

After

sage: v = vector([x,x^2,3*x]); w = vector([2*x,x,3+x])
sage: %timeit v.pairwise_product(w)
500 ns ± 3.55 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
sage: %timeit w.pairwise_product(v)
502 ns ± 8.06 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

@user202729
Copy link
Contributor

user202729 commented Aug 21, 2025

pairwise_product seems to incur a significant slowdown.

given that in one of the run the standard deviation of 10⁶ runs is 8ns, and the difference is on the order of 20ns, I'd be tempted to dismiss it as random fluctuation.

This difference is… around 2.5σ, so roughly p=0.012?

@user202729
Copy link
Contributor

do add a doctest.

@whoami730
Copy link
Contributor

pairwise_product seems to incur a significant slowdown.

given that in one of the run the standard deviation of 10⁶ runs is 8ns, and the difference is on the order of 20ns, I'd be tempted to dismiss it as random fluctuation.

This difference is… around 2.5σ, so roughly p=0.012?

It is probably happening in each loop of the run and in each run right? One sure shot method to verify is to take a larger dimension say 100 or 1000 and do performance testing then.

@vluo13
Copy link
Contributor Author

vluo13 commented Aug 21, 2025

I added a doctest that uses the original code that generated the error. Is the location where I put it ok?


sage: R = cartesian_product([ZZ, ZZ])
sage: assert R in CommutativeRings()
sage: matrix(1, 1, [R.zero()]) * vector([R.zero()])
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using lmul or rmul explicitly. We can have both tests - matrix * vector and vector * matrix.

Copy link
Contributor

Choose a reason for hiding this comment

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

by lmul/rmul you likely mean testing multiply the matrix on left/right side. Calling the internal method explicitly is fine, but not possible if the method is cdef only.

Copy link
Contributor

Choose a reason for hiding this comment

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

The method being tested is cpdef _lmul_(self, Element right):, thus I believe both matrix * vector and matrix._lmul_(vector) should be tested, similar to other tests above.

cdef list a = left._entries
cdef list b = (<FreeModuleElement_generic_dense>right)._entries
v = [(<RingElement> a[i])._add_(<RingElement> b[i]) for i in range(left._degree)]
v = [(<Element> a[i])._add_(<Element> b[i]) for i in range(left._degree)]
Copy link
Contributor

Choose a reason for hiding this comment

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

A test for v + v should be added as well, probably similarly other operations can also be tested for.

@user202729
Copy link
Contributor

while adding the tests for other operations (+, etc.) is fine, I think the risk of regression is very low. Now wait for someone to approve workflows.

@whoami730
Copy link
Contributor

@tscrim requesting workflow approval on this PR

@github-actions
Copy link

github-actions bot commented Sep 1, 2025

Documentation preview for this PR (built with commit 1bb74cc; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@vbraun vbraun merged commit 5eacee0 into sagemath:develop Sep 7, 2025
22 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"SystemError: NULL result without error in PyObject_Call" in _matrix_times_vector_ over cartesian_product rings

4 participants