On Apr 2, 1:48 am, Daishi <
dai...@gmail.com> wrote:
> Hi Pearu;
>
> Thanks! I noticed two simple things:
>
> 1. Logic(True) != Logic('True')
> (The LHS is a number, while the RHS is a symbol).
> Given how generally sympycore seems to parse
> string arguments it seems like this would be a nice
> property to have.
This is fixed in svn yesterday. The fix was to define
get_predefined_symbols() method for Logic.
> 2. >>> print Logic('True and False').as_tree()
> Verbatim:
> AND[
> SYMBOL[True]
> SYMBOL[False]
> ]
>
> I expected this to simply be Logic(False).
It should work now.
> I originally thought that perhaps this was due to the
> issue in 1., but even if I explicitly do:
>
> >>> print Logic(AND, (Logic(True), Logic(False))).as_tree()
>
> Verbatim:
> AND[
> NUMBER[True]
> NUMBER[False]
> ]
>
> On the other hand, I'm not entirely sure that in general
> logical sentences should be "simplified" unless explicitly
> requested by the user, so perhaps this is the right behavior.
The above is expected behavior.
In general, sympycore supports three ways of creating
symbolic expressions. I'll describe them below using Logic but
the idea applies also to other Algebra classes:
1) Logic(AND, frozenset([x,y])) - returns Logic instance representing
`x and y` without
performing any canonization. Either the canonization is done by the
caller algorithm
or an user needs an uncanonized representation. So,
Logic(AND, frozenset([True,False])) -> `True and False`
This way of creating Logic instances is used by 2)
2) Logic.And(x, y) - returns Logic instance representing `x and y` but
also performs
basic canonization. An important note is that `x` and `y` must be
boolean expressions.
So,
Logic.And(True, False) leads to an exception.
This way of creating Logic instances is used by algorithms and by 3)
3) And(x, y) - returns Logic instances representing `x and y`. It
converts `x` and `y`
to Logic instances and performs basic canonization (by calling
Logic.And).
This is what users should use to create boolean expressions. So,
And(True, False) -> `False`
Note that Logic defines two number-like instances representing the
True and False values.
They are available via Logic.true and Logic.false, and are actually
equal to Logic(NUMBER, True)
and Logic(NUMBER, False), respectively.
> On a slightly separate note, it appears that .subs() currently
> does an implicit 'eval' in addition to substitution, but that
> sometimes this is short-circuited. Hence one observes
> what seems like slightly odd behavior:
>
> >>> print Logic(AND, (Logic(True), Logic(False))).subs([]).as_tree()
>
> Verbatim:
> AND[
> NUMBER[True]
> NUMBER[False]
This is expected because of 1) above.
> ]>>> print Logic(AND, (Logic(True), Logic(False))).subs({'a':1}).as_tree()
>
> Verbatim:
> NUMBER[False]
This is also expected because subs actually uses 2) above.
> Perhaps there should be a distinct .eval() separate from .subs()?
> (Or have I missed it somewhere?)
Yes, I think the descriptions of ways to create Logic instances should
cover this.
> Finally, my goal here to express some basic quantification.
> It seems to add an operator within an Algebra what you do
> is create an interned symbol for the head in utils.py and then
> implement the operation within the Algebra, is that about right?
Yes. I think that the head symbols defined in utils.py cover already
all needed cases that the parser can handle.
To create a new symbolic operator, say, Implies, one should define a
callable object `Implies` that is used as a head. For example,
class Implies(object):
def __new__(cls, x, y):
# perform basic evaluation and return simplified result
return Logic(cls, (x, y))
See also how, say, `sin(x)` is defined. There is a special hook
(defined in sympycore/calculus/function.py) for how to parse
Calculus('sin(x)') correctly.
The same should be implemented also for Logic functions so that
Logic('Implies(x, y)') would work as expected.
Regards,
Pearu