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

Fix Singular polynomial comparison #39018

Merged
merged 16 commits into from
Jan 27, 2025
Merged

Conversation

user202729
Copy link
Contributor

@user202729 user202729 commented Nov 21, 2024

Fixes #35681

Basically, I think this change makes the comparison makes more sense (apart from that, it should speed up the comparison a bit because it only calls cfGreater when cfEqual returns False, and get rid of the cfSub)

After this change, as long as cfGreater defines a total order, you get a total order on the polynomials.
For example now Integers(10)[] has a total order.

For unordered fields however, cfGreater may not define a total order anyway;
but in newer Singular, cfGreater now defines a total order. It's not always consistent with cfGreaterZero though.
Singular/Singular#1253 (comment)

There's a lot of test breakage because now we change which polynomial compares greater than 0, and that is used to determine whether the sign to display is + or - in several places.


More detail:

    TESTS::

        sage: R.<x, y> = ZZ[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2
        True

    ::

        sage: R.<x, y> = GF(7)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x                     # NEW
        False
        sage: x^2+x > x^2-x                     # OLD
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2                        # NEW
        False
        sage: x^2 > -x^2                        # OLD
        True

    ::

        sage: R.<x, y> = Integers(8)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2
        True

    ::

        sage: R.<x, y> = Integers(10)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x
        False
        sage: x^2+x > x^2-x                     # NEW
        False
        sage: x^2+x > x^2-x                     # OLD
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0
        True
        sage: x^2 > -x^2                        # NEW
        False
        sage: x^2 > -x^2                        # OLD
        True

    ::

        sage: R.<x, y> = ZZ[]
        sage: l = [i*x+j*x^2 for i in range(-5, 5) for j in range(-5, 5)]
        sage: l.sort()
        sage: for i in range(len(l)):
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])

    ::

        sage: R.<x, y> = Integers(10)[]
        sage: l = [i*x+j*y for i in range(7) for j in range(7)]
        sage: l.sort()
        sage: for i in range(len(l)):           # NEW
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])
        sage: for i in range(len(l)):           # OLD
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])
        Traceback (most recent call last):
        ...
        AssertionError: (y, 2*y)

The comparison function was added all the way back in 2007 without explanation e22dc86

📝 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

Copy link

github-actions bot commented Nov 21, 2024

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

@kwankyu
Copy link
Collaborator

kwankyu commented Jan 17, 2025

I like this change. Would you resolve the conflicts?

Moreover, I think we should not lose existing elaborate formatting for PEP8, in particular splitting long lines.

@kwankyu
Copy link
Collaborator

kwankyu commented Jan 17, 2025

sage: R.<x, y> = Integers(10)[]
sage: l = [i*x+j*y for i in range(7) for j in range(7)]
sage: l.sort()
sage: for i in range(len(l)):           # NEW
....:     for b in l[:i]:
....:         assert b < l[i], (b, l[i])

How about adding this doctest somewhere?

@user202729 user202729 marked this pull request as draft January 22, 2025 05:56
@user202729
Copy link
Contributor Author

user202729 commented Jan 23, 2025

What I mean is the long lines are inserted there by sage --fixdoctests… Anyway I wrote a quick script to do the reformatting automatically.

"""
Script to reformat diff file to wrap lines automatically

usage:

	git diff develop > /tmp/a.diff
	python [this script] < /tmp/a.diff > /tmp/b.diff
	git apply -R /tmp/a.diff
	git apply /tmp/b.diff
"""

import textwrap
import re
import sys

def reformat_diff(input_diff):
	lines = input_diff.split('\n')
	output_lines = []

	for line in lines:
		if line.startswith('+') and not line.startswith('+++'):
			leading_spaces = re.match(r'^\+(\s*)', line).group(1)
			stripped_line = line[len(leading_spaces) + 1:]
			if not stripped_line:
				output_lines.append(line)
			else:
				wrapped_lines = textwrap.wrap(stripped_line, width=120,
											  initial_indent=f"+{leading_spaces}",
											  subsequent_indent=f"+ {leading_spaces}",	# one added space here
											  break_long_words=False,
											  break_on_hyphens=False,
											  )
				for wrapped_line in wrapped_lines:
					output_lines.append(wrapped_line)
		else:
			output_lines.append(line)

	return '\n'.join(output_lines)

import sys
import subprocess

input_diff = sys.stdin.read()

output_diff = reformat_diff(input_diff)

result = subprocess.run(
    ['recountdiff'],
    input=output_diff,
    text=True,
	encoding='u8',
    capture_output=True
)

print(result.stdout, end='')

if result.stderr:
    print(result.stderr, file=sys.stderr)

This should probably be incorporated into sage-fixdoctests eventually.

The issues should be fixed now, and tests on changed files pass locally.

@user202729 user202729 marked this pull request as ready for review January 23, 2025 04:40
@kwankyu
Copy link
Collaborator

kwankyu commented Jan 23, 2025

Thanks for explanation.

sage-fixdoctests does not touch the (manually formatted) output if the doctest passes. The output line get changed (and the manual formatting is gone) only when the doctest fails to pass. In the latter case, manual formatting should be redone.

