forall and exists cannot be used as predicate

2 views
Skip to first unread message

Nils Bruin

unread,
Jan 30, 2008, 5:45:52 PM1/30/08
to sage-devel
Presently, because forall and exists return tuples rather than
booleans, their return value is always True, so they cannot be used as
a predicate, which is very unintuitive given their names. Proposed
solution: optional parameter witness (default: False) that determines
return value type.

Ticket (has patch)

http://trac.sagemath.org/sage_trac/attachment/ticket/1987

Mike Hansen

unread,
Jan 30, 2008, 5:49:45 PM1/30/08
to sage-...@googlegroups.com
Hmm... witness is very unintuitive; maybe we can think up a better
name. Also, there are functions in Python which have similar
functionality.

sage: l = [1,2,3]
sage: any([i == 2 for i in l])
True
sage: all([i == 2 for i in l])
False

--Mike

Nils Bruin

unread,
Jan 30, 2008, 6:09:18 PM1/30/08
to sage-devel
On Jan 30, 2:49 pm, "Mike Hansen" <mhan...@gmail.com> wrote:
[...]
> name. Also, there are functions in Python which have similar
> functionality.
>
> sage: l = [1,2,3]
> sage: any([i == 2 for i in l])
> True
> sage: all([i == 2 for i in l])
> False

That's instructive. In that case, forall and exists should probably
have their help extended by a pointer that if a witness is not
required, the user should type:

any(P(s) for s in S)

or

all(P(s) for s in S)

That's actually a nicer syntax anyway and it would be a shame if
people keep hobbling along with forall and exists when there is a much
nicer option. (I got a tab completion hit on "forall" and "exists" and
assumed those were the right functions to use. They are often not).
That teaches me to *not* write patches :-)

John Cremona

unread,
Jan 30, 2008, 10:03:14 PM1/30/08
to sage-...@googlegroups.com
I agree with Nils. I just started using forall and exists and found
it stupid to have to append [0] to get the boolean value. And given
their existence I never looked further to find the python any() and
all() functions.

On 30/01/2008, Nils Bruin <nbr...@sfu.ca> wrote:
>
> On Jan 30, 2:49 pm, "Mike Hansen" <mhan...@gmail.com> wrote:
> [...]
> > name. Also, there are functions in Python which have similar
> > functionality.
> >
> > sage: l = [1,2,3]
> > sage: any([i == 2 for i in l])
> > True
> > sage: all([i == 2 for i in l])
> > False
>
> That's instructive. In that case, forall and exists should probably
> have their help extended by a pointer that if a witness is not
> required, the user should type:
>
> any(P(s) for s in S)
>
> or
>
> all(P(s) for s in S)
>
> That's actually a nicer syntax anyway and it would be a shame if
> people keep hobbling along with forall and exists when there is a much
> nicer option. (I got a tab completion hit on "forall" and "exists" and
> assumed those were the right functions to use. They are often not).
> That teaches me to *not* write patches :-)

On the contrary! But change it to a patch for the docstrong for
exists() and forall().

John


>
> > On Jan 30, 2008 2:45 PM, Nils Bruin <nbr...@sfu.ca> wrote:
> >
> >
> >
> > > Presently, because forall and exists return tuples rather than
> > > booleans, their return value is always True, so they cannot be used as
> > > a predicate, which is very unintuitive given their names. Proposed
> > > solution: optional parameter witness (default: False) that determines
> > > return value type.
> >
> > > Ticket (has patch)
> >
> > >http://trac.sagemath.org/sage_trac/attachment/ticket/1987
> >
>


--
John Cremona

Nils Bruin

unread,
Jan 31, 2008, 9:08:04 PM1/31/08
to sage-devel
OK, I changed the patch on http://trac.sagemath.org/sage_trac/ticket/1987
so that "forall" and "exists" do not change functionality, but have a
pointer to "all" and "any" in their docstrings. Incidentally, it is
*crucial* to *not* use square brackets inside any and all. If you do,
you destroy any possible "short circuit evaluation".

sage: all(a %2 == 0 for a in ZZ) #terminates quickly
False
sage: all([a %2 == 0 for a in ZZ]) #blows up

William Stein

unread,
Jan 31, 2008, 9:50:57 PM1/31/08
to sage-...@googlegroups.com

Any chance you could also post a patch that adds this very important
insight to the documentation?

Also, in your posted patch you emphasize that forall and exists
are *NOT* suitable for use in an if, etc. I would have written that
to use them thus you have to use the ugly forall(...)[0], and it is
much nicer to use all(...) and any(...).

William

William

Nils Bruin

unread,
Feb 1, 2008, 12:52:40 AM2/1/08
to sage-devel
On Jan 31, 6:50 pm, "William Stein" <wst...@gmail.com> wrote:

[...]
> Also, in your posted patch you emphasize that forall and exists
> are *NOT* suitable for use in an if, etc. I would have written that
> to use them thus you have to use the ugly forall(...)[0], and it is
> much nicer to use all(...) and any(...).
[...]

sage: L=[1..10^6]
sage: L[10^6-3]=-1
sage: %timeit any(a<0 for a in L)
10 loops, best of 3: 2.44 s per loop
sage: %timeit exists(L, lambda a: a<0)
10 loops, best of 3: 2.84 s per loop
sage: g=lambda a: a<0
sage: %timeit any(g(a) for a in L)
10 loops, best of 3: 1.14 s per loop

If you don't need the witness, you should not be using "exists". It's
a bit weird the lambda clause actually speeds things up in "any".

William Stein

unread,
Feb 1, 2008, 1:22:48 AM2/1/08
to sage-...@googlegroups.com

It's because here 0 is created a million times (because the preparser
turns this into a<Integer(0)):

sage: any(a<0 for a in L)

and here 0 is created only once:

sage: g=lambda a: a<0

sage: any(g(a) for a in L)

And yes, we do plan to sometime make it so the preparser intelligently factors
out constants, but haven't done this yet.

William

Nils Bruin

unread,
Feb 1, 2008, 1:33:34 AM2/1/08
to sage-devel
I forgot one case. This is weird. Exists seems *faster* than any. That
should never be happening!

sage: L=[1..10^6]
sage: L[10^6-3]=-1
sage: %timeit any(a<0 for a in L)
10 loops, best of 3: 2.47 s per loop
sage: %timeit exists(L, lambda a: a<0)
10 loops, best of 3: 2.83 s per loop
sage: g=lambda a: a<0
sage: %timeit any(g(a) for a in L)
10 loops, best of 3: 1.19 s per loop
sage: %timeit exists(L, g)
10 loops, best of 3: 1.04 s per loop

John Cremona

unread,
Feb 1, 2008, 9:25:47 AM2/1/08
to sage-...@googlegroups.com
any() ans all() certainly deserve to be better known. In the patch I
submitted yesterday including the file
sage/rings/number_field/number_field_ideal.py there's a whole
function, doctest and all, called
def is_pari_zero_vector(z):
which can be replaced entirely by "not all(z)".

John


--
John Cremona

John Cremona

unread,
Feb 1, 2008, 11:04:18 AM2/1/08
to sage-...@googlegroups.com
On 01/02/2008, John Cremona <john.c...@gmail.com> wrote:
> any() ans all() certainly deserve to be better known. In the patch I
> submitted yesterday including the file
> sage/rings/number_field/number_field_ideal.py there's a whole
> function, doctest and all, called
> def is_pari_zero_vector(z):
> which can be replaced entirely by "not all(z)".

I meant: "not any(z)".

> John
>
> On 01/02/2008, Nils Bruin <nbr...@sfu.ca> wrote:
> >
> > I forgot one case. This is weird. Exists seems *faster* than any. That
> > should never be happening!
> >
> > sage: L=[1..10^6]
> > sage: L[10^6-3]=-1
> > sage: %timeit any(a<0 for a in L)
> > 10 loops, best of 3: 2.47 s per loop
> > sage: %timeit exists(L, lambda a: a<0)
> > 10 loops, best of 3: 2.83 s per loop
> > sage: g=lambda a: a<0
> > sage: %timeit any(g(a) for a in L)
> > 10 loops, best of 3: 1.19 s per loop
> > sage: %timeit exists(L, g)
> > 10 loops, best of 3: 1.04 s per loop
> >
> >
> > > >
> >
>
>
> --
> John Cremona
>


--
John Cremona

Nils Bruin

unread,
Feb 1, 2008, 5:02:57 PM2/1/08
to sage-devel
The timing differences between "any" and "exists" still bother me a
bit, so I tried plain sage -ipython:

sage: def exists(S, P):
...: for x in S:
...: if P(x): return True, x
...:
...: return False, None
sage: L=range(10^6)
sage: L[10^6-3]=-1
sage: g=lambda a: a<0
sage: %timeit any(g(a) for a in L)
100000 loops, best of 3: 7.09 µs per loop
sage: %timeit exists(L, g)
100000 loops, best of 3: 4.44 µs per loop
sage: %timeit any(a<0 for a in L)
100000 loops, best of 3: 4.57 µs per loop
sage: %timeit exists(L, lambda a: a<0)
100000 loops, best of 3: 4.86 µs per loop

The differences are crazy. Assigning a lambda expression to an
identifier speeds things up?
Reply all
Reply to author
Forward
0 new messages