Gmail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
New assumption system
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 46 - Collapse all  -  Translate all to Translated (View all originals)   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:04 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: New assumption system
The following are a series of patches that implement the new assumption system, which
consists of:

   - preparatory stuff (patches 1-5)
   - a logic module (much cleaner than the old one)
   - new style-assumptions (very simple objects)
   - query module, which substitutes the .is_* syntax

I tried hard to separate these 3 functionalities as much as possible.

This is more an initial implementation from whom we can star to work rather than a
finished product, so in case you have any objections, we can start discussing.

Thanks for the review,

- Fabian

pd: patch 3 was already approved, just that i did not push it in.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Implement variations in sympy.utilities.iterables" by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:05 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 1/8] Implement variations in sympy.utilities.iterables
From: Fabian Seoane <fab...@fseoane.net>

variations is a routine that calculates all possible variations
of size n (with or without repetition) of a given set.
---
 doc/src/modules.txt                     |    1 +
 doc/src/modules/utilities/index.txt     |   11 ++++++++
 doc/src/modules/utilities/iterables.txt |   39 +++++++++++++++++++++++++++++++
 sympy/utilities/iterables.py            |   36 ++++++++++++++++++++++++++++
 sympy/utilities/tests/test_iterables.py |    6 ++++-
 5 files changed, 92 insertions(+), 1 deletions(-)
 create mode 100644 doc/src/modules/utilities/index.txt
 create mode 100644 doc/src/modules/utilities/iterables.txt

diff --git a/doc/src/modules.txt b/doc/src/modules.txt
index fca4eb6..6c46683 100644
--- a/doc/src/modules.txt
+++ b/doc/src/modules.txt
@@ -31,6 +31,7 @@ access any SymPy module, or use this contens:
    modules/statistics.txt
    modules/concrete.txt
    modules/solvers.txt
+   modules/utilities/index.txt

 Contributions to docs
 ---------------------
diff --git a/doc/src/modules/utilities/index.txt b/doc/src/modules/utilities/index.txt
new file mode 100644
index 0000000..3e1e692
--- /dev/null
+++ b/doc/src/modules/utilities/index.txt
@@ -0,0 +1,11 @@
+Utilities
+=========
+
+This module contains some general purpose utilities that are used across SymPy
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   iterables.txt
\ No newline at end of file
diff --git a/doc/src/modules/utilities/iterables.txt b/doc/src/modules/utilities/iterables.txt
new file mode 100644
index 0000000..023a3bc
--- /dev/null
+++ b/doc/src/modules/utilities/iterables.txt
@@ -0,0 +1,39 @@
+Iterables
+=========
+
+cartes
+------
+
+Returns the cartesian product of two sequences
+
+Examples::
+       >>> from sympy.utilities.iterables import cartes
+       >>> cartes([1,2,3], ['a', 'b', 'c'])
+       [[1, 'a'],
+       [1, 'b'],
+       [1, 'c'],
+       [2, 'a'],
+       [2, 'b'],
+       [2, 'c'],
+       [3, 'a'],
+       [3, 'b'],
+       [3, 'c']]
+
+
+
+variations
+----------
+
+variations(seq, n) Returns all the variations of the list of size n.
+
+Has an optional third argument. Must be a boolean value and makes the method
+return the variations with repetition if set to True, or the variations
+without repetition if set to False.
+
+Examples::
+    >>> from sympy.utilities.iterables import variations
+    >>> variations([1,2,3], 2)
+    [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
+    >>> variations([1,2,3], 2, True)
+    [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
+    
diff --git a/sympy/utilities/iterables.py b/sympy/utilities/iterables.py
index 6179622..24ebcd0 100644
--- a/sympy/utilities/iterables.py
+++ b/sympy/utilities/iterables.py
@@ -173,3 +173,39 @@ def recursion(result, M, k):
         for elem in recursion([item], M[i + 1:], k - 1):
             yield elem

+
+def cartes(seq0, seq1, modus='pair'):
+    """Return the cartesian product of two sequences """
+    if  modus == 'pair':
+        return [[item0, item1] for item0 in seq0 for item1 in seq1]
+    elif modus == 'triple':
+        return [item0 + [item1] for item0 in seq0 for item1 in seq1]
+
+def variations(seq, n, repetition=False):
+    """Returns all the variations of the list of size n.
+
+    variations(seq, n, True) will return all the variations of the list of
+        size n with repetitions
+
+    variations(seq, n, False) will return all the variations of the list of
+        size n without repetitions
+    """
+    def setrep(seq):  # remove sets with duplicates (repetition is relevant)
+        def delrep(seq):  # remove duplicates while maintaining order
+            result = []
+            for item in seq:
+                if item not in result:
+                    result.append(item)
+            return result
+        return [item for item in seq if item == delrep(item)]
+
+    if n == 1:
+        return [[item] for item in seq]
+    result = range(len(seq))
+    cartesmodus = 'pair'
+    for i in range(n-1):
+        result = cartes(result, range(len(seq)), cartesmodus)
+        if not repetition:
+            result = setrep(result)
+        cartesmodus = 'triple'
+    return [[seq[index] for index in indices] for indices in result]
diff --git a/sympy/utilities/tests/test_iterables.py b/sympy/utilities/tests/test_iterables.py
index 1eea497..959c900 100644
--- a/sympy/utilities/tests/test_iterables.py
+++ b/sympy/utilities/tests/test_iterables.py
@@ -1,6 +1,6 @@
 from sympy import symbols
 from sympy.utilities.iterables import postorder_traversal, \
-    preorder_traversal, flatten, subsets
+    preorder_traversal, flatten, subsets, variations

 w,x,y,z= symbols('wxyz')
@@ -31,3 +31,7 @@ def test_subsets():
     assert list(subsets([1, 2, 3], 2)) == [[1, 2], [1,3], [2, 3]]
     assert list(subsets([1, 2, 3], 3)) == [[1, 2, 3]]

+def test_variations():
+    assert variations([1,2,3], 2) == [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
+    assert variations([1,2,3], 2, True) == [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], \
+                        [3,1], [3,2], [3,3]]
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "implement get_class and get_mod_func in sympy.utilities.source" by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:06 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 2/8] implement get_class and get_mod_func in sympy.utilities.source
From: Fabian Seoane <fab...@fseoane.net>

Function get_class returns a class from a given string. It makes use
of get_mod_func

Implemented after a function with same name in django's codebase
---
 sympy/utilities/source.py            |   30 ++++++++++++++++++++++++++++++
 sympy/utilities/tests/test_source.py |    8 ++++++++
 2 files changed, 38 insertions(+), 0 deletions(-)
 create mode 100644 sympy/utilities/tests/test_source.py

diff --git a/sympy/utilities/source.py b/sympy/utilities/source.py
index 56ca7f7..213d3d8 100644
--- a/sympy/utilities/source.py
+++ b/sympy/utilities/source.py
@@ -10,3 +10,33 @@ def source(object):
     """
     print 'In file: %s' % inspect.getsourcefile(object)
     print inspect.getsource(object)
+
+def get_class(lookup_view):
+    """
+    Convert a string version of a class name to the object.
+
+    For example, get_class('sympy.core.Basic') will return
+    class Basic located in module sympy.core
+    """
+    if isinstance(lookup_view, str):
+        # Bail early for non-ASCII strings (they can't be functions).
+        lookup_view = lookup_view.encode('ascii')
+        mod_name, func_name = get_mod_func(lookup_view)
+        if func_name != '':
+            lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
+            if not callable(lookup_view):
+                raise AttributeError("'%s.%s' is not a callable." % (mod_name, func_name))
+    return lookup_view
+
+def get_mod_func(callback):
+    """
+    splits the string path to a class into a string path to the module
+    and the name of the class. For example:
+        >>> get_mod_func('sympy.core.basic.Basic')
+        ('sympy.core.basic', 'Basic')
+    """
+    try:
+        dot = callback.rindex('.')
+    except ValueError:
+        return callback, ''
+    return callback[:dot], callback[dot+1:]
\ No newline at end of file
diff --git a/sympy/utilities/tests/test_source.py b/sympy/utilities/tests/test_source.py
new file mode 100644
index 0000000..0716d46
--- /dev/null
+++ b/sympy/utilities/tests/test_source.py
@@ -0,0 +1,8 @@
+from sympy.utilities.source import get_mod_func, get_class
+
+def test_get_mod_func():
+    assert get_mod_func('sympy.core.basic.Basic') == ('sympy.core.basic', 'Basic')
+
+def test_get_class():
+    _basic = get_class('sympy.core.basic.Basic')
+    assert _basic.__name__ == 'Basic'
\ No newline at end of file
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Allow Function.eval to return non-instances of Basic." by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:07 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 3/8] Allow Function.eval to return non-instances of Basic.
It was specially annoying that you could not return list
or tuples.

I don't know the reason of this behaviour, fortunately
changing it did not break any tests.

I added a test for this
---
 sympy/core/function.py             |   17 ++++++-----------
 sympy/core/tests/test_functions.py |    7 +++++++
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/sympy/core/function.py b/sympy/core/function.py
index aae869d..8331751 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -138,18 +138,13 @@ def __new__(cls, *args, **options):
         # up to here.
         if options.get('evaluate') is False:
             return Basic.__new__(cls, *args, **options)
-        r = cls.eval(*args)
-        if isinstance(r, Basic):
+        evaluated = cls.eval(*args)
+        if evaluated is not None: return evaluated
+        # Just undefined functions have nargs == None
+        if not cls.nargs and hasattr(cls, 'undefined_Function'):
+            r = Basic.__new__(cls, *args, **options)
+            r.nargs = len(args)
             return r
-        elif r is None:
-            # Just undefined functions have nargs == None
-            if not cls.nargs and hasattr(cls, 'undefined_Function'):
-                r = Basic.__new__(cls, *args, **options)
-                r.nargs = len(args)
-                return r
-            pass
-        elif not isinstance(r, tuple):
-            args = (r,)
         return Basic.__new__(cls, *args, **options)

     @property
diff --git a/sympy/core/tests/test_functions.py b/sympy/core/tests/test_functions.py
index 8d7d165..94b08a6 100644
--- a/sympy/core/tests/test_functions.py
+++ b/sympy/core/tests/test_functions.py
@@ -290,3 +290,10 @@ def eq(a,b,eps):
     assert eq(exp(-0.5+1.5*I).evalf(15), Real("0.0429042815937374") + Real("0.605011292285002")*I, 1e-13)
     assert eq(log(pi+sqrt(2)*I).evalf(15), Real("1.23699044022052") + Real("0.422985442737893")*I, 1e-13)
     assert eq(cos(100).evalf(15), Real("0.86231887228768"), 1e-13)
+
+def test_extensibility_eval():
+    class MyFunc(Function):
+        @classmethod
+        def eval(cls, *args):
+            return (0,0,0)
+    assert MyFunc(0) == (0,0,0)
\ No newline at end of file
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Add a second cls argument to flatten." by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:08 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 4/8] Add a second cls argument to flatten.
This permits to flatten with respect to a given class (see docstring).
This will be used in the logic module to denest classes of the same type
(but I believe it will be useful also in other places)
---
 sympy/utilities/iterables.py            |   25 +++++++++++++++++++++----
 sympy/utilities/tests/test_iterables.py |    6 ++++++
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/sympy/utilities/iterables.py b/sympy/utilities/iterables.py
index 24ebcd0..8d96b04 100644
--- a/sympy/utilities/iterables.py
+++ b/sympy/utilities/iterables.py
@@ -65,7 +65,7 @@ def make_list(expr, kind):
         return [expr]

-def flatten(iterable):
+def flatten(iterable, cls=None):
     """Recursively denest iterable containers.

        >>> flatten([1, 2, 3])
@@ -77,13 +77,30 @@ def flatten(iterable):
        >>> flatten( (1,2, (1, None)) )
        [1, 2, 1, None]

+       If cls argument is specif, it will only flatten instances of that
+       class, for example:
+
+       >>> from sympy.core import Basic
+       >>> class MyOp(Basic):
+       ...     pass
+       ...
+       >>> flatten([MyOp(1, MyOp(2, 3))], cls=MyOp)
+       [1, 2, 3]
+
+
+
     adapted from http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks
     """
-
+    if cls is None:
+        reducible = lambda x: hasattr(x, "__iter__") and not isinstance(x, basestring)
+    else:
+        reducible = lambda x: isinstance(x, cls)
     result = []
     for el in iterable:
-        if hasattr(el, "__iter__") and not isinstance(el, basestring):
-            result.extend(flatten(el))
+        if reducible(el):
+            if hasattr(el, 'args'):
+                el = el.args
+            result.extend(flatten(el, cls=cls))
         else:
             result.append(el)
     return result
diff --git a/sympy/utilities/tests/test_iterables.py b/sympy/utilities/tests/test_iterables.py
index 959c900..3aaf3be 100644
--- a/sympy/utilities/tests/test_iterables.py
+++ b/sympy/utilities/tests/test_iterables.py
@@ -25,6 +25,12 @@ def test_flatten():
     assert flatten( (1,(1,)) ) == [1,1]
     assert flatten( (x,(x,)) ) == [x,x]

+    from sympy.core.basic import Basic
+    class MyOp(Basic):
+        pass
+    assert flatten( [MyOp(x, y), z]) == [MyOp(x, y), z]
+    assert flatten( [MyOp(x, y), z], cls=MyOp) == [x, y, z]
+

 def test_subsets():
     assert list(subsets([1, 2, 3], 1)) == [[1], [2], [3]]
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Add support for bool types in sympify." by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:09 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 5/8] Add support for bool types in sympify.
Before of this, sympy would convert True --> S.One, False --> S.Zero,
but with the logic module with classes inheriting from basic, I need
to manipulate boolean expressions, so converting booleans to S.One
and S.Zero is in my oppinion wrong because of conceptual reasons
and efficiency.

The only module that used this behaviour was functions.elementary.piecewise,
and was adopted to use the new one.
---
 sympy/core/sympify.py                   |    4 ++--
 sympy/functions/elementary/piecewise.py |   18 +++++++++++-------
 sympy/printing/ccode.py                 |    2 +-
 sympy/printing/latex.py                 |    2 +-
 sympy/printing/pretty/pretty.py         |    2 +-
 sympy/utilities/decorator.py            |    3 ++-
 6 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/sympy/core/sympify.py b/sympy/core/sympify.py
index 8da69d2..b00961b 100644
--- a/sympy/core/sympify.py
+++ b/sympy/core/sympify.py
@@ -57,6 +57,8 @@ def sympify(a, locals=None, convert_xor=True):
         return a
     if isinstance(a, BasicType):
         return a
+    elif isinstance(a, bool):
+        return a
     elif isinstance(a, (int, long)):
         return Integer(a)
     elif isinstance(a, (float, decimal.Decimal)):
@@ -68,8 +70,6 @@ def sympify(a, locals=None, convert_xor=True):
         if ireal + iimag*1j == a:
             return ireal + iimag*S.ImaginaryUnit
         return real + S.ImaginaryUnit * imag
-    elif isinstance(a, bool):
-        raise NotImplementedError("bool support")
     elif isinstance(a, (list,tuple,set)):
         return type(a)([sympify(x) for x in a])

diff --git a/sympy/functions/elementary/piecewise.py b/sympy/functions/elementary/piecewise.py
index d5afef7..3abbb1f 100644
--- a/sympy/functions/elementary/piecewise.py
+++ b/sympy/functions/elementary/piecewise.py
@@ -147,7 +147,7 @@ def _eval_interval(self, sym, a, b):
         #    -  eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3]
         # 3) Sort the intervals to make it easier to find correct exprs
         for expr, cond in self.args:
-            if cond.is_Number:
+            if isinstance(cond, bool) or cond.is_Number:
                 if cond:
                     default = expr
                     break
@@ -203,15 +203,19 @@ def _eval_derivative(self, s):
     def _eval_subs(self, old, new):
         if self == old:
             return new
-        return Piecewise(*[(e._eval_subs(old, new), c._eval_subs(old, new)) \
-                                for e, c in self.args])
+        new_args = []
+        for e, c in self.args:
+            if isinstance(c, bool):
+                new_args.append((e._eval_subs(old, new), c))
+            else:
+                new_args.append((e._eval_subs(old, new), c._eval_subs(old, new)))
+        return Piecewise( *new_args )

     @classmethod
     def __eval_cond(cls, cond):
         """Returns S.One if True, S.Zero if False, or None if undecidable."""
-        if type(cond) == bool or cond.is_number:
-            return sympify(bool(cond))
-        if cond.args[0].is_Number and cond.args[1].is_Number:
-            return sympify(bool(cond))
+        if type(cond) == bool or cond.is_number or (cond.args[0].is_Number and cond.args[1].is_Number):
+            if cond: return S.One
+            return S.Zero
         return None

diff --git a/sympy/printing/ccode.py b/sympy/printing/ccode.py
index a1341b5..7a6ccf6 100644
--- a/sympy/printing/ccode.py
+++ b/sympy/printing/ccode.py
@@ -38,7 +38,7 @@ def _print_Piecewise(self, expr):
         ecpairs = ["(%s) {\n%s\n}\n" % (self._print(c), self._print(e)) \
                        for e, c in expr.args[:-1]]
         last_line = ""
-        if expr.args[-1].cond is S.One:
+        if expr.args[-1].cond == True:
             last_line = "else {\n%s\n}" % self._print(expr.args[-1].expr)
         else:
             ecpairs.append("(%s) {\n%s\n" % \
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index 6f2b089..02cdd00 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -521,7 +521,7 @@ def _print_Relational(self, expr):
     def _print_Piecewise(self, expr):
         ecpairs = [r"%s & for %s" % (self._print(e), self._print(c)) \
                        for e, c in expr.args[:-1]]
-        if expr.args[-1].cond is S.One:
+        if expr.args[-1].cond == True:
             ecpairs.append(r"%s & \textrm{otherwise}" % \
                                self._print(expr.args[-1].expr))
         else:
diff --git a/sympy/printing/pretty/pretty.py b/sympy/printing/pretty/pretty.py
index 5065d6c..19ffff2 100644
--- a/sympy/printing/pretty/pretty.py
+++ b/sympy/printing/pretty/pretty.py
@@ -318,7 +318,7 @@ def _print_Piecewise(self, pexpr):
         P = {}
         for n, ec in enumerate(pexpr.args):
             P[n,0] = self._print(ec.expr)
-            if ec.cond is S.One:
+            if ec.cond == True:
                 P[n,1] = prettyForm('otherwise')
             else:
                 P[n,1] = prettyForm(*prettyForm('for ').right(self._print(ec.cond)))
diff --git a/sympy/utilities/decorator.py b/sympy/utilities/decorator.py
index 1d022d6..489f781 100644
--- a/sympy/utilities/decorator.py
+++ b/sympy/utilities/decorator.py
@@ -39,6 +39,8 @@ def threaded_proxy(func):
         def threaded_decorator(expr, *args, **kwargs):
             if isinstance(expr, Matrix):
                 return expr.applyfunc(lambda f: func(f, *args, **kwargs))
+            elif isinstance(expr, bool):
+                    return expr
             elif hasattr(expr, '__iter__'):
                 return expr.__class__([ func(f, *args, **kwargs) for f in expr ])
             else:
@@ -47,7 +49,6 @@ def threaded_decorator(expr, *args, **kwargs):
                 if isinstance(expr, Relational):
                     lhs = func(expr.lhs, *args, **kwargs)
                     rhs = func(expr.rhs, *args, **kwargs)
-
                     return Relational(lhs, rhs, expr.rel_op)
                 elif expr.is_Add and use_add:
                     return Add(*[ func(f, *args, **kwargs) for f in expr.args ])
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "New-style assumptions" by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:10 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 6/8] New-style assumptions
For now these are very lightweight objects, bascally just containers
storing an expression, a key (string) and a value (boolean).

This will be used extensively by the query module
---
 sympy/__init__.py                             |    1 +
 sympy/assumptions/__init__.py                 |    1 +
 sympy/assumptions/assumptions.py              |   41 +++++++++++++++++++++++++
 sympy/assumptions/known_facts.py              |   21 +++++++++++++
 sympy/assumptions/tests/test_assumptions_2.py |   23 ++++++++++++++
 5 files changed, 87 insertions(+), 0 deletions(-)
 create mode 100644 sympy/assumptions/__init__.py
 create mode 100644 sympy/assumptions/assumptions.py
 create mode 100644 sympy/assumptions/known_facts.py
 create mode 100644 sympy/assumptions/tests/test_assumptions_2.py

diff --git a/sympy/__init__.py b/sympy/__init__.py
index f4c7d3a..d5b33fc 100644
--- a/sympy/__init__.py
+++ b/sympy/__init__.py
@@ -22,6 +22,7 @@ def __sympy_debug():
 import symbol as stdlib_symbol
 from sympy.core import *

+from assumptions import Assume
 from polys import *
 from series import *
 from functions import *
diff --git a/sympy/assumptions/__init__.py b/sympy/assumptions/__init__.py
new file mode 100644
index 0000000..41e388a
--- /dev/null
+++ b/sympy/assumptions/__init__.py
@@ -0,0 +1 @@
+from assumptions import Assume
\ No newline at end of file
diff --git a/sympy/assumptions/assumptions.py b/sympy/assumptions/assumptions.py
new file mode 100644
index 0000000..473751d
--- /dev/null
+++ b/sympy/assumptions/assumptions.py
@@ -0,0 +1,41 @@
+from sympy.core.symbol import Symbol
+
+class Assume(object):
+    """New-style assumptions
+
+    >>> from sympy import Symbol, Assume
+    >>> x = Symbol('x')
+    >>> Assume(x, integer=True)
+    Assume( x, integer, True )
+    >>> Assume(x, integer=False)
+    Assume( x, integer, False )
+    """
+
+    __global_registry = {}
+
+    def __init__(self, expr, *args, **kwargs):
+        if not isinstance(expr, Symbol):
+            raise NotImplementedError
+        if len(kwargs) != 1:
+            raise ValueError('Wrong set of arguments')
+        self._args = (expr, kwargs.keys()[0], kwargs.values()[0])
+
+    @property
+    def expr(self):
+        return self._args[0]
+
+    @property
+    def key(self):
+        return self._args[1]
+
+    @property
+    def value(self):
+        return self._args[2]
+
+    def __repr__(self):
+        return u"Assume( %s, %s, %s )" % (self.expr, self.key, self.value)
+
+    def __eq__(self, other):
+        if isinstance(other, type(self)):
+            return self._args == other._args
+        return False
\ No newline at end of file
diff --git a/sympy/assumptions/known_facts.py b/sympy/assumptions/known_facts.py
new file mode 100644
index 0000000..cb2a9e9
--- /dev/null
+++ b/sympy/assumptions/known_facts.py
@@ -0,0 +1,21 @@
+
+known_facts_dict = {
+    'even'       : ['integer & ~odd'],
+    'composite'  : ['integer & ~prime'],
+    'complex'    : ['real | imaginary', 'rational | irrational | imaginary'], # this is not quite correct
+    'integer'    : ['rational & numerator_is_one'],
+    'irrational' : ['real & ~rational'],
+    'imaginary'  : ['complex & ~real'],
+    'rational'   : ['real & ~irrational'],
+    'real'       : ['complex & ~imaginary', 'rational | irrational'],
+    'unbounded'  : ['extended_real & ~bounded'],
+    'negative'   : ['real & ~positive & ~zero'],
+    'nonpositive': ['real & ~positive', 'zero | negative'],
+    'nonnegative': ['real & ~negative', 'zero | positive'],
+    'noninteger' : ['real & ~integer'],
+    'nonzero'    : ['real & ~zero'],
+    'odd'        : ['integer & ~even'],
+    'prime'      : ['integer & positive & ~composite'],
+    'positive'   : ['real & ~negative & ~zero'],
+    'zero'       : ['real & ~positive & ~negative']
+}
diff --git a/sympy/assumptions/tests/test_assumptions_2.py b/sympy/assumptions/tests/test_assumptions_2.py
new file mode 100644
index 0000000..768418d
--- /dev/null
+++ b/sympy/assumptions/tests/test_assumptions_2.py
@@ -0,0 +1,23 @@
+"""rename this to test_assumptions.py when the old assumptions system is deleted"""
+from sympy.core import Symbol
+from sympy.assumptions import Assume
+
+def test_assume():
+    x = Symbol('x')
+    assump = Assume(x, integer=True)
+    assert assump.expr == x
+    assert assump.key == 'integer'
+    assert assump.value == True
+
+def test_assume_False():
+    x = Symbol('x')
+    assump = Assume(x, integer=False)
+    assert assump.expr == x
+    assert assump.key == 'integer'
+    assert assump.value == False
+
+def test_assume_equal():
+    x = Symbol('x')
+    assert Assume(x, positive=True)  == Assume(x, positive=True)
+    assert Assume(x, positive=True)  != Assume(x, positive=False)
+    assert Assume(x, positive=False) == Assume(x, positive=False)
\ No newline at end of file
--
1.6.1.2


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Implement new query module." by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:12 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 8/8] Implement new query module.
From: Fabian Seoane <fab...@fseoane.net>

The old query system (.is_* properties) has some limitations:

    1. Can't assume relations. It is not possible to specify relations between different
        objects. For example, you can assume that x>0 and y>0, but you can't
        assume x>y

    2. Verbose code splitted across multiple classes. Each class must override
        query methods (.is_*).

    3. Extensibility. To add new assumptions you have to add code to
        the core

The assumption system implemented in this series of patches relies on these
principles:

    1. Assumptions are separate from objects. Assumptions are instances of Assume, which is
       a class that holds a reference to the expression and to the 'key' (what it assumes)

    2. Queries out of the core. No more .is_* methods. Specific queries are implemented
        as subclasses of QueryHandler, and the query function calls the appropriate
        subclass of QueryHandler

        query -> QueryHandler -> QueryNegativeHandler
                              -> QueryIntegerHandler
                              -> QueryBoundedHandler
                              ...
       That way, creating new queries is a matter of subclassing QueryHandler and override
       the apropriate methods.

PD: note that this query module cannot use relations (yet), but at least the infraestructure
is ready to support them.
---
 sympy/__init__.py                |    1 +
 sympy/query/__init__.py          |  130 ++++++++
 sympy/query/handlers/__init__.py |  103 +++++++
 sympy/query/handlers/calculus.py |  118 ++++++++
 sympy/query/handlers/ntheory.py  |  114 +++++++
 sympy/query/handlers/order.py    |  156 ++++++++++
 sympy/query/handlers/sets.py     |  255 ++++++++++++++++
 sympy/query/tests/test_query.py  |  606 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 1483 insertions(+), 0 deletions(-)
 create mode 100644 sympy/query/__init__.py
 create mode 100644 sympy/query/handlers/__init__.py
 create mode 100644 sympy/query/handlers/calculus.py
 create mode 100644 sympy/query/handlers/ntheory.py
 create mode 100644 sympy/query/handlers/order.py
 create mode 100644 sympy/query/handlers/sets.py
 create mode 100644 sympy/query/tests/test_query.py

diff --git a/sympy/__init__.py b/sympy/__init__.py
index d5b33fc..3f08748 100644
--- a/sympy/__init__.py
+++ b/sympy/__init__.py
@@ -34,6 +34,7 @@ def __sympy_debug():
 from geometry import *
 from utilities import *
 from integrals import *
+from query import query
 # This module is slow to import:
 #from physics import units
 from plotting import Plot, textplot
diff --git a/sympy/query/__init__.py b/sympy/query/__init__.py
new file mode 100644
index 0000000..6d7f228
--- /dev/null
+++ b/sympy/query/__init__.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+import inspect
+from sympy.core import Symbol, sympify
+from sympy.utilities.source import get_class
+from sympy.assumptions.known_facts import known_facts_dict
+from sympy.logic.kb import PropKB
+from sympy.logic.boolalg import compile_rule
+
+def query(expr, *args, **kwargs):
+    """
+    1. We build a knowledge base
+    """
+    assumptions = kwargs.pop('assumptions', [])
+    if not isinstance(assumptions, (list, tuple)):
+        assumptions = [assumptions]
+
+    key, value = kwargs.popitem()
+    expr = sympify(expr)
+    if len(kwargs) > 0:
+        # split multiple queries
+        k = {key: value}
+        return query(expr, assumptions=assumptions, **k) and \
+               query(expr, assumptions=assumptions, **kwargs)
+    if not value: # only True queries from now on (e.g. prime=True)
+        k = {key: True}
+        result = query(expr, assumptions=assumptions, **k)
+        if result is not None:
+            return not result
+        return
+
+    # direct resolution method, no logic
+    resolutor = get_class(handlers_dict[key])(expr, key, assumptions)
+    if resolutor.resolution is not None:
+        return resolutor.resolution
+
+    # use logic inference
+    if not expr.is_Atom: return
+    kb = PropKB()
+    # add the knowledge base facts related to assumptions
+    for assump in assumptions:
+        if expr.has(assump.expr):
+            if assump.value:
+                kb.tell(Symbol(assump.key))
+            else:
+                kb.tell(~Symbol(assump.key))
+            for s in known_facts_dict.get(assump.key, []):
+                if assump.value:
+                    kb.tell(compile_rule(s))
+                else:
+                    kb.tell(~compile_rule(s))
+
+    if kb.ask(Symbol(key)): return True
+    if kb.ask(~Symbol(key)): return False
+
+    # try to prove some equivalent fact
+    equiv = known_facts_dict.get(key, [])
+    #if equiv is None: return
+    for s in equiv:
+        rule = compile_rule(s)
+        if kb.ask(rule):
+            return True
+        elif kb.ask(~rule):
+            return False
+
+    # try some depht-first search, we collect all info in the
+    # knowledge base
+    symbols = []
+    for clause in kb.clauses:
+        for s in clause.atoms(Symbol):
+            if str(s) == key: continue
+            if str(s) in [x.key for x in assumptions]: continue
+            if s not in symbols:
+                symbols.append(s)
+
+    for sym in symbols:
+        if kb.ask(sym) == True:
+            for s in known_facts_dict.get(str(sym), []):
+                kb.tell(compile_rule(s))
+
+    if kb.ask(Symbol(key)): return True
+    if kb.ask(~Symbol(key)): return False
+
+# query_dict tells us what query handler we should use
+# for a particular key
+handlers_dict = {
+    'bounded'        : 'sympy.query.handlers.calculus.QueryBoundedHandler',
+    'commutative'    : 'sympy.query.handlers.QueryCommutativeHandler',
+    'comparable'     : 'sympy.query.handlers.QueryComparableHadler',
+    'complex'        : 'sympy.query.handlers.sets.QueryComplexHandler',
+    'composite'      : 'sympy.query.handlers.ntheory.QueryCompositeHandler',
+    'even'           : 'sympy.query.handlers.ntheory.QueryEvenHandler',
+    'extended_real'  : 'sympy.query.handlers.sets.QueryExtendedRealHandler',
+    'finite'         : 'sympy.query.handlers.QueryFiniteHandler',
+    'imaginary'      : 'sympy.query.handlers.sets.QueryImaginaryHandler',
+    'infinitesimal'  : 'sympy.query.handlers.QueryInfinitesimalHandler',
+    'integer'        : 'sympy.query.handlers.sets.QueryIntegerHandler',
+    'irrational'     : 'sympy.query.handlers.sets.QueryIrrationalHandler',
+    'rational'       : 'sympy.query.handlers.sets.QueryRationalHandler',
+    'nonnegative'    : 'sympy.query.handlers.order.QueryNonNegativeHandler',
+    'noninteger'     : 'sympy.query.handlers.sets.QueryNonIntegerHandler',
+    'nonpositive'    : 'sympy.query.handlers.order.QueryNonPositiveHandler',
+    'nonzero'        : 'sympy.query.handlers.order.QueryNonZeroHandler',
+    'negative'       : 'sympy.query.handlers.order.QueryNegativeHandler',
+    'positive'       : 'sympy.query.handlers.order.QueryPositiveHandler',
+    'prime'          : 'sympy.query.handlers.ntheory.QueryPrimeHandler',
+    'real'           : 'sympy.query.handlers.sets.QueryRealHandler',
+    'odd'            : 'sympy.query.handlers.ntheory.QueryOddHandler',
+    'unbounded'      : 'sympy.query.handlers.calculus.QueryUnboundedHandler',
+    'zero'           : 'sympy.query.handlers.order.QueryZeroHandler'
+}
+
+class QueryHandler(object):
+    """Base class that all Query Handlers must inherit"""
+
+    facts = []
+    resolution = None
+
+    def __init__(self, expr, key, assumptions=None):
+        """
+        TODO
+        """
+        self.expr = expr
+        self.key = key
+        self.assumptions = assumptions
+
+        mro = inspect.getmro(type(self.expr))
+        for subclass in mro:
+            if hasattr(self, subclass.__name__):
+                self.resolution = getattr(self, subclass.__name__)()
+                break
diff --git a/sympy/query/handlers/__init__.py b/sympy/query/handlers/__init__.py
new file mode 100644
index 0000000..8945a0b
--- /dev/null
+++ b/sympy/query/handlers/__init__.py
@@ -0,0 +1,103 @@
+
+from sympy.query import query, QueryHandler
+
+
+"""Facts must only have one level of indirection to avoid infinite recursion"""
+
+class CommonHandler(QueryHandler):
+    """Defines some useful methods common to most Handlers """
+    def Symbol(self):
+        if self.assumptions is None:
+            return None
+        for assump in self.assumptions:
+            if assump.expr == self.expr and assump.key == self.key:
+                return assump.value
+        return None
+
+    def NaN(self):
+        return False
+
+
+class QueryCommutativeHandler(CommonHandler):
+    def Basic(self):
+        for a in self.expr.args:
+            if query(a, commutative=True, assumptions=self.assumptions) == False:
+                return False
+        else:
+            return True
+
+    def NaN(self):
+        return True
+
+class QueryFiniteHandler(CommonHandler):
+
+    def Mul(self):
+        for arg in self.expr.args:
+            _result = query(arg, finite=True, assumptions=self.assumptions)
+            if not _result:
+                return _result
+        return True
+
+    Add = Mul
+
+    def Number(self):
+        return True
+
+    def Infinity(self):
+        return False
+
+    def NegativeInfinity(self):
+        return False
+
+    def NumberSymbol(self):
+        return True
+
+    def ImaginaryUnit(self):
+        return True
+
+class QueryInfinitesimalHandler(CommonHandler):
+
+    def Mul(self):
+        for arg in self.expr.args:
+            _result = query(arg, infinitesimal=True, assumptions=self.assumptions)
+            if not _result:
+                return _result
+        return True
+
+    Add = Mul
+
+    def Number(self):
+        return self.expr == 0
+
+    def Pi(self):
+        return False
+
+    def Exp1(self):
+        return False
+
+    def ImaginaryUnit(self):
+        return False
+
+class
...

read more »


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "A new general-purpose logic module." by Fabian Pedregosa
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:20 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:20:11 +0200
Local: Wed, Jun 10 2009 11:20 am
Subject: [PATCH 7/8] A new general-purpose logic module.
This is a replacement for sympy.core.logic and will be used
extensively by the query module. The old logic module can be
removed once the old assumption system is removed.

Contents
--------

  sympy.logic.boolalg
    - Operators for boolean algebra on symbols {And: &, Or: |, Not: ~}
    - some useful methods, mainly used to convert expressions to
      conjunctive normal form (CNF)

  sympy.logic.inference
    - Rules for inference in propositional logic. Main method here is
      satisfiable(expr), which checks satisfiability of a propositional
      sentence (for now using dpll algorithm)

  sympy.logic.kb
    - Definition of a knowledge base

  sympy.algorithms
    - some algorithms used by higher order methods (just DPLL for now),
      but in a future we should also have Quine-McCluskey for simplification
      of boolean expressions

Most of the methods in this module are implementations of algorithms described
in the book "AI: A modern approach", http://aima.cs.berkeley.edu/
---
 sympy/core/basic.py                 |   26 ++++++-
 sympy/logic/__init__.py             |    2 +
 sympy/logic/algorithms/dpll.py      |   49 +++++++++++
 sympy/logic/boolalg.py              |  155 +++++++++++++++++++++++++++++++++++
 sympy/logic/inference.py            |  119 +++++++++++++++++++++++++++
 sympy/logic/kb.py                   |   36 ++++++++
 sympy/logic/tests/test_boolalg.py   |  110 +++++++++++++++++++++++++
 sympy/logic/tests/test_inference.py |   46 ++++++++++
 8 files changed, 541 insertions(+), 2 deletions(-)
 create mode 100644 sympy/logic/__init__.py
 create mode 100644 sympy/logic/algorithms/__init__.py
 create mode 100644 sympy/logic/algorithms/dpll.py
 create mode 100755 sympy/logic/boolalg.py
 create mode 100755 sympy/logic/inference.py
 create mode 100644 sympy/logic/kb.py
 create mode 100755 sympy/logic/tests/test_boolalg.py
 create mode 100755 sympy/logic/tests/test_inference.py

diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index b48e633..6ab3101 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -680,8 +680,30 @@ def __rdiv__(self, other):
     __truediv__ = __div__
     __rtruediv__ = __rdiv__

-
-
+    # *******************
+    # * Logic operators *
+    # *******************
+
+    def __and__(self, other):
+        """Overloading for & operator"""
+        from sympy.logic.boolalg import And
+        return And(self, other)
+    def __or__(self, other):
+        """Overloading for |"""
+        from sympy.logic.boolalg import Or
+        return Or(self, other)
+    def __invert__(self):
+        """Overloading for ~"""
+        from sympy.logic.boolalg import Not
+        return Not(self)
+    def __rshift__(self, other):
+        """Overloading for >>"""
+        from sympy.logic.boolalg import Implies
+        return Implies(self, other)
+    def __lshift__(self, other):
+        """Overloading for <<"""
+        from sympy.logic.boolalg import Implies
+        return Implies(other, self)

     def __repr__(self):
diff --git a/sympy/logic/__init__.py b/sympy/logic/__init__.py
new file mode 100644
index 0000000..5076249
--- /dev/null
+++ b/sympy/logic/__init__.py
@@ -0,0 +1,2 @@
+from boolalg import *
+from inference import *
\ No newline at end of file
diff --git a/sympy/logic/algorithms/__init__.py b/sympy/logic/algorithms/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sympy/logic/algorithms/dpll.py b/sympy/logic/algorithms/dpll.py
new file mode 100644
index 0000000..77d92ed
--- /dev/null
+++ b/sympy/logic/algorithms/dpll.py
@@ -0,0 +1,49 @@
+from sympy.core import Symbol
+from sympy.logic.boolalg import conjuncts, to_cnf
+from sympy.logic.inference import find_pure_symbol, find_unit_clause, pl_true
+
+def dpll_satisfiable(expr):
+    """Check satisfiability of a propositional sentence.
+    It returns a model rather than True when it succeeds
+    >>> from sympy import symbols
+    >>> A, B = symbols('AB')
+    >>> dpll_satisfiable(A & ~B)
+    {A: True, B: False}
+    >>> dpll_satisfiable(A & ~A)
+    False
+
+    References: Implemented as described in http://aima.cs.berkeley.edu/
+    """
+    clauses = conjuncts(to_cnf(expr))
+    symbols = list(expr.atoms(Symbol))
+    return dpll(clauses, symbols, {})
+
+def dpll(clauses, symbols, model):
+    """See if the clauses are true in a partial model.
+    http://en.wikipedia.org/wiki/DPLL_algorithm
+    """
+    unknown_clauses = [] ## clauses with an unknown truth value
+    for c in clauses:
+        val =  pl_true(c, model)
+        if val == False:
+            return False
+        if val != True:
+            unknown_clauses.append(c)
+    if not unknown_clauses:
+        return model
+    P, value = find_pure_symbol(symbols, unknown_clauses)
+    if P:
+        model.update({P: value})
+        syms = [x for x in symbols if x != P]
+        return dpll(clauses, syms, model)
+    P, value = find_unit_clause(clauses, model)
+    if P:
+        model.update({P: value})
+        syms = [x for x in symbols if x != P]
+        return dpll(clauses, syms, model)
+    P = symbols.pop()
+    model_1, model_2 = model.copy(), model.copy()
+    model_1.update({P: True})
+    model_2.update({P: False})
+    return (dpll(clauses, symbols, model_1) or
+            dpll(clauses, symbols, model_2))
\ No newline at end of file
diff --git a/sympy/logic/boolalg.py b/sympy/logic/boolalg.py
new file mode 100755
index 0000000..1a57740
--- /dev/null
+++ b/sympy/logic/boolalg.py
@@ -0,0 +1,155 @@
+"""Boolean algebra module for SymPy"""
+from sympy.core import Basic, Function, sympify, Symbol
+from sympy.utilities import flatten
+
+
+class BooleanFunction(Function):
+    """Boolean function is a function that lives in a boolean space
+    It is used as base class for And, Or, Not, etc.
+    """
+    pass
+
+class And(BooleanFunction):
+    """Evaluates to True if all it's arguments are True,
+    False otherwise"""
+    @classmethod
+    def eval(cls, *args):
+        if len(args) < 2: raise ValueError("And must have at least two arguments")
+        out_args = []
+        for i, arg in enumerate(args): # we iterate over a copy or args
+            if isinstance(arg, bool):
+                if not arg: return False
+                else: continue
+            out_args.append(arg)
+        if len(out_args) == 0: return True
+        if len(out_args) == 1: return out_args[0]
+        sargs = sorted(flatten(out_args, cls=cls))
+        return Basic.__new__(cls, *sargs)
+
+class Or(BooleanFunction):
+    @classmethod
+    def eval(cls, *args):
+        if len(args) < 2: raise ValueError("And must have at least two arguments")
+        out_args = []
+        for i, arg in enumerate(args): # we iterate over a copy or args
+            if isinstance(arg, bool):
+                if arg: return True
+                else: continue
+            out_args.append(arg)
+        if len(out_args) == 0: return False
+        if len(out_args) == 1: return out_args[0]
+        sargs = sorted(flatten(out_args, cls=cls))
+        return Basic.__new__(cls, *sargs)
+
+class Not(BooleanFunction):
+    """De Morgan rules applied automatically, so Not is moved inward"""
+    @classmethod
+    def eval(cls, *args):
+        if len(args) > 1:
+            return map(cls, args)
+        arg = args[0]
+        # apply De Morgan Rules
+        if isinstance(arg, And):
+            return Or( *[Not(a) for a in arg.args])
+        if isinstance(arg, Or):
+            return And(*[Not(a) for a in arg.args])
+        if isinstance(arg, bool): return not arg
+        if isinstance(arg, Not):
+            if len(arg.args) == 1: return arg.args[0]
+            return arg.args
+
+class Implies(BooleanFunction):
+    def __init__(self, *args, **kwargs):
+        if len(args) != 2: raise ValueError("Wrong set of arguments")
+        return super(BooleanFunction, self).__init__(*args, **kwargs)
+
+class Equivalent(BooleanFunction):
+    pass
+
+### end class definitions. Some useful methods
+
+def conjuncts(expr):
+    """Return a list of the conjuncts in the expr s.
+    >>> from sympy import symbols
+    >>> A, B = symbols('AB')
+    >>> conjuncts(A & B)
+    [A, B]
+    >>> conjuncts(A | B)
+    [Or(A, B)]
+    """
+    if isinstance(expr, And):
+        return list(expr.args)
+    else:
+        return [expr]
+
+def disjuncts(expr):
+    """Return a list of the disjuncts in the sentence s.
+    >>> from sympy import symbols
+    >>> A, B = symbols('AB')
+    >>> disjuncts(A | B)
+    [A, B]
+    >>> disjuncts(A & B)
+    [And(A, B)]
+    """
+    if isinstance(expr, Or):
+        return list(expr.args)
+    else:
+        return [expr]
+
+def distribute_and_over_or(expr):
+    """Given a sentence s consisting of conjunctions and disjunctions
+    of literals, return an equivalent sentence in CNF.
+    """
+    if isinstance(expr, Or):
+        expr = Or(*expr.args)
+        if len(expr.args) == 0:
+            return False
+        if len(expr.args) == 1:
+            return distribute_and_over_or(expr.args[0])
+        for arg in expr.args:
+            if isinstance(arg, And):
+                conj = arg
+                break
+        else: return type(expr)(*expr.args)
+        others = [a for a in expr.args if a is not conj]
+        if len(others) == 1:
+            rest = others[0]
+        else:
+            rest = Or(*others)
+        return And(*map(distribute_and_over_or,
+                   [Or(c, rest) for c in conj.args]))
+    elif isinstance(expr, And):
+        return And(*map(distribute_and_over_or, expr.args))
+    else:
+        return expr
+
+def to_cnf(expr):
+    """Convert a propositional logical sentence s to conjunctive normal form.
+    That is, of the form ((A | ~B | ...) & (B | C | ...) & ...)
+    """
+    expr = sympify(expr)
+    expr = eliminate_implications(expr)
+    return distribute_and_over_or(expr)
+
+def eliminate_implications(expr):
+    """Change >>, <<, and <=> into &, |, and ~. That is, return an Expr
+  
...

read more »


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Implement variations in sympy.utilities.iterables" by fseoane
fseoane  
View profile  
 More options Jun 10, 11:25 am
From: fseoane <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 08:25:41 -0700 (PDT)
Local: Wed, Jun 10 2009 11:25 am
Subject: Re: Implement variations in sympy.utilities.iterables
just realized that the query module no longer uses this routine.

Anyway, I believe it is nice and can be useful in a future ..., please
review ...

On Jun 10, 5:20 pm, Fabian Pedregosa <fab...@fseoane.net> wrote:


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "New assumption system" by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 11:34 am
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 09:34:07 -0600
Local: Wed, Jun 10 2009 11:34 am
Subject: Re: New assumption system

Could you also push this to some branch to github? I'll play with it.

Ondrej


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Fabian Pedregosa  
View profile  
 More options Jun 10, 11:44 am
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 17:44:43 +0200
Local: Wed, Jun 10 2009 11:44 am
Subject: Re: New assumption system

should be in the usual location:

git pull http://fseoane.net/git/sympy.git assumptions

but currently the server seems to be down ... i'll ping you when it
comes back

> Ondrej

--
http://fseoane.net/blog/

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Fabian Pedregosa  
View profile  
 More options Jun 10, 12:45 pm
From: Fabian Pedregosa <fab...@fseoane.net>
Date: Wed, 10 Jun 2009 18:45:41 +0200
Local: Wed, Jun 10 2009 12:45 pm
Subject: Re: New assumption system

git pull http://fseoane.net/git/sympy.git master

(notice branch is master, not assumptions) should be working now,

~Fabian

> but currently the server seems to be down ... i'll ping you when it
> comes back

>> Ondrej

--
http://fseoane.net/blog/

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Add a second cls argument to flatten." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:30 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:30:33 -0600
Local: Wed, Jun 10 2009 1:30 pm
Subject: Re: [PATCH 4/8] Add a second cls argument to flatten.

If the cls argument is specified

Add more regular tests for this. All things in the docstrings should
also be tested in regular tests. Add tests with more nested stuff.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "A new general-purpose logic module." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:41 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:41:10 -0600
Local: Wed, Jun 10 2009 1:41 pm
Subject: Re: [PATCH 7/8] A new general-purpose logic module.

On Wed, Jun 10, 2009 at 9:20 AM, Fabian Pedregosa<fab...@fseoane.net> wrote:

> This is a replacement for sympy.core.logic and will be used
> extensively by the query module. The old logic module can be
> removed once the old assumption system is removed.

The code is good, tests are ok, but please try to add more doctests,
so that it's easier for users to understand what each function is
doing. I marked the functions where I would add a doctest below:

Add couple doctests

Add couple doctests

> +    @classmethod
> +    def eval(cls, *args):
> +        if len(args) < 2: raise ValueError("And must have at least two arguments")
> +        out_args = []
> +        for i, arg in enumerate(args): # we iterate over a copy or args
> +            if isinstance(arg, bool):
> +                if not arg: return False
> +                else: continue
> +            out_args.append(arg)
> +        if len(out_args) == 0: return True
> +        if len(out_args) == 1: return out_args[0]
> +        sargs = sorted(flatten(out_args, cls=cls))
> +        return Basic.__new__(cls, *sargs)
> +
> +class Or(BooleanFunction):

Add couple doctests

Add couple doctests

Add couple doctests

...

read more »


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Implement variations in sympy.utilities.iterables" by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:47 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:47:35 -0600
Local: Wed, Jun 10 2009 1:47 pm
Subject: Re: [PATCH 1/8] Implement variations in sympy.utilities.iterables
Looks good, please add doctests.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "A new general-purpose logic module." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:49 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:49:40 -0600
Local: Wed, Jun 10 2009 1:49 pm
Subject: Re: [PATCH 7/8] A new general-purpose logic module.
Also, how does this module compare to the assumptions logic module
that we already have in

sympy/core/facts.py

? Is it a duplicate functionality, or a new functionality, etc.?  Is
it better/worse, what are your plans with facts.py (should we remove
it or maintain both)?

Ondrej

...

read more »


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Implement new query module." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:57 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:57:05 -0600
Local: Wed, Jun 10 2009 1:57 pm
Subject: Re: [PATCH 8/8] Implement new query module.
Looks good in general. Nice and thorough tests, thanks for that.
Couple minor comments:

* add more documentation and doctests to the classes below

Put the lines (in the log):

> The assumption system implemented in this series of patches relies on these
> principles:

...

as a module docstring.

Otherwise +1.

Ondrej

...

read more »


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "implement get_class and get_mod_func in sympy.utilities.source" by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:57 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:57:43 -0600
Local: Wed, Jun 10 2009 1:57 pm
Subject: Re: [PATCH 2/8] implement get_class and get_mod_func in sympy.utilities.source
+1


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Allow Function.eval to return non-instances of Basic." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:58 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:58:10 -0600
Local: Wed, Jun 10 2009 1:58 pm
Subject: Re: [PATCH 3/8] Allow Function.eval to return non-instances of Basic.
+1


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "Add support for bool types in sympify." by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 1:58 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 11:58:53 -0600
Local: Wed, Jun 10 2009 1:58 pm
Subject: Re: [PATCH 5/8] Add support for bool types in sympify.
Could you please write some tests for this?

Otherwise +1


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "New-style assumptions" by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 2:00 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 12:00:22 -0600
Local: Wed, Jun 10 2009 2:00 pm
Subject: Re: [PATCH 6/8] New-style assumptions
+1


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Discussion subject changed to "New assumption system" by Ondrej Certik
Ondrej Certik  
View profile  
 More options Jun 10, 2:02 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 12:02:03 -0600
Local: Wed, Jun 10 2009 2:02 pm
Subject: Re: New assumption system

Patches are ok, tests pass. Code is ok too, I only had some minor
remarks regarding docstrings and doctests. It's important to write
nice docstrings, because they show up in our documentation. Those
should not serve as tests though, only to guide the user, so that he
has an idea what the function does.

Ondrej


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Brian Granger  
View profile  
 More options Jun 10, 2:12 pm
From: Brian Granger <ellisonbg....@gmail.com>
Date: Wed, 10 Jun 2009 11:12:08 -0700
Local: Wed, Jun 10 2009 2:12 pm
Subject: Re: New assumption system
Fabian,

Looks like very exciting work.  I have a few questions about the new system...

One thing that really bothered me about the old .is_* syntax is that
it made it very difficult for users to create their own Sympy
subclasses and have them be true equals with the built-in Sympy types.
 The reason is that for each new type you created, you would have to
modify the Sympy core to add the appropriate is_* syntax for your new
types.

It look like your patches will make it much easier for users to create
custom Sympy types that are on equal grounds as the built in ones.  Is
this the case?  If I create a new type, will I be able to implement
queries for that type and will I be able to tell the Sympy core about
my objects without modifying the Sympy core?

I think we should make it a goal that new sympy types can be created
without modifying Sympy core.  Another area that currently violates
this idea is the printing system.  But, this will have to be modified
anyways to get it to work with the Sage notebook's handling of latex
output.

Cheers,

Brian


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ondrej Certik  
View profile  
 More options Jun 10, 2:18 pm
From: Ondrej Certik <ond...@certik.cz>
Date: Wed, 10 Jun 2009 12:18:00 -0600
Subject: Re: New assumption system

Yes, definitely!

> I think we should make it a goal that new sympy types can be created
> without modifying Sympy core.  Another area that currently violates
> this idea is the printing system.  But, this will have to be modified
> anyways to get it to work with the Sage notebook's handling of latex
> output.

It has to be fixed for the sage notebook, but otherwise how does it violate it?

If you create your own class and want to hook it up let's say in the
latex printer, just override the _latex_ method.

The same way, if you want to create your own printer, just override or
create a new Printer class from scratch. That way, sympy can be
extented both by new classes and new printers. What is your idea to do
it some other way?

Ondrej


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 1 - 25 of 46   Newer >
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google