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

Comparisons in quadratic number field #13213

Closed
videlec opened this issue Jul 8, 2012 · 41 comments
Closed

Comparisons in quadratic number field #13213

videlec opened this issue Jul 8, 2012 · 41 comments

Comments

@videlec
Copy link
Contributor

videlec commented Jul 8, 2012

The order of quadratic field with specified embedding is not induced from the order of RR and CC. More precisely we have

sage: K.<sqrt2> = NumberField(x^2 - 2, 'sqrt2', embedding=1.4142)
sage: sqrt2 < 100
False

sage: K.<s> = NumberField(x^3 - 2, 's', embedding=1.26)
sage: s < 100
False

which is not compatible with the order of RR and

sage: K.<i> = QuadraticField(-1)
sage: i > 1
True
sage: 1 > i
True

which is not compatible (!) with the order of CC.

The ticket implements the order for quadratic field (for which comparisons are made using only operations on integers).

Note:

  • this patch is partly a duplicate because of comparison with quadratic number field elements #7160
  • the modifications for quadratic field field modify the behavior of many commands (especially about output order).
  • the patch introduces a new attribute to NumberFieldElement_quadratic called standard_embedding (of type bint)

There is no significant lost of speed as shown on the following timings.

sage: K.<sqrt2> = QuadraticField(2, 'sqrt2', embedding=1.4142)
sage: a = (3*sqrt2 + 18)/7
sage: b = (5*sqrt2 + 14)/5
sage: %timeit a < b
1000000 loops, best of 3: 408 ns per loop

sage: K.<s> = QuadraticField(-2)
sage: a = 3*s + 2/4
sage: b = 5/7*s + 1/3
sage: %timeit a < b
1000000 loops, best of 3: 352 ns per loop

Timings without the patch

sage: sage: K.<sqrt2> = QuadraticField(2,'sqrt2',embedding=1.4142)
sage: a = (3*sqrt2 + 18)/7
sage: b = (5*sqrt2 + 14)/5
sage: %timeit a < b
1000000 loops, best of 3: 393 ns per loop

sage: K.<s> = QuadraticField(-2)
sage: a = 3*s+2/4
sage: b = 5/7*s+1/3
sage: %timeit a < b
1000000 loops, best of 3: 344 ns per loop

Apply:

Component: number fields

Keywords: real number field, comparison

Author: Vincent Delecroix

Reviewer: Burcin Erocal, Volker Braun

Merged: sage-5.10.beta4

Issue created by migration from https://trac.sagemath.org/ticket/13213

@videlec videlec added this to the sage-5.10 milestone Jul 8, 2012
@videlec videlec self-assigned this Jul 8, 2012
@a-andre
Copy link

a-andre commented Jul 8, 2012

comment:1

I had a short look at your patch.
Could you use Python 3 compatible syntax to raise errors. E.g.

raise ValueError("absolute value not implemented for complex embeddings")

@a-andre
Copy link

a-andre commented Jul 8, 2012

Changed author from vdelecroix to Vincent Delecroix

@videlec

This comment has been minimized.

@videlec

This comment has been minimized.

@videlec

This comment has been minimized.

@burcin
Copy link

burcin commented Jul 10, 2012

comment:5

Thanks again for the patch. A few comments:

  • reimplementing the comparison of quadratic number field elements is a well defined unit of change itself. I suggest moving floor() and ceil() implementations to a separate patch, even a different ticket.
  • Do you really need to use rich comparisons? Working only with __cmp__ should simplify the case comparisons before the return statements and avoid the new python_object.pxi include.
  • I guess speed could be further improved by using an approximation (with doubles say) first and falling back to the exact computation if the results are too close.
  • left.D is of type Integer. Cython tries to do the right thing for <unsigned int> left.D, but it would be better to use mpz_mul() with left.D.value.
  • mpz_sgn() returns 0 if the argument is 0. You don't seem to cover this case, though I couldn't find any example that returns wrong results.
  • To avoid code duplication, it might be better change the if statement to:
        if mpz_sgn(i)*mpz_sgn(j) == 1:
            # both i and j are positive or negative
            mpz_mul(i, i, i)
            mpz_mul(j, j, j)
            mpz_mul_ui(j, j, <unsigned int> left.D)

            test = mpz_cmp(i, j)
            if mpz_sgn(i) == -1:
                # both i and j are negative
                test *= -1

@burcin
Copy link

burcin commented Jul 10, 2012

Reviewer: Burcin Erocal

@videlec
Copy link
Contributor Author

videlec commented Jul 11, 2012

comment:6
  • reimplementing the comparison of quadratic number field elements is a well defined unit of change itself. I suggest moving floor() and ceil() implementations to a separate patch, even a different ticket.
  • left.D is of type Integer. Cython tries to do the right thing for <unsigned int> left.D, but it would be better to use mpz_mul() with left.D.value.

Done and done.

  • Do you really need to use rich comparisons? Working only with __cmp__ should simplify the case comparisons before the return statements and avoid the new python_object.pxi include.

We loose speed (~1 micro sec) by doing this. I quickly look at the code of comparison for Integer. The comparison is directly implemented inside __richcmp__ and avoid as much as possible the coercion machinery (ie the type of the input is check with the cython function PY_TYPE_CHECK). Do you think we should proceed that way ?

  • I guess speed could be further improved by using an approximation (with doubles say) first and falling back to the exact computation if the results are too close.

What do you mean by too close ? How do I certify that my float comparison is accurate enough ?
Moreover, if we proceed that way we have to perform conversion from mpz_t to float (or double or real_mpfr). A way it may work is to look first if a,b, D and denom have reasonable values (recall that mpz_t have unlimited precision) and if yes, convert it to double and try to compare the arguments.
Last, I'm not sure the gain of speed would be terrific. Comparison requires only 7 integer operations.

  • mpz_sgn() returns 0 if the argument is 0. You don't seem to cover this case, though I couldn't find any example that returns wrong results.

Actually there is no problem since we compute the sign of an expression of the form a^2 + b^2 D where a and b are both integers (and one of them is non null) and D is a square free integer. Hence the sign is never 0.

  • To avoid code duplication, it might be better change the if statement to:
        if mpz_sgn(i)*mpz_sgn(j) == 1:
            # both i and j are positive or negative
            mpz_mul(i, i, i)
            mpz_mul(j, j, j)
            mpz_mul_ui(j, j, <unsigned int> left.D)

            test = mpz_cmp(i, j)
            if mpz_sgn(i) == -1:
                # both i and j are negative
                test *= -1

Sure but that way we call twice mpz_sgn(i)... I may change it if you prefer.

Actually, the part where a lot of time is lost is the check for embedding

if not RDF.has_coerce_map_from(left._parent):
    ...

By replacing it by

if left.D < 0:
   ...

I pass from 4 micro second to 2 micro seconds. That way comparison without embedding for positive discriminant will be equivalent to comparison with the standard embedding. This is in the last version of the patch. What do you think about that ?

@videlec

This comment has been minimized.

@videlec
Copy link
Contributor Author

videlec commented Jul 18, 2012

comment:8

The code for comparison introduces a small bug as it ask to the parent whether the embedding is standard or not (via the boolean attribute _standard_embedding). But the latter was not defined for Cyclotomic field of order 3,4,6 (which are the ones which are quadratic). In that case, the attribute _standard_embedding is created at the initialization of the cyclotomic field.

The new patch takes care of this.

@videlec

This comment has been minimized.

@videlec
Copy link
Contributor Author

videlec commented Aug 4, 2012

comment:10

Because there are many parents for quadratic elements, I was obliged to test whether the parent has a method '_standard_embedding' or not. I correct all tests (many output have changed) and waiting for patchbot and reviewer!

@videlec
Copy link
Contributor Author

videlec commented Aug 8, 2012

comment:12

I corrected the two last tests that have failed...

@jdemeyer
Copy link

jdemeyer commented Aug 8, 2012

comment:13

How does this patch here relate to #7160?

@jdemeyer
Copy link

jdemeyer commented Aug 8, 2012

comment:14

In the ticket title "real number field", should it say "quadratic number field" instead?

@videlec
Copy link
Contributor Author

videlec commented Aug 8, 2012

comment:15

Hi Jeroen,

From the last comment of Burcin on #7160, it seems to me that we will close #7160 as a duplicate. On the other hand, an other patch is coming for comparisons of general number field. Would you prefer to have it on a separate ticket ?

@jdemeyer
Copy link

jdemeyer commented Aug 8, 2012

comment:16

Replying to @videlec:

From the last comment of Burcin on #7160, it seems to me that we will close #7160 as a duplicate. On the other hand, an other patch is coming for comparisons of general number field. Would you prefer to have it on a separate ticket ?

I don't care very much, but I think it should be clear how the various tickets relate to eachother.

Also #10064 is related, at least it has #7160 as dependency.

@videlec

This comment has been minimized.

@tkluck
Copy link

tkluck commented Aug 9, 2012

comment:18

Just had a quick look at your patch. How about using @cached_method as a decorator for _gen_approx? Then you don't have to implement caching yourself. It makes the code a little bit easier to read.

@videlec
Copy link
Contributor Author

videlec commented Aug 13, 2012

comment:19

Hello,

Actually, a lot of time is lost for asking questions to the parent. For quadratic number field, it is for asking about the attribute _standard_embedding. I build a new patch with a bint attribute added to NumberFieldElement_quadratic and the speed of comparison is divided by 10 (from 4 milliseconds to 400 nanoseconds). It will be updated as soon as possible.
As modifying the structure of NumberFieldElement_quadratic is a major change, I will split the patch into two parts : quadratic number fields and general number fields.

Vincent

@videlec
Copy link
Contributor Author

videlec commented May 10, 2013

comment:27

Last minute modification: more tests, more docs.

apply trac_13213-quadratic_field_comparison.patch

@kcrisman
Copy link
Member

comment:28

#7545 is possibly a related ticket.

@videlec
Copy link
Contributor Author

videlec commented May 10, 2013

comment:29

There is a strange problem

sage: K.<sqrt2> = QuadraticField(2)
sage: 1/2 + sqrt2 > 0
False

@videlec
Copy link
Contributor Author

videlec commented May 10, 2013

comment:30

Replying to @videlec:

There is a strange problem

sage: K.<sqrt2> = QuadraticField(2)
sage: 1/2 + sqrt2 > 0
False

I got the problem... it was because there is a natural morphism implemented from the rational field to quadratic number field (sage.rings.number_field.number_field_element_quadratic.Q_to_quadratic_field_element) which uses a non properly initialized instance of a quadratic element !

@videlec
Copy link
Contributor Author

videlec commented May 10, 2013

comment:31

apply trac_13213-quadratic_field_comparison.patch

@vbraun
Copy link
Member

vbraun commented May 14, 2013

comment:32

I get a doctest failure with sage-5.10.beta2:

File "devel/sage/doc/de/tutorial/tour_advanced.rst", line 483, in doc.de.tutorial.tour_advanced
Failed example:
    M.T(2).charpoly('x').factor()
Expected:
    (x - 2*zeta6 - 1) * (x - zeta6 - 2) * (x + zeta6 + 1)^2
Got:
    (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2
**********************************************************************
1 item had failures:
   1 of 136 in doc.de.tutorial.tour_advanced
    [118 tests, 1 failure, 1.44 s]

@videlec
Copy link
Contributor Author

videlec commented May 15, 2013

@videlec
Copy link
Contributor Author

videlec commented May 15, 2013

comment:33

Replying to @vbraun:

I get a doctest failure with sage-5.10.beta2:

File "devel/sage/doc/de/tutorial/tour_advanced.rst", line 483, in doc.de.tutorial.tour_advanced
Failed example:
    M.T(2).charpoly('x').factor()
Expected:
    (x - 2*zeta6 - 1) * (x - zeta6 - 2) * (x + zeta6 + 1)^2
Got:
    (x - zeta6 - 2) * (x - 2*zeta6 - 1) * (x + zeta6 + 1)^2
**********************************************************************
1 item had failures:
   1 of 136 in doc.de.tutorial.tour_advanced
    [118 tests, 1 failure, 1.44 s]

Thanks for that. I got the same error on my computer and change the patch accordingly. Why was patchbot happy with the former patch ?

apply trac_13213-quadratic_field_comparison.patch

@vbraun
Copy link
Member

vbraun commented May 15, 2013

comment:34

The patchbot apparently doesn't check German docs. Enttäuschend! ;-)

@vbraun
Copy link
Member

vbraun commented May 15, 2013

comment:35

All tests pass.

@vbraun
Copy link
Member

vbraun commented May 15, 2013

Changed reviewer from Burcin Erocal to Burcin Erocal, Volker Braun

@kcrisman
Copy link
Member

Changed work issues from rebase 5.10.beta2 to none

@jdemeyer
Copy link

Merged: sage-5.10.beta4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants