--
You received this message because you are subscribed to the Google Groups "sympy" group.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.
--
A quick scan of the English and German Wikipedia pages on three-valued
logic turned up a whole lot of different logic systems, with different
truth tables. The meaning of the third value could be things like:
- indeterminate/unknown
- irrelevant
- both
- neither
- nonsensical/paradox
Is "none"/"no value" the right terminology for the kind of logic that's
being discussed here?
What's the truth table - does it match an existing three-valued logic?
If yes, I'd take the terminology from there.
Actually, "no value" is pretty close. None means that we don't know
the answer, ether because it could be either True or False, or because
we don't have sufficient algorithms to compute it (we don't
differentiate between the two). So for example, if x is assumed to be
positive, x > 2 would have the logical value of None, because we don't
have enough information to determine if x is in the interval (0, 2] or
(2, oo). On the other hand, something like (pi + E).is_irrational
would be None, because this fact is not known for sure by anyone.
As far as the truth table, the logical operands short-circuit as you
would expect, but otherwise, an operand with None gives None again.
So for example, True & None would be True, but False & None would be
None. Not None would also be None. Note that Python's two valued
logic assigns to None the boolean value of False. This is useful,
because you can check for truth using the two valued logic (e.g., "if
x.is_positive" will be correct for True, False, or None), but you have
to be careful when checking for falsity. In that case, you have to
check something like "if x.is_positive is False" instead of "if not
x.is_positive", or you will get the wrong answer if x.is_positive is
None. Better would be to have something like x.is_nonpositive, which
would do the three-valued logic for you.
But that's off topic. The point is that I think None is actually an OK name.
As far as putting it in S, it turns out I was wrong. You can't do
"S.None = something", because that's a syntax error (I tested it
wrong). You also can't do it with True or False, as that's a syntax
error in Python 3. Furthermore, S.True, S.False, and S.None are all
SyntaxErrors in Python 3, so even __setattr__ wouldn't work (this
could work in Python 2, where that is not a syntax error, but we have
to support both).
The Singleton registry is built to assign the exact name of the class
to the attributes automatically (you just have to add "__metaclass__ =
Singleton" to the top of the class definition). But you can define
any additional attribute, and it seems to work. So you can just do
S.Whatever = BooleanNone
and so on, and it will work (or at least it worked in my tests).
So we need to come up with good shortcut names. Here are some options:
- S.T, S.F, and S.N? Those are easy to type, though they could be a
little confusing.
- S.true, S.false, S.none
- Instead of None, use a name more indicative of what it means, like
"maybe" or "unknown" (this option is independent of the others).
- Don't have any shortcut names. If you want it, you can do
S.BooleanTrue, etc., or just S(True).
I'm slightly leaning toward the last option, though not too strongly.
Aaron Meurer
Also, Boolean logic is two-valued. If you add None, you get a
non-Boolean logic (aka multi-valued logic), so "BooleanNone" is a
contradiction that makes about as much sense as "RealI" or "RationalPi".
>
> Actually, "no value" is pretty close. None means that we don't know
> the answer, ether because it could be either True or False, or because
> we don't have sufficient algorithms to compute it (we don't
> differentiate between the two). So for example, if x is assumed to be
> positive, x > 2 would have the logical value of None, because we don't
> have enough information to determine if x is in the interval (0, 2] or
> (2, oo). On the other hand, something like (pi + E).is_irrational
> would be None, because this fact is not known for sure by anyone.
>
> As far as the truth table, the logical operands short-circuit as you
> would expect, but otherwise, an operand with None gives None again.
> So for example, True & None would be True, but False & None would be
> None. Not None would also be None. Note that Python's two valued
> logic assigns to None the boolean value of False. This is useful,
> because you can check for truth using the two valued logic (e.g., "if
> x.is_positive" will be correct for True, False, or None), but you have
> to be careful when checking for falsity. In that case, you have to
> check something like "if x.is_positive is False" instead of "if not
> x.is_positive", or you will get the wrong answer if x.is_positive is
> None. Better would be to have something like x.is_nonpositive, which
> would do the three-valued logic for you.
You are confusing the problem domain with the implementation domain.
BooleanTrue and BooleanFalse are needed to represent and manipulate
boolean formulas. Their (symbolic) behaviour should be dictated by the
definitions and theorems of mathematics and logic.
What bool(<boolean expr>) and ask(<boolean expr>) return is a separate
issue where Python conventions and implementation details matter. I
think that if bool(Symbol('x') > 2) raises an exception,
bool(BooleanTrue()) should raise the same exception. On the other hand,
ask() handles the conversion of Boolean expression into one of the
Python builtins True, False and None and it's only after it has been
called that we need to deal with that cumbersome 3-valued logic
operating on True, False and None.
>
> But that's off topic. The point is that I think None is actually an OK name.
>
> As far as putting it in S, it turns out I was wrong. You can't do
> "S.None = something", because that's a syntax error (I tested it
> wrong). You also can't do it with True or False, as that's a syntax
> error in Python 3. Furthermore, S.True, S.False, and S.None are all
> SyntaxErrors in Python 3, so even __setattr__ wouldn't work (this
> could work in Python 2, where that is not a syntax error, but we have
> to support both).
>
> The Singleton registry is built to assign the exact name of the class
> to the attributes automatically (you just have to add "__metaclass__ =
> Singleton" to the top of the class definition). But you can define
> any additional attribute, and it seems to work. So you can just do
>
> S.Whatever = BooleanNone
>
> and so on, and it will work (or at least it worked in my tests).
Yes, doing it manually should work without any problem (but be careful
to set the instance, not the class, on the attribute). The Singleton
metaclass effectively runs "S.BooleanTrue = BooleanTrue()".
>
> So we need to come up with good shortcut names. Here are some options:
>
> - S.T, S.F, and S.N? Those are easy to type, though they could be a
> little confusing.
>
> - S.true, S.false, S.none
We could also use S.True_/S.False_ or S.TRUE/S.FALSE.
>
> - Instead of None, use a name more indicative of what it means, like
> "maybe" or "unknown" (this option is independent of the others).
>
> - Don't have any shortcut names. If you want it, you can do
> S.BooleanTrue, etc., or just S(True).
>
> I'm slightly leaning toward the last option, though not too strongly.
Are you suggesting that sympify(True) should return BooleanTrue()? That
seems reasonable to me, but it has interesting side-effects on the
distinction between sympify() and _sympify()
So perhaps the class structure should represent a little better the
disconnect between two-valued and three-valued logic. It seems to me
that perhaps BooleanTrue and BooleanFalse could be considered as part
of both, as the three-valued logic deriving purely from those two is
exactly the same as two-valued logic.
Yes.
How would you quantify the distinction between sympify() and
_sympify()? From what I understand, the disconnect exists so that we
don't necessarily automatically convert strings into SymPy objects in
some places.
The whole point of creating these objects is so that we can have
boolean types in .args (in particular, in Piecewise(evaluate=False); I
suppose things like And(evaluate=False) would also be possible now as
well). So whichever of sympify() or _sympify() is responsible for
sympifying .args would have to do it. I think S(True) is a lot cleaner
than S.true, S.TRUE, and so on.
Aaron Meurer