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

Quaternion Algebra Fractional Ideal improvements - equivalence and reduced bases #37100

Merged
merged 28 commits into from
Mar 25, 2024

Conversation

jtcc2
Copy link
Contributor

@jtcc2 jtcc2 commented Jan 19, 2024

Includes the following changes

  1. Added .is_definite() to quaternion algebras, which performs a check on the invariants.
  2. Added .reduced_basis() to quaternion fractional ideals which uses LLL to find the basis of shortest elements
  3. Modified quaternion fractional ideal .is_equivalent to include a side parameter which can be set to 'left' or 'right' to do left-ideal or right-ideal equivalence, and a certificate parameter which if true, returns the element a such that I = J*a. Throws a NotImplementedError for indefinite quaternion algebras which fixes Ideal equivalence in indefinite quaternion algebras #37080 . Backwards compatible.
  4. Also added .is_left_equivalent and .is_right_equivalent.
  5. Added .is_principal to quaternion fractional ideals of rank 4 in definite quaternion algebras. Includes certificate parameter for finding generator. Finds the shortest norm element in the lattice and checks its norm.
  6. Fixes isomorphism_to of quaternion_algebra.py does not find an isomorphism of isomorphic maximal orders #37337, bug in quaternion order .isomorphism_to where it cannot find the isomorphism between $\mathcal{O}$ and $\alpha^{-1} \mathcal{O} \alpha$ if $nrd(\alpha)$ is a ramified prime times a square. Fixed this by repeating the previous isomorphism_to method multiple times on inputs $\mathcal{O}$ and $\alpha^{-1} \mathcal{O} \alpha$ with $\alpha = 1, i, j, k$. Throws a NotImplementedError in cases not covered.

@S17A05 @Jonathke

#sd123

@S17A05
Copy link
Member

S17A05 commented Jan 30, 2024

@yyyyx4 Can you have a look at this since you worked on a similar issue in #34976?

Comment on lines 2533 to 2535
if not self.quaternion_algebra().is_definite():
if not self.quadratic_form().is_positive_definite():
raise TypeError("The quaternion algebra must be definite")
Copy link
Member

Choose a reason for hiding this comment

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

Aren't these two tests equivalent? Were they duplicated by accident?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, these two should be equivalent - I believe the latter test was originally put in place for the method to also work for "lattices" of non-maximal rank, until it came up that .gram_matrix() needs a full rank lattice anyway. I'll remove the second test.

"""
# shorthand: let I be self
if not isinstance(self, QuaternionFractionalIdeal_rational):
if not isinstance(J, QuaternionFractionalIdeal_rational):
Copy link
Member

Choose a reason for hiding this comment

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

I'd say in this case we should probably throw a TypeError. Returning False is arguably correct, but I can't see any situation in which users will rely on this behaviour wilfully, hence failing visibly is better.

def is_equivalent(self, J, B=10) -> bool:
"""
Return ``True`` if ``self`` and ``J`` are equivalent as right ideals.
def is_equivalent(self, J, B=10, certificate=False, side=None):
Copy link
Member

Choose a reason for hiding this comment

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

Personally I would simply deprecate this method in favor of the two new explicitly named one-sided methods: Having it default to .is_right_equivalent() is arbitrary and ambiguous.

Copy link
Member

Choose a reason for hiding this comment

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

So should I add a deprecation warning for now to set it up for future removal, or should I remove it immediately?

Copy link
Member

Choose a reason for hiding this comment

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

According to The Rules, we're only allowed to remove things once they've been deprecated for one year, so it has to be the former: Add a deprecation warning. (If you agree, that is: I don't have a strong opinion about this either way.)

Comment on lines 3004 to 3005
raise NotImplementedError('equivalence test of ideals not implemented'
'for indefinite quaternion algebras')
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
raise NotImplementedError('equivalence test of ideals not implemented'
'for indefinite quaternion algebras')
raise NotImplementedError('equivalence test of ideals not implemented'
' for indefinite quaternion algebras')

Comment on lines 3074 to 3069
# Use Pari's qfminim with flag = 1 to find alpha with N(alpha) = N(I)
_,v = self.quadratic_form().__pari__().qfminim(None, None, 1)
return True, sum(ZZ(c)*g for c,g in zip(v, self.basis()))
Copy link
Member

Choose a reason for hiding this comment

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

Same here re: the .minimal_element() method from #34976.

'implemented in indefinite'
'quaternion algebras')

if len(self.basis()) < 4:
Copy link
Member

Choose a reason for hiding this comment

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

Can this fail?

Copy link
Member

Choose a reason for hiding this comment

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

On faulty input, I believe, since calling B.ideal([i,j]) for a quaternion algebra B gives a "fractional ideal", but it really is just a two-dimensional sublattice with basis (i,j).

Copy link
Member

Choose a reason for hiding this comment

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

Interesting, I was expecting the constructor for fractional ideals to check the rank. That should probably be fixed eventually, but it doesn't necessarily have to be done here and now.

Comment on lines 3061 to 3063
raise NotImplementedError('principality test not'
'implemented in indefinite'
'quaternion algebras')
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
raise NotImplementedError('principality test not'
'implemented in indefinite'
'quaternion algebras')
raise NotImplementedError('principality test not'
' implemented in indefinite'
' quaternion algebras')

Comment on lines 3031 to 3033
# Use Pari's qfminim with flag = 1 to find alpha as above
_,v = IJbar.quadratic_form().__pari__().qfminim(None, None, 1)
alpha = sum(ZZ(c)*g for c,g in zip(v, IJbar.basis()))
Copy link
Member