I think there is nothing wrong with the procedure. Manual formatting would be rarely needed. The present case is special since by the very nature of the goal many doctests fail and sage-fixdoctest eradicates manual formatting.

We may develop an automatic formatter (for doctest outputs) as you attempted above. But I think it would be very hard to make it perfect. If the automatic formatter is not perfect, then we would need to examine each of the changes it makes anyway. I doubt that developing it is worth while...

@kwankyu
Copy link
Collaborator

kwankyu commented Jan 23, 2025

I prepared a commit in the branch https://github.com/kwankyu/sage/tree/p/recover-formatting that recovers the manual formatting to your branch.

I followed PEP8 that prefers the style like

123
+ 456 
+ 789

and tried to format expressions to make them look like the original.

Could you cherry-pick the last commit of the branch?

@user202729
Copy link
Contributor Author

Sure, thanks for the effort.

@kwankyu
Copy link
Collaborator

kwankyu commented Jan 23, 2025

Thanks. This PR is good to go once all checks pass.

@user202729
Copy link
Contributor Author

sage: R.<x, y> = Integers(10)[]
sage: l = [i*x+j*y for i in range(7) for j in range(7)]
sage: l.sort()
sage: for i in range(len(l)):           # NEW
....:     for b in l[:i]:
....:         assert b < l[i], (b, l[i])

How about adding this doctest somewhere?

I forget to apply this, fixed now.

Also fix a broken test (you probably didn't notice it because you need --long to see the test fail). Originally (without this pull request) that one has long line as well (it's the author intention I suppose, although we can replace that with trailing ..., with the risk of it matching too much)

@kwankyu
Copy link
Collaborator

kwankyu commented Jan 23, 2025

Also fix a broken test (you probably didn't notice it because you need --long to see the test fail). Originally (without this pull request) that one has long line as well (it's the author intention I suppose, although we can replace that with trailing ..., with the risk of it matching too much)

Ah right. Thanks.

Copy link
Collaborator

@kwankyu kwankyu left a comment

Choose a reason for hiding this comment

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

Thanks. LGTM.

vbraun pushed a commit to vbraun/sage that referenced this pull request Jan 25, 2025
    
Fixes sagemath#35681

Basically, I think this change makes the comparison makes more sense
(apart from that, it should speed up the comparison a bit because it
only calls `cfGreater` when `cfEqual` returns `False`, and get rid of
the `cfSub`)

After this change, **as long as `cfGreater` defines a total order, you
get a total order on the polynomials**.
For example now `Integers(10)[]` has a total order.

For unordered fields however, `cfGreater` may not define a total order
anyway;
but in newer Singular, `cfGreater` now defines a total order. It's not
always consistent with `cfGreaterZero` though.
Singular/Singular#1253 (comment)

There's a lot of test breakage because now we change which polynomial
compares greater than `0`, and that is used to determine whether the
sign to display is `+` or `-` in several places.

--------

More detail:

```python
    TESTS::

        sage: R.<x, y> = ZZ[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2
        True

    ::

        sage: R.<x, y> = GF(7)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x                     # NEW
        False
        sage: x^2+x > x^2-x                     # OLD
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2                        # NEW
        False
        sage: x^2 > -x^2                        # OLD
        True

    ::

        sage: R.<x, y> = Integers(8)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x                       # NEW
        True
        sage: x^2 > x^2-x                       # OLD
        False
        sage: x^2+x > x^2-x
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0                          # NEW
        False
        sage: -x^2 > 0                          # OLD
        True
        sage: x^2 > -x^2
        True

    ::

        sage: R.<x, y> = Integers(10)[]
        sage: x^2+x > x^2
        True
        sage: x^2 > x^2-x
        False
        sage: x^2+x > x^2-x                     # NEW
        False
        sage: x^2+x > x^2-x                     # OLD
        True
        sage: x^2 > 0
        True
        sage: -x^2 > 0
        True
        sage: x^2 > -x^2                        # NEW
        False
        sage: x^2 > -x^2                        # OLD
        True

    ::

        sage: R.<x, y> = ZZ[]
        sage: l = [i*x+j*x^2 for i in range(-5, 5) for j in range(-5,
5)]
        sage: l.sort()
        sage: for i in range(len(l)):
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])

    ::

        sage: R.<x, y> = Integers(10)[]
        sage: l = [i*x+j*y for i in range(7) for j in range(7)]
        sage: l.sort()
        sage: for i in range(len(l)):           # NEW
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])
        sage: for i in range(len(l)):           # OLD
        ....:     for b in l[:i]:
        ....:         assert b < l[i], (b, l[i])
        Traceback (most recent call last):
        ...
        AssertionError: (y, 2*y)
```

The comparison function was added all the way back in 2007 without
explanation e22dc86

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

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

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#39018
Reported by: user202729
Reviewer(s): Kwankyu Lee, user202729
@vbraun vbraun merged commit 40c09d8 into sagemath:develop Jan 27, 2025
23 of 25 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.

Multivariate ring of polynomials over real numbers give incorrect comparison against 0?
3 participants