From e94104306c2689755b6cb2c976d31216984621d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Santos=20Costa?= Date: Tue, 1 Jun 2010 00:33:32 +0100 Subject: [PATCH] port of PYSWIP package. --- packages/pyswip/CHANGELOG | 46 ++ packages/pyswip/COPYING | 340 ++++++++++ packages/pyswip/INSTALL | 73 +++ packages/pyswip/Makefile.in | 45 ++ packages/pyswip/README | 98 +++ packages/pyswip/README.YAP | 16 + packages/pyswip/examples/README | 14 + packages/pyswip/examples/coins/coins.pl | 42 ++ packages/pyswip/examples/coins/coins.py | 22 + packages/pyswip/examples/create_term.py | 27 + packages/pyswip/examples/draughts/puzzle1.pl | 18 + packages/pyswip/examples/draughts/puzzle1.py | 34 + packages/pyswip/examples/hanoi/hanoi.pl | 12 + packages/pyswip/examples/hanoi/hanoi.py | 67 ++ packages/pyswip/examples/knowledgebase.py | 33 + packages/pyswip/examples/register_foreign.py | 14 + .../examples/register_foreign_simple.py | 20 + .../pyswip/examples/sendmoremoney/money.pl | 22 + .../pyswip/examples/sendmoremoney/money.py | 21 + packages/pyswip/examples/sudoku/sudoku.pl | 31 + packages/pyswip/examples/sudoku/sudoku.py | 62 ++ .../pyswip/examples/sudoku/sudoku_daily.py | 78 +++ packages/pyswip/pyswip/__init__.py | 24 + packages/pyswip/pyswip/core.py | 595 ++++++++++++++++++ packages/pyswip/pyswip/easy.py | 476 ++++++++++++++ packages/pyswip/pyswip/prolog.py | 155 +++++ packages/pyswip/setup.py | 117 ++++ 27 files changed, 2502 insertions(+) create mode 100644 packages/pyswip/CHANGELOG create mode 100644 packages/pyswip/COPYING create mode 100644 packages/pyswip/INSTALL create mode 100644 packages/pyswip/Makefile.in create mode 100644 packages/pyswip/README create mode 100644 packages/pyswip/README.YAP create mode 100644 packages/pyswip/examples/README create mode 100644 packages/pyswip/examples/coins/coins.pl create mode 100644 packages/pyswip/examples/coins/coins.py create mode 100644 packages/pyswip/examples/create_term.py create mode 100644 packages/pyswip/examples/draughts/puzzle1.pl create mode 100644 packages/pyswip/examples/draughts/puzzle1.py create mode 100644 packages/pyswip/examples/hanoi/hanoi.pl create mode 100644 packages/pyswip/examples/hanoi/hanoi.py create mode 100644 packages/pyswip/examples/knowledgebase.py create mode 100644 packages/pyswip/examples/register_foreign.py create mode 100644 packages/pyswip/examples/register_foreign_simple.py create mode 100644 packages/pyswip/examples/sendmoremoney/money.pl create mode 100644 packages/pyswip/examples/sendmoremoney/money.py create mode 100644 packages/pyswip/examples/sudoku/sudoku.pl create mode 100644 packages/pyswip/examples/sudoku/sudoku.py create mode 100644 packages/pyswip/examples/sudoku/sudoku_daily.py create mode 100644 packages/pyswip/pyswip/__init__.py create mode 100644 packages/pyswip/pyswip/core.py create mode 100644 packages/pyswip/pyswip/easy.py create mode 100644 packages/pyswip/pyswip/prolog.py create mode 100644 packages/pyswip/setup.py diff --git a/packages/pyswip/CHANGELOG b/packages/pyswip/CHANGELOG new file mode 100644 index 000000000..47ccfc1c1 --- /dev/null +++ b/packages/pyswip/CHANGELOG @@ -0,0 +1,46 @@ +PySWIP CHANGELOG +================ + ++ 0.2.2 + * PySWIP won't rely on the (id of the) functor handle of ``=/2``. + * Sebastian Höhn's patch to enable PySWIP to work on MAC OS-X is incorporated. + ++ 0.2.1 + + * Importing ``pyswip`` automatically initializes SWI-Prolog. + * Fixed a bug with querying lists with the new interface. + ++ 0.2.0 + + * All names are included with ``from pyswip import ...`` + * New *Pythonic* interface + * Prolog.query returns real Python datatypes + * Markus Triska's Sudoku Solver + * Prolog module support + * Foreign functions retrieve Python datatypes. + ++ 0.1.3 + + * Renamed ``pyswip/util.py`` to ``pyswip/prolog.py``. + * New module ``pyswip.easy``. + * Now it is possible to register a Python function as a Prolog predicate through SWI-Prolog's Foreign Function Interface. + * Additions to the core library. + * Added example, *register foreign* which shows how to register a Python function as an SWI-Prolog predicate. + * Added example, *Towers of Hanoi* + ++ 0.1.2 + + * Renamed ``PrologRunner`` to ``Prolog``. + * Removed ``query`` method of ``Prolog``, ``queryGenerator`` is renamed as ``query``. + * Added ``asserta``, ``assertz`` and ``consult`` methods to ``Prolog``. + * The necessary cleanup is done even if the ``query`` generator doesn't run to the end. + * Errors during the execution of ``query`` is caught and ``PrologError`` is raised. + * Many new additions to the core library. + * Added ``examples`` directory. + * Added examples, *coins* and *draughts*. + ++ 0.1.1 + + * Added ``queryGenerator`` to PrologRunner, ``query`` calls ``queryGenerator``. + * Added example ``send more money``. + diff --git a/packages/pyswip/COPYING b/packages/pyswip/COPYING new file mode 100644 index 000000000..f90922eea --- /dev/null +++ b/packages/pyswip/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/packages/pyswip/INSTALL b/packages/pyswip/INSTALL new file mode 100644 index 000000000..4b67fb441 --- /dev/null +++ b/packages/pyswip/INSTALL @@ -0,0 +1,73 @@ +PySWIP INSTALL +============== + +PySWIP requires SWI-Prolog as a shared library since it uses ctypes to access SWI-Prolog/C functions. The shared library is present in Win32 installer, but missing by default from the builds made directly from the source. + +Installing on Linux +------------------- + +These instructions are tested on a Linux system, but should also work for POSIX systems. Also, you may want to install development packages for readline and libgmp (not required for basics). + +You need to do the following to install a shared library enabled version of SWI-Prolog. We use version 5.6.34 of SWI-Prolog but any other recent version should work fine. Please make the necessary modifications for your environment. + +1) Get the source from: http://www.swi-prolog.org/download.html:: + + $ wget http://gollem.science.uva.nl/cgi-bin/nph-download/SWI-Prolog/pl-5.6.34.tar.gz + +2) Extract the archive and cd into it:: + + $ tar xzvf pl-5.6.34.tar.gz + $ cd pl-5.6.34 + +3) Configure the source with shared library enabled:: + + $ ./configure --prefix=/usr --enable-shared + +4) Compile the source:: + + $ make + +5) Install the source:: + + $ sudo make install + +6) clp library is useful for constraint handling problems, so let's install that too:: + + $ cd cd packages/clpqr + $ ./configure --prefix=/usr --enable-shared + $ make && make install + + +7) Create a soft link to ``libpol.so``:: + + $ sudo ln -s /usr/lib/pl-5.6.34/lib/i686-linux/libpl.so.5.6.34 /usr/lib/libpl.so + +8) Next, get and install ctypes from: http://starship.python.net/crew/theller/ctypes . Note that you don't need to install it if you are using Python 2.5. + +9) Unpack PySwIP package and install it with, ``python setup.py install``. + +10) After you install it, you can test it with the following at your Python shell:: + + >>> from pyswip import Prolog + >>> prolog = Prolog() + >>> prolog.assertz("father(michael,john)") + +If you get an error, such as "libpl (shared) not found." or "FATAL ERROR: Resource not found" be sure you have installed SWI-Prolog as a share library. Check your default library directory (usually ``/usr/lib``) for ``libpl.so``. + + +Installing on Win32 +------------------- + +1) Get a recent version of SWI-Prolog for Win32 from: http://www.swi-prolog.org/dl-stable.html and install it. + +2) You need to add SWI-Prolog's bin directory ``C:\Program Files\pl\bin`` to *path*, here are two tutorials for that: http://www.computerhope.com/issues/ch000549.htm and http://vlaurie.com/computers2/Articles/environment.htm + +3) Get a Windows installer version of PySWIP and install it. + +4) After you install it, you can test it with the following at your Python console:: + + >>> from pyswip import Prolog + >>> prolog = Prolog() + >>> prolog.assertz("father(michael,john)") + + diff --git a/packages/pyswip/Makefile.in b/packages/pyswip/Makefile.in new file mode 100644 index 000000000..6296ea4f5 --- /dev/null +++ b/packages/pyswip/Makefile.in @@ -0,0 +1,45 @@ +# +# default base directory for YAP installation +# +# +ROOTDIR = @prefix@ +# +# where the binary should be +# +BINDIR = $(ROOTDIR)/bin +# +# where YAP should look for binary libraries +# +LIBDIR=@libdir@ +YAPLIBDIR=@libdir@/Yap +# +# where YAP should look for architecture-independent Prolog libraries +# +SHAREDIR=$(ROOTDIR)/share +# +# +# You shouldn't need to change what follows. +# +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +srcdir=@srcdir@ +YAP_EXTRAS=@YAP_EXTRAS@ + +install: + (cd $(srcdir); python setup.py install) + +clean: + +test: + (cd $(srcdir)/examples; python create_term.py) + (cd $(srcdir)/examples; python knowledgebase.py) + (cd $(srcdir)/examples; python knowledgebase.py) + (cd $(srcdir)/examples; python register_foreign.py) + (cd $(srcdir)/examples; python register_foreign_simple.py) + (cd $(srcdir)/examples/coins; python coins.py) + (cd $(srcdir)/examples/draughts; python puzzle1.py) + (cd $(srcdir)/examples/hanoi; python hanoi.py) + (cd $(srcdir)/examples/sendmoremoney; python money.py) + (cd $(srcdir)/examples/sudoku; python sudoku.py) + (cd $(srcdir)/examples/sudoku; python sudoku_daily.py) diff --git a/packages/pyswip/README b/packages/pyswip/README new file mode 100644 index 000000000..592fc1107 --- /dev/null +++ b/packages/pyswip/README @@ -0,0 +1,98 @@ +PySWIP README +============ + +:Version: + 0.2.2 + +:Author: + Yuce Tekol. + +:Project Website: + http://code.google.com/p/pyswip + + +Introduction +------------ + +PySWIP is a GPL'd Python - SWI-Prolog bridge enabling to query SWI-Prolog in your Python programs. It features an (incomplete) SWI-Prolog foreign language interface, a utility class that makes it easy querying with Prolog and also a Pythonic interface. + +Since PySWIP uses SWI-Prolog as a shared library and ctypes to access it, it doesn't require compilation to be installed. + +Note that this version of PySWIP is slightly incompatible with 0.1.x versions. + +Requirements: +------------- + +* Python 2.3 and higher. +* ctypes 1.0 and higher. +* SWI-Prolog 5.6.x and higher (most probably other versions will also work). +* libpl as a shared library. +* Works on Linux and Win32, should work for all POSIX. + +Example (Using Prolog): +----------------------- + + >>> from pyswip import Prolog + >>> prolog = Prolog() + >>> prolog.assertz("father(michael,john)") + >>> prolog.assertz("father(michael,gina)") + >>> list(prolog.query("father(michael,X)")) + [{'X': 'john'}, {'X': 'gina'}] + >>> for soln in prolog.query("father(X,Y)"): + ... print soln["X"], "is the father of", soln["Y"] + ... + michael is the father of john + michael is the father of gina + +Since version 0.1.3 of PySWIP, it is possible to register a Python function as a Prolog predicate through SWI-Prolog's foreign language interface. + +Example (Foreign Functions): +---------------------------- + + from pyswip import Prolog, registerForeign + + def hello(t): + print "Hello,", t + hello.arity = 1 + + registerForeign(hello) + + prolog = Prolog() + prolog.assertz("father(michael,john)") + prolog.assertz("father(michael,gina)") + list(prolog.query("father(michael,X), hello(X)")) + +Outputs: + Hello, john + Hello, gina + +Since version 0.2, PySWIP contains a 'Pythonic' interface which allows writing predicates in pure Python (*Note that interface is experimental.*) + +Example (Pythonic interface): +----------------------------- + + from pyswip import Functor, Variable, Query + + assertz = Functor("assertz", 2) + father = Functor("father", 2) + + call(assertz(father("michael","john"))) + call(assertz(father("michael","gina"))) + + X = Variable() + q = Query(father("michael",X)) + while q.nextSolution(): + print "Hello,", X.value + q.closeQuery() + +Outputs: + Hello, john + Hello, gina + +The core functionality of ``Prolog.query`` is based on Nathan Denny's public domain prolog.py found at http://www.ahsc.arizona.edu/~schcats/projects/docs/prolog-0.2.0.html + +Install +------- + +Please see ``INSTALL`` for detailed instructions. + diff --git a/packages/pyswip/README.YAP b/packages/pyswip/README.YAP new file mode 100644 index 000000000..567b69ed4 --- /dev/null +++ b/packages/pyswip/README.YAP @@ -0,0 +1,16 @@ +This is an experimental port of Yuce Tekol's pyswip package. It +supports for 64 bit code, and should work in SWI-Prolog. + +- YAP must be compiled as a dynamic library +- libYap.so must be in the ld path: either use --prefix=/usr or + LD_LIBRARY_PATH + +Only tested in Linux right now. Use + +make install +make tests + +from packages/pyswip + +to see how it goes. + diff --git a/packages/pyswip/examples/README b/packages/pyswip/examples/README new file mode 100644 index 000000000..f19cdc6f8 --- /dev/null +++ b/packages/pyswip/examples/README @@ -0,0 +1,14 @@ +PySWIP Examples +=============== + +This directory contains examples for PySWIP. + +The ones marked with (clp) requires clp library of SWI-Prolog. + ++ (clp) coins/ ++ (clp) draughts/ ++ hanoi/ : towers of Hanoi ++ (clp) sendmoremoney/ : if, SEND + MORE = MONEY, what is S, E, N, D, M, O, R, Y? ++ (clp) sudoku/ : Sudoku solver (Prolog code is contributed by Markus Triska) ++ create_term.py : shows creating a Prolog term ++ register_foreign.py : shows how to call PL_register_foreign diff --git a/packages/pyswip/examples/coins/coins.pl b/packages/pyswip/examples/coins/coins.pl new file mode 100644 index 000000000..82fa31419 --- /dev/null +++ b/packages/pyswip/examples/coins/coins.pl @@ -0,0 +1,42 @@ + +% Coins -- 2007 by Yuce Tekol + +:- use_module(library('clpfd')). + +coins(S, Count, Total) :- + % A=1, B=5, C=10, D=50, E=100 + S = [A, B, C, D, E], + + Av is 1, + Bv is 5, + Cv is 10, + Dv is 50, + Ev is 100, + + Aup is Total // Av, + Bup is Total // Bv, + Cup is Total // Cv, + Dup is Total // Dv, + Eup is Total // Ev, + + A in 0..Aup, + B in 0..Bup, + C in 0..Cup, + D in 0..Dup, + E in 0..Eup, + + VA #= A*Av, + VB #= B*Bv, + VC #= C*Cv, + VD #= D*Dv, + VE #= E*Ev, + + sum(S, #=, Count), + VA + VB + VC + VD + VE #= Total, + + label(S). + +% :- findall(S, coins(S, 100, 500), Ss), halt. + %:- coins(S, 100, 500), writeln(S), fail. + + diff --git a/packages/pyswip/examples/coins/coins.py b/packages/pyswip/examples/coins/coins.py new file mode 100644 index 000000000..b6e2a8887 --- /dev/null +++ b/packages/pyswip/examples/coins/coins.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# 100 coins must sum to $5.00 + +from pyswip.prolog import Prolog + +def main(): + prolog = Prolog() + prolog.consult("coins.pl") + count = int(raw_input("How many coins (default: 100)? ") or 100) + total = int(raw_input("What should be the total (default: 500)? ") or 500) + for i, soln in enumerate(prolog.query("coins(S, %d, %d)." % (count,total))): + # [1,5,10,50,100] + S = zip(soln["S"], [1, 5, 10, 50, 100]) + print i, + for c, v in S: + print "%dx%d" % (c,v), + print + list(prolog.query("coins(S, %d, %d)." % (count,total))) + +if __name__ == "__main__": + main() diff --git a/packages/pyswip/examples/create_term.py b/packages/pyswip/examples/create_term.py new file mode 100644 index 000000000..a9f176582 --- /dev/null +++ b/packages/pyswip/examples/create_term.py @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- + +from pyswip.core import * +from pyswip.prolog import Prolog + +def main(): + prolog = Prolog() + + a1 = PL_new_term_refs(2) + a2 = a1 + 1 + t = PL_new_term_ref() + ta = PL_new_term_ref() + + animal2 = PL_new_functor(PL_new_atom("animal"), 2) + assertz = PL_new_functor(PL_new_atom("assertz"), 1) + PL_put_atom_chars(a1, "gnu") + PL_put_integer(a2, 50) + #PL_cons_functor(t, animal2, a1, a2) + PL_cons_functor_v(t, animal2, a1) + PL_cons_functor_v(ta, assertz, t) + PL_call(ta, None) + +# prolog.assertz("animal(gnu, 50)") + print list(prolog.query("animal(X,Y)", catcherrors=True)) + +if __name__ == "__main__": + main() diff --git a/packages/pyswip/examples/draughts/puzzle1.pl b/packages/pyswip/examples/draughts/puzzle1.pl new file mode 100644 index 000000000..fba5e9695 --- /dev/null +++ b/packages/pyswip/examples/draughts/puzzle1.pl @@ -0,0 +1,18 @@ +% This example is adapted from http://eclipse.crosscoreop.com/examples/puzzle1.pl.txt + +:- use_module(library('clpfd')). + +solve(Board) :- + Board = [NW,N,NE,W,E,SW,S,SE], + domains(Board,0..12), + sum(Board, #=, 12), + NW + N + NE #= 5, + NE + E + SE #= 5, + NW + W + SW #= 5, + SW + S + SE #= 5, + label(Board). + +domains([],_). +domains([Pos|Board],D) :- + Pos in D, + domains(Board,D). diff --git a/packages/pyswip/examples/draughts/puzzle1.py b/packages/pyswip/examples/draughts/puzzle1.py new file mode 100644 index 000000000..149fe7498 --- /dev/null +++ b/packages/pyswip/examples/draughts/puzzle1.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# This example is adapted from http://eclipse.crosscoreop.com/examples/puzzle1.pl.txt + +# "Twelve draught pieces are arranged in a square frame with four on +# each side. Try placing them so there are 5 on each side. (Kordemsky) +# +# "Maybe this problem is not described very well but I wanted to stick +# with the original text from Kordemsky. The problem may be stated in +# terms of guards on the wall of a square fort. If a guard stands on a +# side wall then he may only watch that particular wall whereas a guard +# at a corner may watch two walls. If twelve guards are positioned such +# that there are two on each side wall and one at each corner then there +# are four guards watching each wall. How can they be rearranged such +# that there are five watching each wall?" + +from pyswip.prolog import Prolog + +def main(): + prolog = Prolog() + prolog.consult("puzzle1.pl") + for soln in prolog.query("solve(B)."): + #B = eval(soln["B"]) + B = soln["B"] + # [NW,N,NE,W,E,SW,S,SE] + print "%d %d %d" % tuple(B[:3]) + print "%d %d" % tuple(B[3:5]) + print "%d %d %d" % tuple(B[5:]) + + cont = raw_input("Press 'n' to finish: ") + if cont.lower() == "n": break + +if __name__ == "__main__": + main() diff --git a/packages/pyswip/examples/hanoi/hanoi.pl b/packages/pyswip/examples/hanoi/hanoi.pl new file mode 100644 index 000000000..3530c0d68 --- /dev/null +++ b/packages/pyswip/examples/hanoi/hanoi.pl @@ -0,0 +1,12 @@ + +% Towers of Hanoi +% Based on: http://en.wikipedia.org/wiki/Prolog + +hanoi(N) :- move(N, left, right, center). +move(0, _, _, _) :- !. +move(N, A, B, C) :- + M is N-1, + move(M, A, C, B), + notify([A,B]), + move(M, C, B, A). + \ No newline at end of file diff --git a/packages/pyswip/examples/hanoi/hanoi.py b/packages/pyswip/examples/hanoi/hanoi.py new file mode 100644 index 000000000..17a215481 --- /dev/null +++ b/packages/pyswip/examples/hanoi/hanoi.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +from collections import deque +from pyswip.prolog import Prolog +from pyswip.easy import getList, registerForeign + +class Notifier: + def __init__(self, fun): + self.fun = fun + + def notify(self, t): + #return not self.fun(getList(t)) + return not self.fun(t) + notify.arity = 1 + +class Tower: + def __init__(self, N=3, interactive=False): + """N is the number of disks + """ + self.N = N + self.disks = dict(left=deque(range(N, 0, -1)), center=deque(), right=deque()) + self.started = False + self.interactive = interactive + self.step = 0 + + def move(self, r): + if not self.started: + self.step += 1 + self.draw() + self.started = True + disks = self.disks + disks[str(r[1])].append(disks[str(r[0])].pop()) + self.step += 1 + return self.draw() + + def draw(self): + disks = self.disks + print "\n Step", self.step + for i in range(self.N): + n = self.N - i - 1 + print " ", + for pole in ["left", "center", "right"]: + if len(disks[pole]) - n > 0: + print disks[pole][n], + else: + print " ", + print + print "-"*9 + print " ", "L", "C", "R" + if self.interactive: + cont = raw_input("Press 'n' to finish: ") + return cont.lower() == "n" + + +def main(): + N = 3 + INTERACTIVITY = True + + prolog = Prolog() + tower = Tower(N, INTERACTIVITY) + notifier = Notifier(tower.move) + registerForeign(notifier.notify) + prolog.consult("hanoi.pl") + list(prolog.query("hanoi(%d)" % N)) + +if __name__ == "__main__": + main() diff --git a/packages/pyswip/examples/knowledgebase.py b/packages/pyswip/examples/knowledgebase.py new file mode 100644 index 000000000..41e62ba94 --- /dev/null +++ b/packages/pyswip/examples/knowledgebase.py @@ -0,0 +1,33 @@ + +from pyswip import * + +p = Prolog() + +assertz = Functor("assertz") +parent = Functor("parent", 2) +test1 = newModule("test1") +test2 = newModule("test2") + +call(assertz(parent("john", "bob")), module=test1) +call(assertz(parent("jane", "bob")), module=test1) + +call(assertz(parent("mike", "bob")), module=test2) +call(assertz(parent("gina", "bob")), module=test2) + +print "knowledgebase test1" + +X = Variable() +print "ok" +q = Query(parent(X, "bob"), module=test1) +print "ok" +while q.nextSolution(): + print X.value +q.closeQuery() + +print "knowledgebase test2" + +q = Query(parent(X, "bob"), module=test2) +while q.nextSolution(): + print X.value +q.closeQuery() + diff --git a/packages/pyswip/examples/register_foreign.py b/packages/pyswip/examples/register_foreign.py new file mode 100644 index 000000000..b344fbc91 --- /dev/null +++ b/packages/pyswip/examples/register_foreign.py @@ -0,0 +1,14 @@ + +from pyswip import Prolog, registerForeign, Atom + +def atom_checksum(*a): + if isinstance(a[0], Atom): + r = sum(ord(c)&0xFF for c in str(a[0])) + a[1].value = r&0xFF + return True + else: + return False + +p = Prolog() +registerForeign(atom_checksum, arity=2) +print list(p.query("X='Python', atom_checksum(X, Y)", catcherrors=False)) diff --git a/packages/pyswip/examples/register_foreign_simple.py b/packages/pyswip/examples/register_foreign_simple.py new file mode 100644 index 000000000..977c8e8a2 --- /dev/null +++ b/packages/pyswip/examples/register_foreign_simple.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +# Demonstrates registering a Python function as a Prolog predicate through SWI-Prolog's FFI. + +from pyswip.prolog import Prolog +from pyswip.easy import registerForeign, getAtomChars + +def hello(t): + print "Hello,", t +hello.arity = 1 + +def main(): + registerForeign(hello) + prolog = Prolog() + prolog.assertz("father(michael,john)") + prolog.assertz("father(michael,gina)") + list(prolog.query("father(michael,X), hello(X)")) + +if __name__ =="__main__": + main() diff --git a/packages/pyswip/examples/sendmoremoney/money.pl b/packages/pyswip/examples/sendmoremoney/money.pl new file mode 100644 index 000000000..fa2bdede7 --- /dev/null +++ b/packages/pyswip/examples/sendmoremoney/money.pl @@ -0,0 +1,22 @@ + +% SEND + MORE = MONEY +% Adapted from: http://en.wikipedia.org/wiki/Constraint_programming + +:- use_module(library(clpfd)). + +sendmore(Digits) :- + Digits = [S,E,N,D,M,O,R,Y], % Create variables + allin(Digits, 0..9), % Associate domains to variables + S #\= 0, % Constraint: S must be different from 0 + M #\= 0, + all_different(Digits), % all the elements must take different values + 1000*S + 100*E + 10*N + D % Other constraints + + 1000*M + 100*O + 10*R + E + #= 10000*M + 1000*O + 100*N + 10*E + Y, + label(Digits). % Start the search + + +allin([],_). +allin([Pos|Board],D) :- + Pos in D, + allin(Board,D). diff --git a/packages/pyswip/examples/sendmoremoney/money.py b/packages/pyswip/examples/sendmoremoney/money.py new file mode 100644 index 000000000..3d667e302 --- /dev/null +++ b/packages/pyswip/examples/sendmoremoney/money.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +# S E N D +# M O R E +# + ------- +# M O N E Y +# +# So, what should be the values of S, E, N, D, M, O, R, Y +# if they are all distinct digits. + +from pyswip import Prolog + +letters = "S E N D M O R Y".split() +prolog = Prolog() +prolog.consult("money.pl") +for result in prolog.query("sendmore(X)"): + r = result["X"] + for i, letter in enumerate(letters): + print letter, "=", r[i] + +print "That's all..." diff --git a/packages/pyswip/examples/sudoku/sudoku.pl b/packages/pyswip/examples/sudoku/sudoku.pl new file mode 100644 index 000000000..d504ffc45 --- /dev/null +++ b/packages/pyswip/examples/sudoku/sudoku.pl @@ -0,0 +1,31 @@ + +% Prolog Sudoku Solver (C) 2007 Markus Triska (triska@gmx.at) +% Public domain code. + +:- use_module(library(clpfd)). + +% Pss is a list of lists representing the game board. + +sudoku(Pss) :- + flatten(Pss, Ps), + allin(Ps, 1..9), + maplist(all_different, Pss), + Pss = [R1,R2,R3,R4,R5,R6,R7,R8,R9], + columns(R1, R2, R3, R4, R5, R6, R7, R8, R9), + blocks(R1, R2, R3), blocks(R4, R5, R6), blocks(R7, R8, R9), + label(Ps). + +columns([], [], [], [], [], [], [], [], []). +columns([A|As],[B|Bs],[C|Cs],[D|Ds],[E|Es],[F|Fs],[G|Gs],[H|Hs],[I|Is]) :- + all_different([A,B,C,D,E,F,G,H,I]), + columns(As, Bs, Cs, Ds, Es, Fs, Gs, Hs, Is). + +blocks([], [], []). +blocks([X1,X2,X3|R1], [X4,X5,X6|R2], [X7,X8,X9|R3]) :- + all_different([X1,X2,X3,X4,X5,X6,X7,X8,X9]), + blocks(R1, R2, R3). + +allin([],_). +allin([Pos|Board],D) :- + Pos in D, + allin(Board,D). diff --git a/packages/pyswip/examples/sudoku/sudoku.py b/packages/pyswip/examples/sudoku/sudoku.py new file mode 100644 index 000000000..c2403b76d --- /dev/null +++ b/packages/pyswip/examples/sudoku/sudoku.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +from pyswip.prolog import Prolog +from pyswip.easy import * + +_ = 0 +puzzle1 = [ + [_,6,_,1,_,4,_,5,_], + [_,_,8,3,_,5,6,_,_], + [2,_,_,_,_,_,_,_,1], + [8,_,_,4,_,7,_,_,6], + [_,_,6,_,_,_,3,_,_], + [7,_,_,9,_,1,_,_,4], + [5,_,_,_,_,_,_,_,2], + [_,_,7,2,_,6,9,_,_], + [_,4,_,5,_,8,_,7,_] + ] + + +puzzle2 = [ + [_,_,1,_,8,_,6,_,4], + [_,3,7,6,_,_,_,_,_], + [5,_,_,_,_,_,_,_,_], + [_,_,_,_,_,5,_,_,_], + [_,_,6,_,1,_,8,_,_], + [_,_,_,4,_,_,_,_,_], + [_,_,_,_,_,_,_,_,3], + [_,_,_,_,_,7,5,2,_], + [8,_,2,_,9,_,7,_,_] + ] + +def pretty_print(table): + print "".join(["/---", "----"*8, "\\"]) + for row in table: + print "".join(["|", "|".join(" %s " % (i or " ") for i in row), "|"]) + print "".join(["\\---", "----"*8, "/"]) + +def solve(problem): + prolog.consult("sudoku.pl") + p = str(problem).replace("0", "_") + result = list(prolog.query("L=%s,sudoku(L)" % p, maxresult=1)) + if result: + result = result[0] + return result["L"] + else: + return False + +def main(): + puzzle = puzzle1 + print "-- PUZZLE --" + pretty_print(puzzle) + print + print " -- SOLUTION --" + solution = solve(puzzle) + if solution: + pretty_print(solution) + else: + print "This puzzle has no solutions [is it valid?]" + +if __name__ == "__main__": + prolog = Prolog() + main() diff --git a/packages/pyswip/examples/sudoku/sudoku_daily.py b/packages/pyswip/examples/sudoku/sudoku_daily.py new file mode 100644 index 000000000..08b91c5ed --- /dev/null +++ b/packages/pyswip/examples/sudoku/sudoku_daily.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +# Sudoku auto-solver. Get today's sudoku at http://www.sudoku.org.uk/daily.asp +# and solve it + +import urllib +from HTMLParser import HTMLParser, HTMLParseError +from pyswip.prolog import Prolog +from pyswip.easy import * + +URL = "http://www.sudoku.org.uk/daily.asp" + +class DailySudokuPuzzle(HTMLParser): + def __init__(self): + self.puzzle = [] + self.__in_td = False + HTMLParser.__init__(self) + + def handle_starttag(self, tag, attrs): + if tag == "td": + for attr in attrs: + if attr[0] == "class" and attr[1] == "InnerTDone": + self.__in_td = True + break + elif tag == "input": + if self.__in_td: + self.puzzle.append(0) + + def handle_endtag(self, tag): + if tag == "td": + self.__in_td = False + + def handle_data(self, data): + if self.__in_td: + self.puzzle.append(int(data)) + +def pretty_print(table): + print "".join(["/---", "----"*8, "\\"]) + for row in table: + print "".join(["|", "|".join(" %s " % (i or " ") for i in row), "|"]) + print "".join(["\\---", "----"*8, "/"]) + +def get_daily_sudoku(url): + puzzle = DailySudokuPuzzle() + f = urllib.urlopen(url) + try: + puzzle.feed(f.read()) + except HTMLParseError: + pass + puzzle = puzzle.puzzle + return [puzzle[i*9:i*9+9] for i in range(9)] + +def solve(problem): + prolog.consult("sudoku.pl") + p = str(problem).replace("0", "_") + result = list(prolog.query("Puzzle=%s,sudoku(Puzzle)" % p, maxresult=1)) + if result: + result = result[0] + return result["Puzzle"] + else: + return False + +if __name__ == "__main__": + prolog = Prolog() # having this in `solve` bites! because of __del__ + + print "Getting puzzle from:", URL + + puzzle = get_daily_sudoku(URL) + print "-- PUZZLE --" + pretty_print(puzzle) + print + print " -- SOLUTION --" + solution = solve(puzzle) + if solution: + pretty_print(solution) + else: + print "This puzzle has no solutions [is it valid?]" + diff --git a/packages/pyswip/pyswip/__init__.py b/packages/pyswip/pyswip/__init__.py new file mode 100644 index 000000000..1ae7aa917 --- /dev/null +++ b/packages/pyswip/pyswip/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +# pyswip -- Python SWI-Prolog bridge +# (c) 2006-2007 Yüce TEKOL +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# PySWIP version +__VERSION__ = "0.2.2b" + +from pyswip.prolog import Prolog +from pyswip.easy import * diff --git a/packages/pyswip/pyswip/core.py b/packages/pyswip/pyswip/core.py new file mode 100644 index 000000000..de12b55f0 --- /dev/null +++ b/packages/pyswip/pyswip/core.py @@ -0,0 +1,595 @@ +# -*- coding: utf-8 -*- + +# pyswip -- Python SWI-Prolog bridge +# (c) 2006-2007 Yüce TEKOL +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import sys + +try: + from ctypes import * +except ImportError: + print>>sys.stderr, "A required module: 'ctypes' not found." + sys.exit(1) + +try: + if sys.platform[:3] == "win": + # we're on windows + _lib = CDLL("libYap.dll") + elif sys.platform[:3] == "dar": + # we're on Mac OS + _lib = CDLL("libYap.dylib") + else: + # UNIX-like + try: + _lib = CDLL("libYap.so") + except IndexError: + # let's try the cwd + _lib = CDLL("./libYap.so") + +except OSError: + print>>sys.stderr, "libYap (shared) not found. Possible reasons:" + print>>sys.stderr, "1) YAP has not been installed as a shared library, use --with-java)" + print>>sys.stderr, "1) set LD_LIBRARY_PATH=/usr/local/lib or somewhere elser where libYap.so can be found" + sys.exit(1) + + +# PySWIP constants +PYSWIP_MAXSTR = 1024 +c_int_p = POINTER(c_int) +c_long_p = POINTER(c_long) +c_double_p = POINTER(c_double) + +# constants (from SWI-Prolog.h) +# PL_unify_term() arguments +PL_VARIABLE = 1 # nothing +PL_ATOM = 2 # const char +PL_INTEGER = 3 # int +PL_FLOAT = 4 # double +PL_STRING = 5 # const char * +PL_TERM = 6 # +# PL_unify_term() +PL_FUNCTOR = 10 # functor_t, arg ... +PL_LIST = 11 # length, arg ... +PL_CHARS = 12 # const char * +PL_POINTER = 13 # void * + # /* PlArg::PlArg(text, type) */ +#define PL_CODE_LIST (14) /* [ascii...] */ +#define PL_CHAR_LIST (15) /* [h,e,l,l,o] */ +#define PL_BOOL (16) /* PL_set_feature() */ +#define PL_FUNCTOR_CHARS (17) /* PL_unify_term() */ +#define _PL_PREDICATE_INDICATOR (18) /* predicate_t (Procedure) */ +#define PL_SHORT (19) /* short */ +#define PL_INT (20) /* int */ +#define PL_LONG (21) /* long */ +#define PL_DOUBLE (22) /* double */ +#define PL_NCHARS (23) /* unsigned, const char * */ +#define PL_UTF8_CHARS (24) /* const char * */ +#define PL_UTF8_STRING (25) /* const char * */ +#define PL_INT64 (26) /* int64_t */ +#define PL_NUTF8_CHARS (27) /* unsigned, const char * */ +#define PL_NUTF8_CODES (29) /* unsigned, const char * */ +#define PL_NUTF8_STRING (30) /* unsigned, const char * */ +#define PL_NWCHARS (31) /* unsigned, const wchar_t * */ +#define PL_NWCODES (32) /* unsigned, const wchar_t * */ +#define PL_NWSTRING (33) /* unsigned, const wchar_t * */ +#define PL_MBCHARS (34) /* const char * */ +#define PL_MBCODES (35) /* const char * */ +#define PL_MBSTRING (36) /* const char * */ + +# /******************************** +# * NON-DETERMINISTIC CALL/RETURN * +# *********************************/ +# +# Note 1: Non-deterministic foreign functions may also use the deterministic +# return methods PL_succeed and PL_fail. +# +# Note 2: The argument to PL_retry is a 30 bits signed integer (long). + +PL_FIRST_CALL = 0 +PL_CUTTED = 1 +PL_REDO = 2 + +PL_FA_NOTRACE = 0x01 # foreign cannot be traced +PL_FA_TRANSPARENT = 0x02 # foreign is module transparent +PL_FA_NONDETERMINISTIC = 0x04 # foreign is non-deterministic +PL_FA_VARARGS = 0x08 # call using t0, ac, ctx +PL_FA_CREF = 0x10 # Internal: has clause-reference */ + +# /******************************* +# * CALL-BACK * +# *******************************/ + +PL_Q_DEBUG = 0x01 # = TRUE for backward compatibility +PL_Q_NORMAL = 0x02 # normal usage +PL_Q_NODEBUG = 0x04 # use this one +PL_Q_CATCH_EXCEPTION = 0x08 # handle exceptions in C +PL_Q_PASS_EXCEPTION = 0x10 # pass to parent environment +PL_Q_DETERMINISTIC = 0x20 # call was deterministic + +# /******************************* +# * BLOBS * +# *******************************/ + +#define PL_BLOB_MAGIC_B 0x75293a00 /* Magic to validate a blob-type */ +#define PL_BLOB_VERSION 1 /* Current version */ +#define PL_BLOB_MAGIC (PL_BLOB_MAGIC_B|PL_BLOB_VERSION) + +#define PL_BLOB_UNIQUE 0x01 /* Blob content is unique */ +#define PL_BLOB_TEXT 0x02 /* blob contains text */ +#define PL_BLOB_NOCOPY 0x04 /* do not copy the data */ +#define PL_BLOB_WCHAR 0x08 /* wide character string */ + +# /******************************* +# * CHAR BUFFERS * +# *******************************/ + +CVT_ATOM = 0x0001 +CVT_STRING = 0x0002 +CVT_LIST = 0x0004 +CVT_INTEGER = 0x0008 +CVT_FLOAT = 0x0010 +CVT_VARIABLE = 0x0020 +CVT_NUMBER = CVT_INTEGER | CVT_FLOAT +CVT_ATOMIC = CVT_NUMBER | CVT_ATOM | CVT_STRING +CVT_WRITE = 0x0040 # as of version 3.2.10 +CVT_ALL = CVT_ATOMIC | CVT_LIST +CVT_MASK = 0x00ff + +BUF_DISCARDABLE = 0x0000 +BUF_RING = 0x0100 +BUF_MALLOC = 0x0200 + +CVT_EXCEPTION = 0x10000 # throw exception on error + +argv = (c_char_p*(len(sys.argv) + 1))() +for i, arg in enumerate(sys.argv): + argv[i] = arg + +argv[-1] = None +argc = len(sys.argv) + +# types + +atom_t = c_ulong +term_t = c_ulong +fid_t = c_ulong +module_t = c_void_p +predicate_t = c_void_p +record_t = c_void_p +qid_t = c_ulong +PL_fid_t = c_ulong +control_t = c_void_p +PL_engine_t = c_void_p +functor_t = c_ulong +PL_atomic_t = c_ulong +foreign_t = c_ulong +pl_wchar_t = c_wchar +atom_t_p = c_void_p + + +##_lib.PL_initialise(len(sys.argv), _argv) + +PL_initialise = _lib.PL_initialise +##PL_initialise.argtypes = [c_int, c_c + +PL_open_foreign_frame = _lib.PL_open_foreign_frame +PL_open_foreign_frame.restype = fid_t + +PL_new_term_ref = _lib.PL_new_term_ref +PL_new_term_ref.restype = term_t + +PL_new_term_refs = _lib.PL_new_term_refs +PL_new_term_refs.restype = term_t + +PL_chars_to_term = _lib.PL_chars_to_term +PL_chars_to_term.argtypes = [c_char_p, term_t] + +PL_call = _lib.PL_call +PL_call.argtypes = [term_t, module_t] + +PL_call_predicate = _lib.PL_call_predicate +PL_call_predicate.argtypes = [module_t, c_int, predicate_t, term_t] + +PL_discard_foreign_frame = _lib.PL_discard_foreign_frame +PL_discard_foreign_frame.argtypes = [fid_t] + +PL_put_list_chars = _lib.PL_put_list_chars +PL_put_list_chars.argtypes = [term_t, c_char_p] + +#PL_EXPORT(void) PL_register_atom(atom_t a); +PL_register_atom = _lib.PL_register_atom +PL_register_atom.argtypes = [atom_t] + +#PL_EXPORT(void) PL_unregister_atom(atom_t a); +PL_unregister_atom = _lib.PL_unregister_atom +PL_unregister_atom.argtypes = [atom_t] + +#PL_EXPORT(atom_t) PL_functor_name(functor_t f); +PL_functor_name = _lib.PL_functor_name +PL_functor_name.argtypes = [functor_t] +PL_functor_name.restype = atom_t + +#PL_EXPORT(int) PL_functor_arity(functor_t f); +PL_functor_arity = _lib.PL_functor_arity +PL_functor_arity.argtypes = [functor_t] + +# /* Get C-values from Prolog terms */ +#PL_EXPORT(int) PL_get_atom(term_t t, atom_t *a); +PL_get_atom = _lib.PL_get_atom +PL_get_atom.argtypes = [term_t, atom_t_p] + + +#PL_EXPORT(int) PL_get_bool(term_t t, int *value); +PL_get_bool = _lib.PL_get_bool +PL_get_bool.argtypes = [term_t, c_int_p] + +#PL_EXPORT(int) PL_get_atom_chars(term_t t, char **a); +PL_get_atom_chars = _lib.PL_get_atom_chars # FIXME +PL_get_atom_chars.argtypes = [term_t, POINTER(c_char_p)] + +##define PL_get_string_chars(t, s, l) PL_get_string(t,s,l) +# /* PL_get_string() is depricated */ +#PL_EXPORT(int) PL_get_string(term_t t, char **s, size_t *len); +PL_get_string = _lib.PL_get_string +PL_get_string.argtypes = [term_t, POINTER(c_char_p), c_int_p] +PL_get_string_chars = PL_get_string +PL_get_string_chars.argtypes = [term_t, POINTER(c_char_p), c_int_p] + +#PL_EXPORT(int) PL_get_chars(term_t t, char **s, unsigned int flags); +PL_get_chars = _lib.PL_get_chars # FIXME: +PL_get_chars.argtypes = [term_t, POINTER(c_char_p), c_uint] + +#PL_EXPORT(int) PL_get_list_chars(term_t l, char **s, +# unsigned int flags); +#PL_EXPORT(int) PL_get_atom_nchars(term_t t, size_t *len, char **a); +#PL_EXPORT(int) PL_get_list_nchars(term_t l, +# size_t *len, char **s, +# unsigned int flags); +#PL_EXPORT(int) PL_get_nchars(term_t t, +# size_t *len, char **s, +# unsigned int flags); +#PL_EXPORT(int) PL_get_integer(term_t t, int *i); +PL_get_integer = _lib.PL_get_integer +PL_get_integer.argtypes = [term_t, POINTER(c_int)] + +#PL_EXPORT(int) PL_get_long(term_t t, long *i); +PL_get_long = _lib.PL_get_long +PL_get_long.argtypes = [term_t, POINTER(c_long)] + +#PL_EXPORT(int) PL_get_pointer(term_t t, void **ptr); +#PL_EXPORT(int) PL_get_float(term_t t, double *f); +PL_get_float = _lib.PL_get_float +PL_get_float.argtypes = [term_t, c_double_p] + +#PL_EXPORT(int) PL_get_functor(term_t t, functor_t *f); +PL_get_functor = _lib.PL_get_functor +PL_get_functor.argtypes = [term_t, POINTER(functor_t)] + +#PL_EXPORT(int) PL_get_name_arity(term_t t, atom_t *name, int *arity); +PL_get_name_arity = _lib.PL_get_name_arity +PL_get_name_arity.argtypes = [term_t, POINTER(atom_t), c_int_p] + +#PL_EXPORT(int) PL_get_module(term_t t, module_t *module); +#PL_EXPORT(int) PL_get_arg(int index, term_t t, term_t a); +PL_get_arg = _lib.PL_get_arg +PL_get_arg.argtypes = [c_int, term_t, term_t] + +#PL_EXPORT(int) PL_get_list(term_t l, term_t h, term_t t); +#PL_EXPORT(int) PL_get_head(term_t l, term_t h); +PL_get_head = _lib.PL_get_head +PL_get_head.argtypes = [term_t, term_t] +#PL_EXPORT(int) PL_get_tail(term_t l, term_t t); +PL_get_tail = _lib.PL_get_tail +PL_get_tail.argtypes = [term_t, term_t] +#PL_EXPORT(int) PL_get_nil(term_t l); +PL_get_nil = _lib.PL_get_nil +PL_get_nil.argtypes = [term_t] +#PL_EXPORT(int) PL_get_term_value(term_t t, term_value_t *v); +#PL_EXPORT(char *) PL_quote(int chr, const char *data); + +PL_put_atom_chars = _lib.PL_put_atom_chars +PL_put_atom_chars.argtypes = [term_t, c_char_p] + +PL_atom_chars = _lib.PL_atom_chars +PL_atom_chars.argtypes = [atom_t] +PL_atom_chars.restype = c_char_p + +PL_predicate = _lib.PL_predicate +PL_predicate.argtypes = [c_char_p, c_int, c_char_p] +PL_predicate.restype = predicate_t + +PL_pred = _lib.PL_pred +PL_pred.argtypes = [functor_t, module_t] +PL_pred.restype = predicate_t + +PL_open_query = _lib.PL_open_query +PL_open_query.argtypes = [module_t, c_int, predicate_t, term_t] +PL_open_query.restype = qid_t + +PL_next_solution = _lib.PL_next_solution +PL_next_solution.argtypes = [qid_t] + +PL_copy_term_ref = _lib.PL_copy_term_ref +PL_copy_term_ref.argtypes = [term_t] +PL_copy_term_ref.restype = term_t + +PL_get_list = _lib.PL_get_list +PL_get_list.argtypes = [term_t, term_t, term_t] + +PL_get_chars = _lib.PL_get_chars +PL_get_chars.argtypes = [term_t, POINTER(c_char_p), c_uint] + +PL_close_query = _lib.PL_close_query +PL_close_query.argtypes = [qid_t] + +#void PL_cut_query(qid) +PL_cut_query = _lib.PL_cut_query +PL_cut_query.argtypes = [qid_t] + +PL_halt = _lib.PL_halt +PL_halt.argtypes = [c_int] + +PL_unify_integer = _lib.PL_unify_integer +PL_unify_integer.argtypes = [term_t,c_long] + +PL_unify = _lib.PL_unify +PL_unify.argtypes = [term_t,term_t] + +PL_unify_arg = _lib.PL_unify_arg +PL_unify.argtypes = [c_int,term_t,atom_t] + +# Verify types + +PL_term_type = _lib.PL_term_type +PL_term_type.argtypes = [term_t] +PL_term_type.restype = c_int + +PL_is_variable = _lib.PL_is_variable +PL_is_variable.argtypes = [term_t] +PL_is_variable.restype = c_int + +PL_is_ground = _lib.PL_is_ground +PL_is_ground.argtypes = [term_t] +PL_is_ground.restype = c_int + +PL_is_atom = _lib.PL_is_atom +PL_is_atom.argtypes = [term_t] +PL_is_atom.restype = c_int + +PL_is_integer = _lib.PL_is_integer +PL_is_integer.argtypes = [term_t] +PL_is_integer.restype = c_int + +PL_is_string = _lib.PL_is_string +PL_is_string.argtypes = [term_t] +PL_is_string.restype = c_int + +PL_is_float = _lib.PL_is_float +PL_is_float.argtypes = [term_t] +PL_is_float.restype = c_int + +#PL_is_rational = _lib.PL_is_rational +#PL_is_rational.argtypes = [term_t] +#PL_is_rational.restype = c_int + +PL_is_compound = _lib.PL_is_compound +PL_is_compound.argtypes = [term_t] +PL_is_compound.restype = c_int + +PL_is_functor = _lib.PL_is_functor +PL_is_functor.argtypes = [term_t, functor_t] +PL_is_functor.restype = c_int + +PL_is_list = _lib.PL_is_list +PL_is_list.argtypes = [term_t] +PL_is_list.restype = c_int + +PL_is_atomic = _lib.PL_is_atomic +PL_is_atomic.argtypes = [term_t] +PL_is_atomic.restype = c_int + +PL_is_number = _lib.PL_is_number +PL_is_number.argtypes = [term_t] +PL_is_number.restype = c_int + +# /* Assign to term-references */ +#PL_EXPORT(void) PL_put_variable(term_t t); +PL_put_variable = _lib.PL_put_variable +PL_put_variable.argtypes = [term_t] +#PL_EXPORT(void) PL_put_atom(term_t t, atom_t a); +#PL_EXPORT(void) PL_put_atom_chars(term_t t, const char *chars); +#PL_EXPORT(void) PL_put_string_chars(term_t t, const char *chars); +#PL_EXPORT(void) PL_put_list_chars(term_t t, const char *chars); +#PL_EXPORT(void) PL_put_list_codes(term_t t, const char *chars); +#PL_EXPORT(void) PL_put_atom_nchars(term_t t, size_t l, const char *chars); +#PL_EXPORT(void) PL_put_string_nchars(term_t t, size_t len, const char *chars); +#PL_EXPORT(void) PL_put_list_nchars(term_t t, size_t l, const char *chars); +#PL_EXPORT(void) PL_put_list_ncodes(term_t t, size_t l, const char *chars); +#PL_EXPORT(void) PL_put_integer(term_t t, long i); +PL_put_integer = _lib.PL_put_integer +PL_put_integer.argtypes = [term_t, c_long] +#PL_EXPORT(void) PL_put_pointer(term_t t, void *ptr); +#PL_EXPORT(void) PL_put_float(term_t t, double f); +#PL_EXPORT(void) PL_put_functor(term_t t, functor_t functor); +PL_put_functor = _lib.PL_put_functor +PL_put_functor.argtypes = [term_t, functor_t] +#PL_EXPORT(void) PL_put_list(term_t l); +PL_put_list = _lib.PL_put_list +PL_put_list.argtypes = [term_t] +#PL_EXPORT(void) PL_put_nil(term_t l); +PL_put_nil = _lib.PL_put_nil +PL_put_nil.argtypes = [term_t] +#PL_EXPORT(void) PL_put_term(term_t t1, term_t t2); +PL_put_term = _lib.PL_put_term +PL_put_term.argtypes = [term_t,term_t] + +# /* construct a functor or list-cell */ +#PL_EXPORT(void) PL_cons_functor(term_t h, functor_t f, ...); +#class _PL_cons_functor(object): +PL_cons_functor = _lib.PL_cons_functor # FIXME: + +#PL_EXPORT(void) PL_cons_functor_v(term_t h, functor_t fd, term_t a0); +PL_cons_functor_v = _lib.PL_cons_functor_v +PL_cons_functor_v.argtypes = [term_t, functor_t, term_t] +PL_cons_functor_v.restype = None + +#PL_EXPORT(void) PL_cons_list(term_t l, term_t h, term_t t); +PL_cons_list = _lib.PL_cons_list + +# +# term_t PL_exception(qid_t qid) +PL_exception = _lib.PL_exception +PL_exception.argtypes = [qid_t] +PL_exception.restype = term_t +# +PL_register_foreign = _lib.PL_register_foreign +PL_register_foreign.argtypes = [c_char_p, c_int, c_void_p, c_int] +PL_register_foreign.restype = None + +# +#PL_EXPORT(atom_t) PL_new_atom(const char *s); +PL_new_atom = _lib.PL_new_atom +PL_new_atom.argtypes = [c_char_p] +PL_new_atom.restype = atom_t + +#PL_EXPORT(functor_t) PL_new_functor(atom_t f, int a); +PL_new_functor = _lib.PL_new_functor +PL_new_functor.argtypes = [atom_t, c_int] +PL_new_functor.restype = functor_t + +# /******************************* +# * RECORDED DATABASE * +# *******************************/ +# +#PL_EXPORT(record_t) PL_record(term_t term); +PL_record = _lib.PL_record +PL_record.argtypes = [term_t] +PL_record.restype = record_t + +#PL_EXPORT(void) PL_recorded(record_t record, term_t term); +PL_recorded = _lib.PL_recorded +PL_recorded.argtypes = [record_t,term_t] +PL_recorded.restype = None + +#PL_EXPORT(void) PL_erase(record_t record); +PL_erase = _lib.PL_erase +PL_erase.argtypes = [record_t] +PL_erase.restype = None +# +#PL_EXPORT(char *) PL_record_external(term_t t, size_t *size); +#PL_EXPORT(int) PL_recorded_external(const char *rec, term_t term); +#PL_EXPORT(int) PL_erase_external(char *rec); + +PL_new_module = _lib.PL_new_module +PL_new_module.argtypes = [atom_t] +PL_new_module.restype = module_t + +intptr_t = c_long +ssize_t = intptr_t +wint_t = c_uint + +#typedef struct +#{ +# int __count; +# union +# { +# wint_t __wch; +# char __wchb[4]; +# } __value; /* Value so far. */ +#} __mbstate_t; + +class _mbstate_t_value(Union): + _fields_ = [("__wch",wint_t), + ("__wchb",c_char*4)] + +class mbstate_t(Structure): + _fields_ = [("__count",c_int), + ("__value",_mbstate_t_value)] + +# stream related funcs +Sread_function = CFUNCTYPE(ssize_t, c_void_p, c_char_p, c_size_t) +Swrite_function = CFUNCTYPE(ssize_t, c_void_p, c_char_p, c_size_t) +Sseek_function = CFUNCTYPE(c_long, c_void_p, c_long, c_int) +Sseek64_function = CFUNCTYPE(c_int64, c_void_p, c_int64, c_int) +Sclose_function = CFUNCTYPE(c_int, c_void_p) +Scontrol_function = CFUNCTYPE(c_int, c_void_p, c_int, c_void_p) + +# IOLOCK +IOLOCK = c_void_p + +# IOFUNCTIONS +class IOFUNCTIONS(Structure): + _fields_ = [("read",Sread_function), + ("write",Swrite_function), + ("seek",Sseek_function), + ("close",Sclose_function), + ("seek64",Sseek64_function), + ("reserved",intptr_t*2)] + +# IOENC +ENC_UNKNOWN,ENC_OCTET,ENC_ASCII,ENC_ISO_LATIN_1,ENC_ANSI,ENC_UTF8,ENC_UNICODE_BE,ENC_UNICODE_LE,ENC_WCHAR = range(9) +IOENC = c_int + +# IOPOS +class IOPOS(Structure): + _fields_ = [("byteno",c_int64), + ("charno",c_int64), + ("lineno",c_int), + ("linepos",c_int), + ("reserved", intptr_t*2)] + +# IOSTREAM +class IOSTREAM(Structure): + _fields_ = [("bufp",c_char_p), + ("limitp",c_char_p), + ("buffer",c_char_p), + ("unbuffer",c_char_p), + ("lastc",c_int), + ("magic",c_int), + ("bufsize",c_int), + ("flags",c_int), + ("posbuf",IOPOS), + ("position",POINTER(IOPOS)), + ("handle",c_void_p), + ("functions",IOFUNCTIONS), + ("locks",c_int), + ("mutex",IOLOCK), + ("closure_hook",CFUNCTYPE(None, c_void_p)), + ("closure",c_void_p), + ("timeout",c_int), + ("message",c_char_p), + ("encoding",IOENC)] +IOSTREAM._fields_.extend([("tee",IOSTREAM), + ("mbstate",POINTER(mbstate_t)), + ("reserved",intptr_t*6)]) + + + +#PL_EXPORT(IOSTREAM *) Sopen_string(IOSTREAM *s, char *buf, size_t sz, const char *m); +#Sopen_string = _lib.Sopen_string +#Sopen_string.argtypes = [POINTER(IOSTREAM), c_char_p, c_size_t, c_char_p] +#Sopen_string.restype = POINTER(IOSTREAM) + +#PL_EXPORT(int) Sclose(IOSTREAM *s); +#Sclose = _lib.Sclose +#Sclose.argtypes = [POINTER(IOSTREAM)] + + +#PL_EXPORT(int) PL_unify_stream(term_t t, IOSTREAM *s); +#PL_unify_stream = _lib.PL_unify_stream +#PL_unify_stream.argtypes = [term_t, POINTER(IOSTREAM)] + diff --git a/packages/pyswip/pyswip/easy.py b/packages/pyswip/pyswip/easy.py new file mode 100644 index 000000000..897299e83 --- /dev/null +++ b/packages/pyswip/pyswip/easy.py @@ -0,0 +1,476 @@ +# -*- coding: utf-8 -*- + +# pyswip.easy -- PySWIP helper functions +# (c) 2006-2007 Yüce TEKOL +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +from pyswip.core import * + + +class InvalidTypeError(TypeError): + def __init__(self, *args): + type = args and args[0] or "Unknown" + msg = "Term is expected to be of type: '%s'" % type + Exception.__init__(self, msg, *args) + + +class Atom(object): + __slots__ = "handle","chars" + + def __init__(self, handleOrChars): + """Create an atom. + ``handleOrChars``: handle or string of the atom. + """ + if isinstance(handleOrChars, basestring): + self.handle = PL_new_atom(handleOrChars) + self.chars = handleOrChars + else: + self.handle = handleOrChars + PL_register_atom(self.handle) + self.chars = c_char_p(PL_atom_chars(self.handle)).value + + def fromTerm(cls, term): + """Create an atom from a Term or term handle.""" + if isinstance(term, Term): + term = term.handle + + a = atom_t() + if PL_get_atom(term, addressof(a)): + return cls(a.value) + + fromTerm = classmethod(fromTerm) + + def __del__(self): + PL_unregister_atom(self.handle) + + value = property(lambda s:s.chars) + + def __str__(self): + if self.chars is not None: + return self.chars + else: + return self.__repr__() + + def __repr__(self): + return str(self.handle).join(["Atom('", "')"]) + +class Term(object): + __slots__ = "handle","chars","__value","a0" + def __init__(self, handle=None, a0=None): + if handle: + #self.handle = PL_copy_term_ref(handle) + self.handle = handle + else: + self.handle = PL_new_term_ref() + self.chars = None + self.a0 = a0 + + def __invert__(self): + return _not(self) + + def get_value(self): + pass + +class Variable(object): + __slots__ = "handle","chars" + + def __init__(self, handle=None, name=None): + self.chars = None + if name: + self.chars = name + if handle: + self.handle = handle + s = create_string_buffer("\00"*64) # FIXME: + ptr = cast(s, c_char_p) + if PL_get_chars(handle, byref(ptr), CVT_VARIABLE|BUF_RING): + self.chars = ptr.value + else: + self.handle = PL_new_term_ref() + #PL_put_variable(self.handle) + + def unify(self, value): + if type(value) == str: + fun = PL_unify_atom_chars + elif type(value) == int: + fun = PL_unify_integer + elif type(value) == bool: + fun = PL_unify_bool + elif type(value) == float: + fun = PL_unify_float + elif type(value) == list: + fun = PL_unify_list + else: + raise + + t = PL_new_term_ref() + fun(self.handle, value) + + def get_value(self): + return getTerm(self.handle) + + value = property(get_value, unify) + + def unified(self): + return PL_term_type(self.handle) == PL_VARIABLE + + def __str__(self): + if self.chars is not None: + return self.chars + else: + return self.__repr__() + + def __repr__(self): + return "Variable(%s)" % self.handle + + def put(self, term): + #PL_put_variable(term) + self.handle = term + + +class Functor(object): + __slots__ = "handle","name","arity","args","__value","a0" + func = {} + + def __init__(self, handleOrName, arity=1, args=None, a0=None): + """Create a functor. + ``handleOrName``: functor handle, a string or an atom. + """ + + self.args = args or [] + self.arity = arity + self.a0 = a0 + + if isinstance(handleOrName, basestring): + self.name = Atom(handleOrName) + self.handle = PL_new_functor(self.name.handle, arity) + self.__value = "Functor%d" % self.handle + elif isinstance(handleOrName, Atom): + self.name = handleOrName + self.handle = PL_new_functor(self.name.handle, arity) + self.__value = "Functor%d" % self.handle + else: + self.handle = handleOrName + self.name = Atom(PL_functor_name(self.handle)) + self.arity = PL_functor_arity(self.handle) + try: + self.__value = self.func[self.handle](self.arity, *self.args) + except KeyError: + self.__value = "Functor%d" % self.handle + + def fromTerm(cls, term): + """Create a functor from a Term or term handle.""" + if isinstance(term, Term): + term = term.handle + + f = functor_t() + if PL_get_functor(term, byref(f)): + # get args + args = [] + arity = PL_functor_arity(f.value) + # let's have all args be consecutive + a0 = PL_new_term_refs(arity) + for i, a in enumerate(range(1, arity + 1)): + if PL_get_arg(a, term, a0 + i): + args.append(getTerm(a0 + i)) + + return cls(f.value, args=args, a0=a0) + + fromTerm = classmethod(fromTerm) + + value = property(lambda s: s.__value) + + def __call__(self, *args): + assert self.arity == len(args) + a = PL_new_term_refs(len(args)) + for i, arg in enumerate(args): + putTerm(a + i, arg) + + t = PL_new_term_ref() + PL_cons_functor_v(t, self.handle, a) + return Term(t) + + def __str__(self): + if self.name is not None and self.arity is not None: + return "%s(%d)" % (self.name,self.arity) + else: + return self.__repr__() + + def __repr__(self): + return "".join(["Functor(", ",".join(str(x) for x in [self.handle,self.arity]+self.args), ")"]) + +def _unifier(arity, *args): + assert arity == 2 + #if PL_is_variable(args[0]): + # args[0].unify(args[1]) + try: + return {args[0].chars:args[1].value} + except AttributeError: + return {args[0].chars:args[1]} + +_unify = Functor("=", 2) +Functor.func[_unify.handle] = _unifier +_not = Functor("not", 1) +_comma = Functor(",", 2) + +def putTerm(term, value): + if isinstance(value, Term): + PL_put_term(term, value.handle) + elif isinstance(value, basestring): + PL_put_atom_chars(term, value) + elif isinstance(value, int): + PL_put_integer(term, value) + elif isinstance(value, Variable): + value.put(term) + elif isinstance(value, list): + putList(term, value) + elif isinstance(value, Atom): + print "ATOM" + elif isinstance(value, Functor): + PL_put_functor(term, value.handle) + else: + raise Exception("Not implemented") + +def putList(l, ls): + PL_put_nil(l) + a = PL_new_term_ref() #PL_new_term_refs(len(ls)) + for item in reversed(ls): + putTerm(a, item) + PL_cons_list(l, a, l) + #PL_get_head(h, h) + +# deprecated +def getAtomChars(t): + """If t is an atom, return it as a string, otherwise raise InvalidTypeError. + """ + s = c_char_p() + if PL_get_atom_chars(t, addressof(s)): + return s.value + else: + raise InvalidTypeError("atom") + +def getAtom(t): + """If t is an atom, return it , otherwise raise InvalidTypeError. + """ + return Atom.fromTerm(t) + +def getBool(t): + """If t is of type bool, return it, otherwise raise InvalidTypeError. + """ + b = c_long() + if PL_get_long(t, byref(b)): + return bool(b.value) + else: + raise InvalidTypeError("bool") + +def getLong(t): + """If t is of type long, return it, otherwise raise InvalidTypeError. + """ + i = c_long() + if PL_get_long(t, byref(i)): + return i.value + else: + raise InvalidTypeError("long") + +getInteger = getLong # just an alias for getLong + +def getFloat(t): + """If t is of type float, return it, otherwise raise InvalidTypeError. + """ + d = c_double() + if PL_get_float(t, byref(d)): + return d.value + else: + raise InvalidTypeError("float") + +def getString(t): + """If t is of type string, return it, otherwise raise InvalidTypeError. + """ + slen = c_int() + s = c_char_p() + if PL_get_string_chars(t, byref(s), byref(slen)): + return s.value + else: + raise InvalidTypeError("string") + +def getTerm(t): + p = PL_term_type(t) + if p < PL_TERM: + return _getterm_router[p](t) + elif PL_is_list(t): + return getList(t) + else: + return getFunctor(t) + +def getList(x): + """Return t as a list. + """ + t = PL_copy_term_ref(x) + head = PL_new_term_ref() + result = [] + while PL_get_list(t, head, t): + result.append(getTerm(head)) + + return result + +def getFunctor(t): + """Return t as a functor + """ + return Functor.fromTerm(t) + +def getVariable(t): + return Variable(t) + +_getterm_router = { + PL_VARIABLE:getVariable, PL_ATOM:getAtom, PL_STRING:getString, + PL_INTEGER:getInteger, PL_FLOAT:getFloat, + PL_TERM:getTerm + } + +def _callbackWrapper(arity=1): + return CFUNCTYPE(*([foreign_t] + [term_t]*arity)) + +def _foreignWrapper(fun): + def wrapper(*args): + args = [getTerm(arg) for arg in args] + r = fun(*args) + return (r is None) and True or r + return wrapper + +def registerForeign(func, name=None, arity=None, flags=0): + """Register a Python predicate + ``func``: Function to be registered. The function should return a value in + ``foreign_t``, ``True`` or ``False``. + ``name`` : Name of the function. If this value is not used, ``func.func_name`` + should exist. + ``arity``: Arity (number of arguments) of the function. If this value is not + used, ``func.arity`` should exist. + """ + if arity is None: + arity = func.arity + + if name is None: + name = func.func_name + + return PL_register_foreign(name, arity, + cast(_callbackWrapper(arity)(_foreignWrapper(func)),c_void_p), (flags)) + +newTermRef = PL_new_term_ref + +def newTermRefs(count): + a = PL_new_term_refs(count) + return range(a, a + count) + +def call(*terms, **kwargs): + """Call term in module. + ``term``: a Term or term handle + """ + for kwarg in kwargs: + if kwarg not in ["module"]: + raise KeyError + + module = kwargs.get("module", None) + + t = terms[0] + for tx in terms[1:]: + t = _comma(t, tx) + + return PL_call(t.handle, module) + +def newModule(name): + """Create a new module. + ``name``: An Atom or a string + """ + if isinstance(name, basestring): + name = Atom(name) + + return PL_new_module(name.handle) + +class Query(object): + qid = None + fid = None + + def __init__(self, *terms, **kwargs): + for key in kwargs: + if key not in ["flags", "module"]: + raise Exception("Invalid kwarg: %s" % key, key) + + flags = kwargs.get("flags", PL_Q_NODEBUG|PL_Q_CATCH_EXCEPTION) + module = kwargs.get("module", None) + + t = terms[0] + for tx in terms[1:]: + t = _comma(t, tx) + + f = Functor.fromTerm(t) + p = PL_pred(f.handle, module) + Query.fid = PL_open_foreign_frame() + Query.qid = PL_open_query(module, flags, p, f.a0) + +# def __del__(self): +# self.closeQuery() + + def nextSolution(): + return PL_next_solution(Query.qid) + + nextSolution = staticmethod(nextSolution) + + def cutQuery(): + PL_cut_query(Query.qid) + + cutQuery = staticmethod(cutQuery) + + def closeQuery(): + if Query.qid is not None: + PL_close_query(Query.qid) + PL_discard_foreign_frame(Query.fid) + Query.qid = None + Query.fid = None + + closeQuery = staticmethod(closeQuery) + + +def _test(): + #from pyswip.prolog import Prolog + #p = Prolog() + + #p = _prolog + + assertz = Functor("assertz") + a = Functor("a_") + b = Functor("b_") + + call(assertz(a(10))) + call(assertz(a([1,2,3]))) + call(assertz(a(11))) + call(assertz(b(11))) + call(assertz(b(12))) + + X = Variable() + + #q = Query(a(X), ~b(X)) + #q = Query(b(X), a(X)) + #while q.nextSolution(): + # print X.value + #print call(a(X),b(X)) + #print call(_comma(~a(X),a(X))) + #q = Query(_comma(a(X), b(X))) + q = Query(a(X)) + while q.nextSolution(): + print ">", X.value + +if __name__ == "__main__": + _test() + diff --git a/packages/pyswip/pyswip/prolog.py b/packages/pyswip/pyswip/prolog.py new file mode 100644 index 000000000..a82027c9c --- /dev/null +++ b/packages/pyswip/pyswip/prolog.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +# prolog.py -- Prolog class +# (c) 2006-2007 Yüce TEKOL +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import atexit +from pyswip.core import * + +def _initialize(): + plargs = (c_char_p*3)() + plargs[0] = "./" + plargs[1] = "-q" + plargs[2] = "-nosignals" + PL_initialise(3, plargs) + swipl_fid = PL_open_foreign_frame() + swipl_load = PL_new_term_ref() + PL_chars_to_term("asserta((pyrun(GoalString,BindingList):-atom_codes(A,GoalString),atom_to_term(A,Goal,BindingList),call(Goal))).", swipl_load) + PL_call(swipl_load, None) + PL_discard_foreign_frame(swipl_fid) +_initialize() + +def _finalize(): + PL_halt(0) +atexit.register(_finalize) + +from pyswip.easy import getTerm + +class PrologError(Exception): + pass + + +#### Prolog #### +class Prolog: + """Easily query SWI-Prolog. + This is a singleton class + """ + class _QueryWrapper(object): + __slots__ = "swipl_fid","swipl_qid","error" + + def __init__(self): + self.error = False + + def __call__(self, query, maxresult, catcherrors, normalize): + plq = catcherrors and (PL_Q_NODEBUG|PL_Q_CATCH_EXCEPTION) or PL_Q_NORMAL + self.swipl_fid = PL_open_foreign_frame() + swipl_head = PL_new_term_ref() + swipl_args = PL_new_term_refs(2) + swipl_goalCharList = swipl_args + swipl_bindingList = swipl_args + 1 + + PL_put_list_chars(swipl_goalCharList, query) + + swipl_predicate = PL_predicate("pyrun", 2, None) + self.swipl_qid = swipl_qid = PL_open_query(None, plq, + swipl_predicate, swipl_args) + while maxresult and PL_next_solution(swipl_qid): + maxresult -= 1 + bindings = [] + swipl_list = PL_copy_term_ref(swipl_bindingList) + t = getTerm(swipl_list) + if normalize: + try: + v = t.value + except AttributeError: + v = {} + for r in [x.value for x in t]: + v.update(r) + yield v + else: + yield t + + if PL_exception(self.swipl_qid): + self.error = True + PL_cut_query(self.swipl_qid) + PL_discard_foreign_frame(self.swipl_fid) + raise PrologError("".join(["Caused by: '", query, "'."])) + + def __del__(self): + if not self.error: + PL_close_query(self.swipl_qid) + PL_discard_foreign_frame(self.swipl_fid) + + def asserta(cls, assertion, catcherrors=False): + cls.query(assertion.join(["asserta((", "))."]), catcherrors=catcherrors).next() + + asserta = classmethod(asserta) + + def assertz(cls, assertion, catcherrors=False): + cls.query(assertion.join(["assertz((", "))."]), catcherrors=catcherrors).next() + + assertz = classmethod(assertz) + + def consult(cls, filename, catcherrors=False): + cls.query(filename.join(["consult('", "')"]), catcherrors=catcherrors).next() + + consult = classmethod(consult) + + def query(cls, query, maxresult=-1, catcherrors=True, normalize=True): + """Run a prolog query and return a generator. + If the query is a yes/no question, returns {} for yes, and nothing for no. + Otherwise returns a generator of dicts with variables as keys. + + >>> prolog = Prolog() + >>> prolog.assertz("father(michael,john)") + >>> prolog.assertz("father(michael,gina)") + >>> bool(list(prolog.query("father(michael,john)"))) + True + >>> bool(list(prolog.query("father(michael,olivia)"))) + False + >>> print sorted(prolog.query("father(michael,X)")) + [{'X': 'gina'}, {'X': 'john'}] + """ + #assert cls.initialized + return cls._QueryWrapper()(query, maxresult, catcherrors, normalize) + + query = classmethod(query) + + +def _test(): + lines = [("assertz(father(michael,john)).","Michael is the father of John"), + ("assertz(father(michael,gina)).","Michael is the father of Gina"), + ("father(michael,john).","Is Michael father of John?"), + ("father(michael,olivia).","Is Michael father of Olivia?"), + ("father(michael,X).","Michael is the father of whom?"), + ("father(X,Y).","Who is the father of whom?")] + + prolog = Prolog() + + for code, comment in lines: + print "?-", code, "[", comment, "]" + print list(prolog.query(code)) + + for r in prolog.query("father(X,Y)"): + print r["X"], "is the father of", r["Y"] + + +if __name__ == "__main__": + #import doctest + #doctest.testmod() + _test() + diff --git a/packages/pyswip/setup.py b/packages/pyswip/setup.py new file mode 100644 index 000000000..551644eb2 --- /dev/null +++ b/packages/pyswip/setup.py @@ -0,0 +1,117 @@ + +# PySWIP setup script + +import sys +import os +import os.path +from distutils.core import setup + +setup(name="pyswip", + version="0.2.2", + url="http://code.google.com/p/pyswip/", + download_url="http://code.google.com/p/pyswip/downloads/list", + author="Yuce Tekol", + author_email="yucetekol@gmail.com", + description="PySWIP enables querying SWI-Prolog and YAP in your Python programs.", + long_description=""" +PySWIP 0.2.2 +============ + +PySWIP is a GPL'd Python - SWI-Prolog bridge enabling to query SWI-Prolog +in your Python programs. It features an (incomplete) SWI-Prolog foreign +language interface, a utility class that makes it easy querying with Prolog +and also a Pythonic interface. + +Since PySWIP uses SWI-Prolog as a shared library and ctypes to access it, +it doesn't require compilation to be installed. + +Note that this version of PySWIP is slightly incompatible with 0.1.x versions. + +Requirements: +------------- + +* Python 2.3 and higher. +* ctypes 1.0 and higher. +* SWI-Prolog 5.6.x and higher (most probably other versions will also work). +* libpl as a shared library. +* Works on Linux and Win32, should work for all POSIX. + +News +---- + +* Importing ``pyswip`` automatically initializes SWI-Prolog. +* Fixed a bug with querying lists with the new interface. + +Example (Using Prolog): +----------------------- + + >>> from pyswip import Prolog + >>> prolog = Prolog() + >>> prolog.assertz("father(michael,john)") + >>> prolog.assertz("father(michael,gina)") + >>> list(prolog.query("father(michael,X)")) + [{'X': 'john'}, {'X': 'gina'}] + >>> for soln in prolog.query("father(X,Y)"): + ... print soln["X"], "is the father of", soln["Y"] + ... + michael is the father of john + michael is the father of gina + +Since version 0.1.3 of PySWIP, it is possible to register a Python function as a Prolog predicate through SWI-Prolog's foreign language interface. + +Example (Foreign Functions): +---------------------------- + + from pyswip import Prolog, registerForeign + + def hello(t): + print "Hello,", t + hello.arity = 1 + + registerForeign(hello) + + prolog = Prolog() + prolog.assertz("father(michael,john)") + prolog.assertz("father(michael,gina)") + list(prolog.query("father(michael,X), hello(X)")) + +Outputs: + Hello, john + Hello, gina + +Since version 0.2, PySWIP contains a 'Pythonic' interface which allows writing predicates in pure Python (*Note that interface is experimental.*) + +Example (Pythonic interface): +----------------------------- + + from pyswip import Functor, Variable, Query + + assertz = Functor("assertz", 2) + father = Functor("father", 2) + + call(assertz(father("michael","john"))) + call(assertz(father("michael","gina"))) + + X = Variable() + q = Query(father("michael",X)) + while q.nextSolution(): + print "Hello,", X.value + +Outputs: + Hello, john + Hello, gina +""", + license="GPL", + packages=["pyswip"], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development :: Libraries :: Python Modules' + ], + ) +