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

Make Qp.integer_ring() faster. #35442

Merged
merged 3 commits into from
Apr 13, 2023
Merged

Conversation

tornaria
Copy link
Contributor

@tornaria tornaria commented Apr 5, 2023

📚 Description

The method pAdicGeneric.integer_ring() uses LocalGeneric.change() to
turn a p-adic field into a p-adic ring. The latter calls a factory
function which, by default, checks primality of p.

However, when p came from a Qp this step is not necessary. We avoid it
by adding check=False to the call to LocalGeneric.change() in
pAdicGeneric.integer_ring(). This results in significant time savings
for large primes, e.g. in the current test suite:

Before this commit:

sage: R = Qp(next_prime(10^60))
sage: timeit('R.integer_ring()')
25 loops, best of 3: 22.2 ms per loop
sage: %time TestSuite(R).run()
CPU times: user 14.4 s, sys: 44 µs, total: 14.4 s
Wall time: 14.4 s

After this commit:

sage: R = Qp(next_prime(10^60))
sage: timeit('R.integer_ring()')
625 loops, best of 3: 68 μs per loop
sage: %time TestSuite(R).run()
CPU times: user 714 ms, sys: 239 µs, total: 715 ms
Wall time: 717 ms

Doctest of padic_base_leaves.py goes down from ~33 to ~5 seconds.

Note that the check=False option for the change() method in relaxed type is broken, so this needs #35441. Other than that this is a one-liner.

📝 Checklist

  • The title is concise, informative, and self-explanatory.
  • The description explains in detail what this PR is about.

⌛ Dependencies

@roed314
Copy link
Contributor

roed314 commented Apr 5, 2023

Look good, though there are linting failures which I didn't look at.

@tornaria
Copy link
Contributor Author

tornaria commented Apr 5, 2023

Look good, though there are linting failures which I didn't look at.

AFAICT, the linting failures are not my fault and fixed by #35418 .

The precision for relaxed p-adics has 3 components:

    `(default_prec, halting_prec, secure)`

where the last one `secure` is a boolean defaulting to `False`.

However, the `construction()` method doesn't know about it:
```
sage: K = QpER(5, secure=True)
sage: K.construction(forbid_frac_field=True)
(Completion[5, prec=(20, 40)], Rational Field)
sage: R = ZpER(5, secure=True)
sage: R.construction()
(Completion[5, prec=(20, 40)], Integer Ring)
```

This has two undesired consequences for the `change()` method:

a. The `secure` attribute is not copied:
```
sage: K.is_secure()
True
sage: K.change().is_secure()
False
sage: R.is_secure()
True
sage: R.change().is_secure()
False
```

b. The `check=False` option is broken:
```
sage: K.change(check=False)
...
ValueError: not enough values to unpack (expected 3, got 2)
sage: R.change(check=False)
...
ValueError: not enough values to unpack (expected 3, got 2)
```

Fixing the `construction()` method solves both issues.

After this commit:
```
sage: K = QpER(5, secure=True)
sage: K.construction(forbid_frac_field=True)
(Completion[5, prec=(20, 40, True)], Rational Field)
sage: K.change().is_secure()
True
sage: K.change(check=False)
5-adic Field handled with relaxed arithmetics
sage: K.change(check=False).is_secure()
True

sage: R = ZpER(5, secure=True)
sage: R.construction()
(Completion[5, prec=(20, 40, True)], Integer Ring)
sage: R.change().is_secure()
True
sage: R.change(check=False)
5-adic Ring handled with relaxed arithmetics
sage: R.change(check=False).is_secure()
True
```
The method pAdicGeneric.integer_ring() uses LocalGeneric.change() to
turn a p-adic field into a p-adic ring. The latter calls a factory
function which, by default, checks primality of p.

However, when p came from a Qp this step is not necessary. We avoid it
by adding `check=False` to the call to `LocalGeneric.change()` in
`pAdicGeneric.integer_ring()`. This results in significant time savings
for large primes, e.g. in the current test suite:

Before this commit:
```
sage: R = Qp(next_prime(10^60))
sage: timeit('R.integer_ring()')
25 loops, best of 3: 22.2 ms per loop
sage: %time TestSuite(R).run()
CPU times: user 14.4 s, sys: 44 µs, total: 14.4 s
Wall time: 14.4 s
```

After this commit:
```
sage: R = Qp(next_prime(10^60))
sage: timeit('R.integer_ring()')
625 loops, best of 3: 68 μs per loop
sage: %time TestSuite(R).run()
CPU times: user 714 ms, sys: 239 µs, total: 715 ms
Wall time: 717 ms
```

Doctest of `padic_base_leaves.py` goes down from ~33 to ~5 seconds.
@tornaria
Copy link
Contributor Author

tornaria commented Apr 6, 2023

Rebased to 10.0.beta8

@github-actions
Copy link

github-actions bot commented Apr 7, 2023

Documentation preview for this PR is ready! 🎉
Built with commit: 18d6640

@vbraun vbraun merged commit a0a388c into sagemath:develop Apr 13, 2023
@mkoeppe mkoeppe added this to the sage-10.0 milestone Apr 14, 2023
vbraun pushed a commit that referenced this pull request Apr 23, 2023
    
### 📚 Description

A test is supposed to take < 1s or else be marked # long time.

Here we consider slow tests taking >> 10s. When possible we fix or
change the test to take less time, otherwise we just mark the test as
long time. Occasionally we create a new smaller test and keep the
original one as long.

After this and #35442 the slowest tests are a few taking ~ 10s.
The total time to doctest all goes down from 880 to 806 seconds (using
`-tp 8 --all`).

~~NOTE: there's a minor merge conflict with #35314 which I will resolve
once that PR is merged.~~

### 📝 Checklist

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
    
URL: #35443
Reported by: Gonzalo Tornaría
Reviewer(s): Gonzalo Tornaría, Matthias Köppe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants