Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/flint/test/test_acb.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,21 @@ def test_acb_contains_methods() -> None:
assert acb(1.1).contains_integer() is False
assert raises(lambda: outer.contains(object()), TypeError) # type: ignore[arg-type]

def test_acb_equal() -> None:
x = acb(arb(2, 0.1), arb(3, 0.2))
y = acb(arb(2, 0.1), arb(3, 0.2))

# reflexivity
assert x.equal(x)
assert y.equal(y)

# symmetry
assert x.equal(y)
assert y.equal(x)

assert not x.equal(acb(arb(2, 0.2), arb(3, 0.3)))
assert not x.equal(acb(arb(3, 0.1), arb(4, 0.2)))
assert not x.equal(acb(arb(3, 0.2), arb(4, 0.3)))

def test_acb_union() -> None:
a = acb(1, 2)
Expand Down
16 changes: 16 additions & 0 deletions src/flint/test/test_arb.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,22 @@ def test_arb_contains() -> None:
assert x.real is x
assert x.imag == arb(0)

def test_arb_equal() -> None:
x = arb(2, 0.1)
y = arb(2, 0.1)

# reflexivity
assert x.equal(x)
assert y.equal(y)

# symmetry
assert x.equal(y)
assert y.equal(x)

assert not x.equal(arb(2, 0.2))
assert not x.equal(arb(3, 0.1))
assert not x.equal(arb(3, 0.2))

def test_arb_comparison() -> None:
x = arb(2)
y = arb(3)
Expand Down
1 change: 1 addition & 0 deletions src/flint/types/acb.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class acb(flint_scalar):
def contains_interior(self, other: iacb, /) -> bool: ...
def overlaps(self, other: iacb, /) -> bool: ...
def contains_integer(self) -> bool: ...
def equal(self, other: iacb, /) -> bool: ...

def mid(self) -> acb: ...
def rad(self) -> arb: ...
Expand Down
4 changes: 4 additions & 0 deletions src/flint/types/acb.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ cdef class acb(flint_scalar):
def contains_integer(self):
return bool(acb_contains_int(self.val))

def equal(self, other):
other = any_as_acb(other)
return bool(acb_equal((<acb>self).val, (<acb>other).val))

def mid(self):
"""
Returns an exact *acb* representing the midpoint of *self*:
Expand Down
1 change: 1 addition & 0 deletions src/flint/types/arb.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class arb(flint_scalar):
def contains_interior(self, other: iarb, /) -> bool: ...
def overlaps(self, other: iarb, /) -> bool: ...
def contains_integer(self) -> bool: ...
def equal(self, other: iarb, /) -> bool: ...

@property
def real(self) -> arb: ...
Expand Down
4 changes: 4 additions & 0 deletions src/flint/types/arb.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ cdef class arb(flint_scalar):
def contains_integer(self):
return bool(arb_contains_int(self.val))

def equal(self, other):
other = any_as_arb(other)
return bool(arb_equal(self.val, (<arb>other).val))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is there a possibility that the conversion to arb is not exact?

I think maybe this should only compare exact arbs aginst other numeric types exactly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

arb_equal should have the same behaviour as arb_contains and arb_overlaps because theyre closely related comparison predictes. if we change one, we should change the other two as well.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't know what you mean.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think maybe this should only compare exact arbs aginst other numeric types exactly.

arb.contains() and arb.overlaps() use any_as_arb() to convert other to an arb. if these two are allowed to do that, then arb.equal() should also be allowed to do that. or if arb.equal() is not allowed to do that, the other two shouldnt be allowed either. i think this is right, because they are all used to compare the ball representation of two arbs, and they also appear closely together in the FLINT docs. so they should all behave the same.

IMHO none of them should use any_as_arb() since it causes implicit type conversion, which isnt good for something as important as equality!

Is there a possibility that the conversion to arb is not exact?

im not familiar enough with any_as_arb() to say


let me know again if im not clear!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is any_as_arb always exact or could it round the input number. I guess we could have an fmpq like 1/3 that cannot be converted to arb without some rounding errorand then we don't know it is contained:

In [1]: from flint import *

In [2]: ctx.prec = 53

In [3]: a = arb(1)/3

In [4]: ctx.prec = 22

In [5]: a.contains(fmpq(1, 3))
Out[5]: False

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think overlaps and equal probably need to special-case some types. There should perhaps be a method that specifically says "other is an arb and is exactly the same as this" as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

can you elaborate a little bit?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There should be a method suitable for use in test code (perhaps there already is) that checks that other is an arb and that it has the exact same representation as self.

Separately I think it should be possible to call e.g. equal or overlaps with something like fmpq it should be able to report the correct answer without any issues due to rounding.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

so if im not mistaken, that means any_as_arb should be changed to raise an error if the arb created is not exact, eliminating any implicit rounding.

if it is so, then it should raise errors based on type, not on value.

in my experience, conversion functions that raise on invalid values will raise runtime errors which are hard to anticipate. its better to raise on types that might potentially be inexact, and be compile-time errors instead. the user would instead convert type manually which is inconvenient but safer and explicit.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No, I think it just means that any_as_arb should not always be used everywhere.


@property
def real(self):
return self
Expand Down