Choose a reason for hiding this comment

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

This one could be alpha = IJbar.minimal_element() once #34976 is merged, but pulling that in as a dependency seems a bit overkill just to deduplicate these two lines. Maybe add a TODO so that eventually someone can replace it later?

Copy link
Member

@S17A05 S17A05 Feb 2, 2024

Choose a reason for hiding this comment

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

Since it might be a good idea to test definiteness with this PR's .is_definite()-method as well, it might actually be a good idea to put a dependency on this PR to yours (see also this review comment).

# As explained by Pizer, we now only need to rescale alpha by 1/N(J)
return True, alpha * (1/J.norm())

def is_principal(self, certificate=False):
Copy link
Member

Choose a reason for hiding this comment

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

This method duplicates quite some code from the equivalence tests. Perhaps the equivalence tests could/should just end up calling .is_principal() on IJbar instead of repeating all the steps on that special case?

@S17A05
Copy link
Member

S17A05 commented Feb 2, 2024

@yyyyx4 Once #34976 is merged I will modify the definiteness check in your code and will integrate your .minimal_element()-method into our code, and then I'll re-request a review; for now I'll just leave this PR labelled as "needs work".

@S17A05 S17A05 force-pushed the develop branch 2 times, most recently from b65ec82 to 554e920 Compare February 3, 2024 00:40
@S17A05
Copy link
Member

S17A05 commented Feb 3, 2024

Since beta 7 of Sage 10.3 was just released, I have instead decided to merge #34976 into this branch. In the progress of figuring this out, however, I caused some chaos in the PR; in particular, GitHub now thinks that a lot of files in .devcontainer have been modified, even though they should be the same files - if someone knows how to fix this please let me know, so that I can repair it.
Otherwise this should be ready for a second review, so I'll update the labels.

@fchapoton
Copy link
Contributor

it was not a good idea to merge with the latest develop. One better way if you really want that is to use github's update branch button that does the merge in the correct direction.

To fix the merge, you could try to rebase your branch on top of develop using git rebase -i develop, but this may trigger conflicts.

@S17A05
Copy link
Member

S17A05 commented Feb 3, 2024

it was not a good idea to merge with the latest develop. One better way if you really want that is to use github's update branch button that does the merge in the correct direction.

To fix the merge, you could try to rebase your branch on top of develop using git rebase -i develop, but this may trigger conflicts.

That's how I did it originally, but then I wrongly assumed that I had to revert it to merge with the other PR's branch, and after that I couldn't do it this way again.

Thanks for the suggestion, I'll try to do that.

@S17A05
Copy link
Member

S17A05 commented Feb 3, 2024

I rebased the branch on upstream/develop, but it still lists the .devcontainer-files under the made changes.

S17A05 and others added 8 commits February 5, 2024 16:01
- Removed greek letter alpha in docstrings in hopes of this fixing infinite build loops
- Updated `.is_definite()` to fit PR sagemath#37173 (up to the reference to Voight's book)
- Other small modifications of docstrings, comments and error warnings
- Slightly cleaned up code with respect to intermediately defined variables
- Added deprecation warning for `.is_equivalent`
- Removed unnecessary call of `.is_positive_definite()` in `.reduced_basis()`
- Reduced `.is_right_equivalent` to `.is_principal` with suitable rescaling
- Fixed some error warnings
- Modified docstrings, moved examples to non-deprecated methods and randomized test of `.is_principal`
- Modified definiteness check in `.minimal_element()` and `.isomorphism_to`; also added check of the base field in the latter method
- Reduced search for a generator in `.is_principal()` to a call to `.minimal_element()`
@yyyyx4
Copy link
Member

yyyyx4 commented Feb 5, 2024

The merge still seems broken. I've attempted to fix it on a new branch by cherry-picking all non-merge commits from here on top of the current develop branch.

You can get my version by adding my fork as a remote and overwriting your version of this branch with mine:

git remote add yyyyx4 https://github.com/yyyyx4/sage.git
git fetch yyyyx4 quatfracidl:this-branch-name -f

After that, you should be able to git push -f the new version of the branch to this pull request as usual.

@S17A05
Copy link
Member

S17A05 commented Feb 5, 2024

The merge still seems broken. I've attempted to fix it on a new branch by cherry-picking all non-merge commits from here on top of the current develop branch.

You can get my version by adding my fork as a remote and overwriting your version of this branch with mine:

git remote add yyyyx4 https://github.com/yyyyx4/sage.git
git fetch yyyyx4 quatfracidl:this-branch-name -f

After that, you should be able to git push -f the new version of the branch to this pull request as usual.

Perfect, that worked - thanks for the help!

S17A05 and others added 2 commits February 14, 2024 11:36
This is not a fix for the issue - it just adapts the error warning to be more ambiguous, as suggested in sagemath#34976 (comment)
Copy link

github-actions bot commented Mar 8, 2024

Documentation preview for this PR (built with commit 8d75358; changes) is ready! 🎉

Copy link
Member

@yyyyx4 yyyyx4 left a comment

Choose a reason for hiding this comment

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

Looks good to me now, thanks!

@vbraun vbraun merged commit 9d73e3c into sagemath:develop Mar 25, 2024
15 of 16 checks passed
@mkoeppe mkoeppe added this to the sage-10.4 milestone Mar 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants